xref: /linux/sound/pci/emu10k1/emumixer.c (revision edec7bbb22dafdab5f8eae4f049ad9d0f615abc4)
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 
8013d45709SPavel Hofman /*
8113d45709SPavel Hofman  * Items labels in enum mixer controls assigning source data to
8213d45709SPavel Hofman  * each destination
8313d45709SPavel 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 
14013d45709SPavel Hofman /*
14113d45709SPavel Hofman  * List of data sources available for each destination
14213d45709SPavel 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 
19913d45709SPavel Hofman /*
20013d45709SPavel Hofman  * Data destinations - physical EMU outputs.
20113d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
20213d45709SPavel 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 
23013d45709SPavel Hofman /*
23113d45709SPavel Hofman  * Data destinations - HANA outputs going to Alice2 (audigy) for
23213d45709SPavel Hofman  *   capture (EMU32 + I2S links)
23313d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
23413d45709SPavel 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 
403a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
4049148cc50SJames Courtier-Dutton 
4059148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4069148cc50SJames Courtier-Dutton {
4079148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4089148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4099148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
4109148cc50SJames Courtier-Dutton 	return 0;
4119148cc50SJames Courtier-Dutton }
4129148cc50SJames Courtier-Dutton 
4139148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(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 	unsigned int val, cache;
4189148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
4199148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
4209148cc50SJames Courtier-Dutton 	if (val == 1)
4219148cc50SJames Courtier-Dutton 		cache = cache | mask;
4229148cc50SJames Courtier-Dutton 	else
4239148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
4249148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
4259148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
4269148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
4279148cc50SJames Courtier-Dutton 	}
4289148cc50SJames Courtier-Dutton 
4299148cc50SJames Courtier-Dutton 	return 0;
4309148cc50SJames Courtier-Dutton }
4319148cc50SJames Courtier-Dutton 
4329148cc50SJames Courtier-Dutton 
4339148cc50SJames Courtier-Dutton 
4349148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \
4359148cc50SJames Courtier-Dutton {								\
4369148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
4379148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
4389148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_adc_pads_info,			\
4399148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_adc_pads_get,			\
4409148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_adc_pads_put,			\
4419148cc50SJames Courtier-Dutton 	.private_value = chid					\
4429148cc50SJames Courtier-Dutton }
4439148cc50SJames Courtier-Dutton 
4449148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = {
4459148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
4469148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
4479148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
4489148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
4499148cc50SJames Courtier-Dutton };
4509148cc50SJames Courtier-Dutton 
451a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
4529148cc50SJames Courtier-Dutton 
4539148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4549148cc50SJames Courtier-Dutton {
4559148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4569148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4579148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
4589148cc50SJames Courtier-Dutton 	return 0;
4599148cc50SJames Courtier-Dutton }
4609148cc50SJames Courtier-Dutton 
4619148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4629148cc50SJames Courtier-Dutton {
4639148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4649148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4659148cc50SJames Courtier-Dutton 	unsigned int val, cache;
4669148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
4679148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
4689148cc50SJames Courtier-Dutton 	if (val == 1)
4699148cc50SJames Courtier-Dutton 		cache = cache | mask;
4709148cc50SJames Courtier-Dutton 	else
4719148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
4729148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.dac_pads) {
4739148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
4749148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
4759148cc50SJames Courtier-Dutton 	}
4769148cc50SJames Courtier-Dutton 
4779148cc50SJames Courtier-Dutton 	return 0;
4789148cc50SJames Courtier-Dutton }
4799148cc50SJames Courtier-Dutton 
4809148cc50SJames Courtier-Dutton 
4819148cc50SJames Courtier-Dutton 
4829148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \
4839148cc50SJames Courtier-Dutton {								\
4849148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
4859148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
4869148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_dac_pads_info,			\
4879148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_dac_pads_get,			\
4889148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_dac_pads_put,			\
4899148cc50SJames Courtier-Dutton 	.private_value = chid					\
4909148cc50SJames Courtier-Dutton }
4919148cc50SJames Courtier-Dutton 
4929148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = {
4939148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
4949148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
4959148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
4969148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
4979148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
4989f4bd5ddSJames Courtier-Dutton };
4999f4bd5ddSJames Courtier-Dutton 
500b0dbdaeaSJames Courtier-Dutton 
501b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
502b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
503b0dbdaeaSJames Courtier-Dutton {
504*edec7bbbSJames Courtier-Dutton 	static char *texts[4] = {
505*edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
506b0dbdaeaSJames Courtier-Dutton 	};
507b0dbdaeaSJames Courtier-Dutton 
508b0dbdaeaSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
509b0dbdaeaSJames Courtier-Dutton 	uinfo->count = 1;
510*edec7bbbSJames Courtier-Dutton 	uinfo->value.enumerated.items = 4;
511*edec7bbbSJames Courtier-Dutton 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
512*edec7bbbSJames Courtier-Dutton 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
513b0dbdaeaSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
514b0dbdaeaSJames Courtier-Dutton 	return 0;
515*edec7bbbSJames Courtier-Dutton 
516*edec7bbbSJames Courtier-Dutton 
517b0dbdaeaSJames Courtier-Dutton }
518b0dbdaeaSJames Courtier-Dutton 
519b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
520b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
521b0dbdaeaSJames Courtier-Dutton {
522b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
523b0dbdaeaSJames Courtier-Dutton 
524b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
525b0dbdaeaSJames Courtier-Dutton 	return 0;
526b0dbdaeaSJames Courtier-Dutton }
527b0dbdaeaSJames Courtier-Dutton 
528b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
529b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
530b0dbdaeaSJames Courtier-Dutton {
531b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
532b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
533b0dbdaeaSJames Courtier-Dutton 	int change = 0;
534b0dbdaeaSJames Courtier-Dutton 
535b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
536b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
537b0dbdaeaSJames Courtier-Dutton 	if (change) {
538b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
539b0dbdaeaSJames Courtier-Dutton 		switch (val) {
540b0dbdaeaSJames Courtier-Dutton 		case 0:
541b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
542b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
543b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
544b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
545b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
546b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
547b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
548b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
549b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
550b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
551b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
552b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
553e40a0b2eSJames Courtier-Dutton 			msleep(10);
554b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
555b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
556b0dbdaeaSJames Courtier-Dutton 			break;
557b0dbdaeaSJames Courtier-Dutton 		case 1:
558b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
559b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
560b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
561b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
562b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
563b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
564b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
565b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
566b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
567b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
568b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
569b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
570e40a0b2eSJames Courtier-Dutton 			msleep(10);
571b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
572b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
573b0dbdaeaSJames Courtier-Dutton 			break;
574*edec7bbbSJames Courtier-Dutton 
575*edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
576*edec7bbbSJames Courtier-Dutton 			/* Mute all */
577*edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
578*edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
579*edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
580*edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
581*edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
582*edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
583*edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
584*edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
585*edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
586*edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
587*edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
588*edec7bbbSJames Courtier-Dutton 			msleep(10);
589*edec7bbbSJames Courtier-Dutton 			/* Unmute all */
590*edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
591*edec7bbbSJames Courtier-Dutton 			break;
592*edec7bbbSJames Courtier-Dutton 
593*edec7bbbSJames Courtier-Dutton 		case 3:
594*edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
595*edec7bbbSJames Courtier-Dutton 			/* Mute all */
596*edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
597*edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
598*edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
599*edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
600*edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
601*edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
602*edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
603*edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
604*edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
605*edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
606*edec7bbbSJames Courtier-Dutton 			msleep(10);
607*edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
608*edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
609*edec7bbbSJames Courtier-Dutton 
610*edec7bbbSJames Courtier-Dutton 
611*edec7bbbSJames Courtier-Dutton 			break;
612b0dbdaeaSJames Courtier-Dutton 		}
613b0dbdaeaSJames Courtier-Dutton 	}
614b0dbdaeaSJames Courtier-Dutton         return change;
615b0dbdaeaSJames Courtier-Dutton }
616b0dbdaeaSJames Courtier-Dutton 
617b0dbdaeaSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_internal_clock =
618b0dbdaeaSJames Courtier-Dutton {
619b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
620b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
621b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
622b0dbdaeaSJames Courtier-Dutton 	.count =	1,
623b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
624b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
625b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
626b0dbdaeaSJames Courtier-Dutton };
627b0dbdaeaSJames Courtier-Dutton 
628184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
629184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
630184c1e2cSJames Courtier-Dutton {
631184c1e2cSJames Courtier-Dutton #if 0
632184c1e2cSJames Courtier-Dutton 	static char *texts[4] = {
633184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
634184c1e2cSJames Courtier-Dutton 	};
635184c1e2cSJames Courtier-Dutton #endif
636184c1e2cSJames Courtier-Dutton 	static char *texts[2] = {
637184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
638184c1e2cSJames Courtier-Dutton 	};
639184c1e2cSJames Courtier-Dutton 
640184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
641184c1e2cSJames Courtier-Dutton 	uinfo->count = 1;
642184c1e2cSJames Courtier-Dutton 	uinfo->value.enumerated.items = 2;
643184c1e2cSJames Courtier-Dutton 	if (uinfo->value.enumerated.item > 1)
644184c1e2cSJames Courtier-Dutton                 uinfo->value.enumerated.item = 1;
645184c1e2cSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
646184c1e2cSJames Courtier-Dutton 	return 0;
647184c1e2cSJames Courtier-Dutton }
648184c1e2cSJames Courtier-Dutton 
649184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
650184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
651184c1e2cSJames Courtier-Dutton {
652184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
653184c1e2cSJames Courtier-Dutton 
654184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
655184c1e2cSJames Courtier-Dutton 	return 0;
656184c1e2cSJames Courtier-Dutton }
657184c1e2cSJames Courtier-Dutton 
658184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
659184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
660184c1e2cSJames Courtier-Dutton {
661184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
662184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
663184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
664184c1e2cSJames Courtier-Dutton 	u32 gpio;
665184c1e2cSJames Courtier-Dutton 	int change = 0;
666184c1e2cSJames Courtier-Dutton 	unsigned long flags;
667184c1e2cSJames Courtier-Dutton 	u32 source;
668184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
669184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
670184c1e2cSJames Courtier-Dutton 	 * for the particular source.
671184c1e2cSJames Courtier-Dutton 	 */
672184c1e2cSJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */
673184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
674184c1e2cSJames Courtier-Dutton 	if (change) {
675184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
676184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
677184c1e2cSJames Courtier-Dutton 		gpio = inl(emu->port + A_IOCFG);
678184c1e2cSJames Courtier-Dutton 		if (source_id==0)
679184c1e2cSJames Courtier-Dutton 			outl(gpio | 0x4, emu->port + A_IOCFG);
680184c1e2cSJames Courtier-Dutton 		else
681184c1e2cSJames Courtier-Dutton 			outl(gpio & ~0x4, emu->port + A_IOCFG);
682184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
683184c1e2cSJames Courtier-Dutton 
684184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
685184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
686184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
687184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
688184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
689184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
690184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
691184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
692184c1e2cSJames Courtier-Dutton 
693184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
694184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
695184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
696184c1e2cSJames Courtier-Dutton 	}
697184c1e2cSJames Courtier-Dutton         return change;
698184c1e2cSJames Courtier-Dutton }
699184c1e2cSJames Courtier-Dutton 
700184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_capture_source =
701184c1e2cSJames Courtier-Dutton {
702184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
703184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
704184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
705184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
706184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
707184c1e2cSJames Courtier-Dutton };
708184c1e2cSJames Courtier-Dutton 
709184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
710184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
711184c1e2cSJames Courtier-Dutton {
712184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
713184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
714184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
715184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
716184c1e2cSJames Courtier-Dutton 	return 0;
717184c1e2cSJames Courtier-Dutton }
718184c1e2cSJames Courtier-Dutton 
719184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
720184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
721184c1e2cSJames Courtier-Dutton {
722184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
723184c1e2cSJames Courtier-Dutton 	int source_id;
724184c1e2cSJames Courtier-Dutton 
725184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
726184c1e2cSJames Courtier-Dutton 
727184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
728184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
729184c1e2cSJames Courtier-Dutton 	return 0;
730184c1e2cSJames Courtier-Dutton }
731184c1e2cSJames Courtier-Dutton 
732184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
733184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
734184c1e2cSJames Courtier-Dutton {
735184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
736184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
737184c1e2cSJames Courtier-Dutton 	unsigned int ngain;
738184c1e2cSJames Courtier-Dutton 	int source_id;
739184c1e2cSJames Courtier-Dutton 	int change = 0;
740184c1e2cSJames Courtier-Dutton 
741184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
742184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
743184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[0];
744184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
745184c1e2cSJames Courtier-Dutton 		return 0;
746184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
747184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
748184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
749184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
750184c1e2cSJames Courtier-Dutton 		change = 1;
751184c1e2cSJames Courtier-Dutton 	}
752184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
753184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[1];
754184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
755184c1e2cSJames Courtier-Dutton 		return 0;
756184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
757184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
758184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
759184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
760184c1e2cSJames Courtier-Dutton 		change = 1;
761184c1e2cSJames Courtier-Dutton 	}
762184c1e2cSJames Courtier-Dutton 
763184c1e2cSJames Courtier-Dutton 	return change;
764184c1e2cSJames Courtier-Dutton }
765184c1e2cSJames Courtier-Dutton 
766184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \
767184c1e2cSJames Courtier-Dutton {								\
768184c1e2cSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
769184c1e2cSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
770184c1e2cSJames Courtier-Dutton 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
771184c1e2cSJames Courtier-Dutton 	.info =  snd_audigy_i2c_volume_info,			\
772184c1e2cSJames Courtier-Dutton 	.get =   snd_audigy_i2c_volume_get,			\
773184c1e2cSJames Courtier-Dutton 	.put =   snd_audigy_i2c_volume_put,			\
774184c1e2cSJames Courtier-Dutton 	.tlv = { .p = snd_audigy_db_scale2 },			\
775184c1e2cSJames Courtier-Dutton 	.private_value = chid					\
776184c1e2cSJames Courtier-Dutton }
777184c1e2cSJames Courtier-Dutton 
778184c1e2cSJames Courtier-Dutton 
779184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = {
780184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Mic Capture Volume", 0),
781184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Line Capture Volume", 0)
782184c1e2cSJames Courtier-Dutton };
783184c1e2cSJames Courtier-Dutton 
7840af68e5eSTakashi Iwai #if 0
785eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
7861da177e4SLinus Torvalds {
7871da177e4SLinus Torvalds 	static char *texts[] = {"44100", "48000", "96000"};
7881da177e4SLinus Torvalds 
7891da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
7901da177e4SLinus Torvalds 	uinfo->count = 1;
7911da177e4SLinus Torvalds 	uinfo->value.enumerated.items = 3;
7921da177e4SLinus Torvalds 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
7931da177e4SLinus Torvalds 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
7941da177e4SLinus Torvalds 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
7951da177e4SLinus Torvalds 	return 0;
7961da177e4SLinus Torvalds }
7971da177e4SLinus Torvalds 
798eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
799eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
8001da177e4SLinus Torvalds {
801eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
8021da177e4SLinus Torvalds 	unsigned int tmp;
8031da177e4SLinus Torvalds 	unsigned long flags;
8041da177e4SLinus Torvalds 
8051da177e4SLinus Torvalds 
8061da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
8071da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
8081da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
8091da177e4SLinus Torvalds 	case A_SPDIF_44100:
8101da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
8111da177e4SLinus Torvalds 		break;
8121da177e4SLinus Torvalds 	case A_SPDIF_48000:
8131da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
8141da177e4SLinus Torvalds 		break;
8151da177e4SLinus Torvalds 	case A_SPDIF_96000:
8161da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
8171da177e4SLinus Torvalds 		break;
8181da177e4SLinus Torvalds 	default:
8191da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
8201da177e4SLinus Torvalds 	}
8211da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
8221da177e4SLinus Torvalds 	return 0;
8231da177e4SLinus Torvalds }
8241da177e4SLinus Torvalds 
825eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
826eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
8271da177e4SLinus Torvalds {
828eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
8291da177e4SLinus Torvalds 	int change;
8301da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
8311da177e4SLinus Torvalds 	unsigned long flags;
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
8341da177e4SLinus Torvalds 	case 0:
8351da177e4SLinus Torvalds 		val = A_SPDIF_44100;
8361da177e4SLinus Torvalds 		break;
8371da177e4SLinus Torvalds 	case 1:
8381da177e4SLinus Torvalds 		val = A_SPDIF_48000;
8391da177e4SLinus Torvalds 		break;
8401da177e4SLinus Torvalds 	case 2:
8411da177e4SLinus Torvalds 		val = A_SPDIF_96000;
8421da177e4SLinus Torvalds 		break;
8431da177e4SLinus Torvalds 	default:
8441da177e4SLinus Torvalds 		val = A_SPDIF_48000;
8451da177e4SLinus Torvalds 		break;
8461da177e4SLinus Torvalds 	}
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
8501da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
8511da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
8521da177e4SLinus Torvalds 	tmp |= val;
8531da177e4SLinus Torvalds 	if ((change = (tmp != reg)))
8541da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
8551da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
8561da177e4SLinus Torvalds 	return change;
8571da177e4SLinus Torvalds }
8581da177e4SLinus Torvalds 
859eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_spdif_output_rate =
8601da177e4SLinus Torvalds {
8611da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
8621da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
8631da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
8641da177e4SLinus Torvalds 	.count =	1,
8651da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
8661da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
8671da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
8681da177e4SLinus Torvalds };
8690af68e5eSTakashi Iwai #endif
8701da177e4SLinus Torvalds 
871eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
872eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
8731da177e4SLinus Torvalds {
874eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
8751da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
8761da177e4SLinus Torvalds 	int change;
8771da177e4SLinus Torvalds 	unsigned int val;
8781da177e4SLinus Torvalds 	unsigned long flags;
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
8811da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
8821da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
8831da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
8841da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
8851da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
8861da177e4SLinus Torvalds 	if (change) {
8871da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
8881da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
8891da177e4SLinus Torvalds 	}
8901da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
8911da177e4SLinus Torvalds 	return change;
8921da177e4SLinus Torvalds }
8931da177e4SLinus Torvalds 
894eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
8951da177e4SLinus Torvalds {
8961da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
8975549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
8981da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
8991da177e4SLinus Torvalds 	.count =	4,
9001da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
9011da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
9021da177e4SLinus Torvalds };
9031da177e4SLinus Torvalds 
904eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_control =
9051da177e4SLinus Torvalds {
9065549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
9071da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
9081da177e4SLinus Torvalds 	.count =	4,
9091da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
9101da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
9111da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
9121da177e4SLinus Torvalds };
9131da177e4SLinus Torvalds 
9141da177e4SLinus Torvalds 
915eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
9161da177e4SLinus Torvalds {
9171da177e4SLinus Torvalds 	if (emu->audigy) {
9181da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
9191da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
9201da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
9211da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
9221da177e4SLinus Torvalds 	} else {
9231da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
9241da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
9251da177e4SLinus Torvalds 	}
9261da177e4SLinus Torvalds }
9271da177e4SLinus Torvalds 
928eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
9291da177e4SLinus Torvalds {
9301da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
9311da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
9321da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
9331da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
9341da177e4SLinus Torvalds 	if (emu->audigy) {
9351da177e4SLinus Torvalds 		unsigned int val = ((unsigned int)volume[4] << 24) |
9361da177e4SLinus Torvalds 			((unsigned int)volume[5] << 16) |
9371da177e4SLinus Torvalds 			((unsigned int)volume[6] << 8) |
9381da177e4SLinus Torvalds 			(unsigned int)volume[7];
9391da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
9401da177e4SLinus Torvalds 	}
9411da177e4SLinus Torvalds }
9421da177e4SLinus Torvalds 
9431da177e4SLinus Torvalds /* PCM stream controls */
9441da177e4SLinus Torvalds 
945eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9461da177e4SLinus Torvalds {
947eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
9481da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
9491da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
9501da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
9511da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
9521da177e4SLinus Torvalds 	return 0;
9531da177e4SLinus Torvalds }
9541da177e4SLinus Torvalds 
955eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
956eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
9571da177e4SLinus Torvalds {
9581da177e4SLinus Torvalds 	unsigned long flags;
959eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
960eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
961eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
9621da177e4SLinus Torvalds 	int voice, idx;
9631da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
9641da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
9651da177e4SLinus Torvalds 
9661da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
9671da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
9681da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
9691da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
9701da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
9711da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
9721da177e4SLinus Torvalds 	return 0;
9731da177e4SLinus Torvalds }
9741da177e4SLinus Torvalds 
975eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
976eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
9771da177e4SLinus Torvalds {
9781da177e4SLinus Torvalds 	unsigned long flags;
979eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
980eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
981eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
9821da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
9831da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
9841da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
9851da177e4SLinus Torvalds 
9861da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
9871da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
9881da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
9891da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
9901da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
9911da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
9921da177e4SLinus Torvalds 				change = 1;
9931da177e4SLinus Torvalds 			}
9941da177e4SLinus Torvalds 		}
9951da177e4SLinus Torvalds 	if (change && mix->epcm) {
9961da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
9971da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
9981da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
9991da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
10001da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
10011da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
10021da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
10031da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
10041da177e4SLinus Torvalds 		}
10051da177e4SLinus Torvalds 	}
10061da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10071da177e4SLinus Torvalds 	return change;
10081da177e4SLinus Torvalds }
10091da177e4SLinus Torvalds 
1010eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_routing_control =
10111da177e4SLinus Torvalds {
10121da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
101367ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
10141da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
10151da177e4SLinus Torvalds 	.count =	32,
10161da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
10171da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
10181da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
10191da177e4SLinus Torvalds };
10201da177e4SLinus Torvalds 
1021eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
10221da177e4SLinus Torvalds {
1023eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10241da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
10251da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
10261da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
10271da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
10281da177e4SLinus Torvalds 	return 0;
10291da177e4SLinus Torvalds }
10301da177e4SLinus Torvalds 
1031eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1032eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
10331da177e4SLinus Torvalds {
10341da177e4SLinus Torvalds 	unsigned long flags;
1035eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1036eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1037eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10381da177e4SLinus Torvalds 	int idx;
10391da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10421da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
10431da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
10441da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10451da177e4SLinus Torvalds 	return 0;
10461da177e4SLinus Torvalds }
10471da177e4SLinus Torvalds 
1048eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1049eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
10501da177e4SLinus Torvalds {
10511da177e4SLinus Torvalds 	unsigned long flags;
1052eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1053eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1054eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10551da177e4SLinus Torvalds 	int change = 0, idx, val;
10561da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10591da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
10601da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
10611da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
10621da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
10631da177e4SLinus Torvalds 			change = 1;
10641da177e4SLinus Torvalds 		}
10651da177e4SLinus Torvalds 	}
10661da177e4SLinus Torvalds 	if (change && mix->epcm) {
10671da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
10681da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
10691da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
10701da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
10711da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
10721da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
10731da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
10741da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
10751da177e4SLinus Torvalds 		}
10761da177e4SLinus Torvalds 	}
10771da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10781da177e4SLinus Torvalds 	return change;
10791da177e4SLinus Torvalds }
10801da177e4SLinus Torvalds 
1081eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_volume_control =
10821da177e4SLinus Torvalds {
10831da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
108467ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
10851da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
10861da177e4SLinus Torvalds 	.count =	32,
10871da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
10881da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
10891da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
10901da177e4SLinus Torvalds };
10911da177e4SLinus Torvalds 
1092eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
10931da177e4SLinus Torvalds {
10941da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
10951da177e4SLinus Torvalds 	uinfo->count = 3;
10961da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
10971da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
10981da177e4SLinus Torvalds 	return 0;
10991da177e4SLinus Torvalds }
11001da177e4SLinus Torvalds 
1101eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1102eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
11031da177e4SLinus Torvalds {
1104eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1105eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1106eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11071da177e4SLinus Torvalds 	unsigned long flags;
11081da177e4SLinus Torvalds 	int idx;
11091da177e4SLinus Torvalds 
11101da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11111da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
11121da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->attn[idx];
11131da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11141da177e4SLinus Torvalds 	return 0;
11151da177e4SLinus Torvalds }
11161da177e4SLinus Torvalds 
1117eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1118eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
11191da177e4SLinus Torvalds {
11201da177e4SLinus Torvalds 	unsigned long flags;
1121eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1122eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1123eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11241da177e4SLinus Torvalds 	int change = 0, idx, val;
11251da177e4SLinus Torvalds 
11261da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11271da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
11281da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 0xffff;
11291da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
11301da177e4SLinus Torvalds 			mix->attn[idx] = val;
11311da177e4SLinus Torvalds 			change = 1;
11321da177e4SLinus Torvalds 		}
11331da177e4SLinus Torvalds 	}
11341da177e4SLinus Torvalds 	if (change && mix->epcm) {
11351da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
11361da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
11371da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
11381da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
11391da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
11401da177e4SLinus Torvalds 		}
11411da177e4SLinus Torvalds 	}
11421da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11431da177e4SLinus Torvalds 	return change;
11441da177e4SLinus Torvalds }
11451da177e4SLinus Torvalds 
1146eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_attn_control =
11471da177e4SLinus Torvalds {
11481da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
114967ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11501da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
11511da177e4SLinus Torvalds 	.count =	32,
11521da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
11531da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
11541da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
11551da177e4SLinus Torvalds };
11561da177e4SLinus Torvalds 
11571da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
11581da177e4SLinus Torvalds 
1159eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11601da177e4SLinus Torvalds {
1161eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11621da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11631da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
11641da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11651da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
11661da177e4SLinus Torvalds 	return 0;
11671da177e4SLinus Torvalds }
11681da177e4SLinus Torvalds 
1169eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1170eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11711da177e4SLinus Torvalds {
11721da177e4SLinus Torvalds 	unsigned long flags;
1173eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1174eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1175eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11761da177e4SLinus Torvalds 	int idx;
11771da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11781da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11791da177e4SLinus Torvalds 
11801da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11811da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
11821da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
11831da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
11841da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11851da177e4SLinus Torvalds 	return 0;
11861da177e4SLinus Torvalds }
11871da177e4SLinus Torvalds 
1188eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1189eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11901da177e4SLinus Torvalds {
11911da177e4SLinus Torvalds 	unsigned long flags;
1192eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11931da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1194eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
11951da177e4SLinus Torvalds 	int change = 0, idx, val;
11961da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11971da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11981da177e4SLinus Torvalds 
11991da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12001da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
12011da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
12021da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
12031da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
12041da177e4SLinus Torvalds 			change = 1;
12051da177e4SLinus Torvalds 		}
12061da177e4SLinus Torvalds 	}
12071da177e4SLinus Torvalds 
12081da177e4SLinus Torvalds 	if (change && mix->epcm) {
12091da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
12101da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
12111da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
12121da177e4SLinus Torvalds 		}
12131da177e4SLinus Torvalds 	}
12141da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12151da177e4SLinus Torvalds 	return change;
12161da177e4SLinus Torvalds }
12171da177e4SLinus Torvalds 
1218eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
12191da177e4SLinus Torvalds {
12201da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
12211da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12221da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
12231da177e4SLinus Torvalds 	.count =	16,
12241da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
12251da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
12261da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
12271da177e4SLinus Torvalds };
12281da177e4SLinus Torvalds 
1229eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12301da177e4SLinus Torvalds {
1231eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12321da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12331da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
12341da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12351da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
12361da177e4SLinus Torvalds 	return 0;
12371da177e4SLinus Torvalds }
12381da177e4SLinus Torvalds 
1239eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1240eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12411da177e4SLinus Torvalds {
12421da177e4SLinus Torvalds 	unsigned long flags;
1243eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1244eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1245eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12461da177e4SLinus Torvalds 	int idx;
12471da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12481da177e4SLinus Torvalds 
12491da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12501da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
12511da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
12521da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12531da177e4SLinus Torvalds 	return 0;
12541da177e4SLinus Torvalds }
12551da177e4SLinus Torvalds 
1256eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1257eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12581da177e4SLinus Torvalds {
12591da177e4SLinus Torvalds 	unsigned long flags;
1260eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12611da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1262eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
12631da177e4SLinus Torvalds 	int change = 0, idx, val;
12641da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12651da177e4SLinus Torvalds 
12661da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12671da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
12681da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
12691da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
12701da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
12711da177e4SLinus Torvalds 			change = 1;
12721da177e4SLinus Torvalds 		}
12731da177e4SLinus Torvalds 	}
12741da177e4SLinus Torvalds 	if (change && mix->epcm) {
12751da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
12761da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
12771da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
12781da177e4SLinus Torvalds 		}
12791da177e4SLinus Torvalds 	}
12801da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12811da177e4SLinus Torvalds 	return change;
12821da177e4SLinus Torvalds }
12831da177e4SLinus Torvalds 
12841da177e4SLinus Torvalds 
1285eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
12861da177e4SLinus Torvalds {
12871da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
12881da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12891da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
12901da177e4SLinus Torvalds 	.count =	16,
12911da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
12921da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
12931da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
12941da177e4SLinus Torvalds };
12951da177e4SLinus Torvalds 
1296eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12971da177e4SLinus Torvalds {
12981da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12991da177e4SLinus Torvalds 	uinfo->count = 1;
13001da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13011da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
13021da177e4SLinus Torvalds 	return 0;
13031da177e4SLinus Torvalds }
13041da177e4SLinus Torvalds 
1305eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1306eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
13071da177e4SLinus Torvalds {
1308eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1309eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1310eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13111da177e4SLinus Torvalds 	unsigned long flags;
13121da177e4SLinus Torvalds 
13131da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13141da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = mix->attn[0];
13151da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13161da177e4SLinus Torvalds 	return 0;
13171da177e4SLinus Torvalds }
13181da177e4SLinus Torvalds 
1319eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1320eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
13211da177e4SLinus Torvalds {
13221da177e4SLinus Torvalds 	unsigned long flags;
1323eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13241da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1325eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
13261da177e4SLinus Torvalds 	int change = 0, val;
13271da177e4SLinus Torvalds 
13281da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13291da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] & 0xffff;
13301da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
13311da177e4SLinus Torvalds 		mix->attn[0] = val;
13321da177e4SLinus Torvalds 		change = 1;
13331da177e4SLinus Torvalds 	}
13341da177e4SLinus Torvalds 	if (change && mix->epcm) {
13351da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
13361da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
13371da177e4SLinus Torvalds 		}
13381da177e4SLinus Torvalds 	}
13391da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13401da177e4SLinus Torvalds 	return change;
13411da177e4SLinus Torvalds }
13421da177e4SLinus Torvalds 
1343eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
13441da177e4SLinus Torvalds {
13451da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
13461da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13471da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
13481da177e4SLinus Torvalds 	.count =	16,
13491da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
13501da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
13511da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
13521da177e4SLinus Torvalds };
13531da177e4SLinus Torvalds 
1354a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
13551da177e4SLinus Torvalds 
1356eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1357eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
13581da177e4SLinus Torvalds {
1359eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13601da177e4SLinus Torvalds 
13611da177e4SLinus Torvalds 	if (emu->audigy)
13621da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
13631da177e4SLinus Torvalds 	else
13641da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
13651da177e4SLinus Torvalds 	return 0;
13661da177e4SLinus Torvalds }
13671da177e4SLinus Torvalds 
1368eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1369eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
13701da177e4SLinus Torvalds {
13711da177e4SLinus Torvalds 	unsigned long flags;
1372eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13731da177e4SLinus Torvalds 	unsigned int reg, val;
13741da177e4SLinus Torvalds 	int change = 0;
13751da177e4SLinus Torvalds 
13761da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1377184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1378184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1379184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
13801da177e4SLinus Torvalds 		reg = inl(emu->port + A_IOCFG);
13811da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
13821da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
13831da177e4SLinus Torvalds 		if (change) {
13841da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
13851da177e4SLinus Torvalds 			reg |= val;
13861da177e4SLinus Torvalds 			outl(reg | val, emu->port + A_IOCFG);
13871da177e4SLinus Torvalds 		}
13881da177e4SLinus Torvalds 	}
13891da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
13901da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0;
13911da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
13921da177e4SLinus Torvalds 	if (change) {
13931da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
13941da177e4SLinus Torvalds 		reg |= val;
13951da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
13961da177e4SLinus Torvalds 	}
13971da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13981da177e4SLinus Torvalds 	return change;
13991da177e4SLinus Torvalds }
14001da177e4SLinus Torvalds 
1401eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata =
14021da177e4SLinus Torvalds {
14031da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
14041da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
14051da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
14061da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
14071da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
14081da177e4SLinus Torvalds };
14091da177e4SLinus Torvalds 
1410eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata =
14111da177e4SLinus Torvalds {
14121da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
14131da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
14141da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
14151da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
14161da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
14171da177e4SLinus Torvalds };
14181da177e4SLinus Torvalds 
14191da177e4SLinus Torvalds /*
14201da177e4SLinus Torvalds  */
1421eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
14221da177e4SLinus Torvalds {
1423eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
14241da177e4SLinus Torvalds 	emu->ac97 = NULL;
14251da177e4SLinus Torvalds }
14261da177e4SLinus Torvalds 
14271da177e4SLinus Torvalds /*
14281da177e4SLinus Torvalds  */
1429eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
14301da177e4SLinus Torvalds {
1431eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
14321da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
14331da177e4SLinus Torvalds 	strcpy(id.name, name);
14341da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
14351da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
14361da177e4SLinus Torvalds }
14371da177e4SLinus Torvalds 
1438eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
14391da177e4SLinus Torvalds {
1440eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
14411da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
14421da177e4SLinus Torvalds 	strcpy(sid.name, name);
14431da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
14441da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
14451da177e4SLinus Torvalds }
14461da177e4SLinus Torvalds 
1447eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
14481da177e4SLinus Torvalds {
1449eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
14501da177e4SLinus Torvalds 	if (kctl) {
14511da177e4SLinus Torvalds 		strcpy(kctl->id.name, dst);
14521da177e4SLinus Torvalds 		return 0;
14531da177e4SLinus Torvalds 	}
14541da177e4SLinus Torvalds 	return -ENOENT;
14551da177e4SLinus Torvalds }
14561da177e4SLinus Torvalds 
1457eb4698f3STakashi Iwai int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
145867ed4161SClemens Ladisch 				int pcm_device, int multi_device)
14591da177e4SLinus Torvalds {
14601da177e4SLinus Torvalds 	int err, pcm;
1461eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1462eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
14631da177e4SLinus Torvalds 	char **c;
14641da177e4SLinus Torvalds 	static char *emu10k1_remove_ctls[] = {
14651da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
14661da177e4SLinus Torvalds 		"Master Mono Playback Switch",
14671da177e4SLinus Torvalds 		"Master Mono Playback Volume",
14681da177e4SLinus Torvalds 		"PCM Out Path & Mute",
14691da177e4SLinus Torvalds 		"Mono Output Select",
14707eae36fbSTakashi Iwai 		"Front Playback Switch",
14717eae36fbSTakashi Iwai 		"Front Playback Volume",
14721da177e4SLinus Torvalds 		"Surround Playback Switch",
14731da177e4SLinus Torvalds 		"Surround Playback Volume",
14741da177e4SLinus Torvalds 		"Center Playback Switch",
14751da177e4SLinus Torvalds 		"Center Playback Volume",
14761da177e4SLinus Torvalds 		"LFE Playback Switch",
14771da177e4SLinus Torvalds 		"LFE Playback Volume",
14781da177e4SLinus Torvalds 		NULL
14791da177e4SLinus Torvalds 	};
14801da177e4SLinus Torvalds 	static char *emu10k1_rename_ctls[] = {
14811da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
14821da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
14831da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
14841da177e4SLinus Torvalds 		NULL
14851da177e4SLinus Torvalds 	};
14861da177e4SLinus Torvalds 	static char *audigy_remove_ctls[] = {
14871da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
148821fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
148921fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
14901da177e4SLinus Torvalds 		"PCM Playback Switch",
14911da177e4SLinus Torvalds 		"PCM Playback Volume",
14921da177e4SLinus Torvalds 		"Master Mono Playback Switch",
14931da177e4SLinus Torvalds 		"Master Mono Playback Volume",
14941da177e4SLinus Torvalds 		"Master Playback Switch",
14951da177e4SLinus Torvalds 		"Master Playback Volume",
14961da177e4SLinus Torvalds 		"PCM Out Path & Mute",
14971da177e4SLinus Torvalds 		"Mono Output Select",
14981da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
14991da177e4SLinus Torvalds 		"Capture Source",
15001da177e4SLinus Torvalds 		"Capture Switch",
15011da177e4SLinus Torvalds 		"Capture Volume",
15021da177e4SLinus Torvalds 		"Mic Select",
15031da177e4SLinus Torvalds 		"Video Playback Switch",
15041da177e4SLinus Torvalds 		"Video Playback Volume",
15051da177e4SLinus Torvalds 		"Mic Playback Switch",
15061da177e4SLinus Torvalds 		"Mic Playback Volume",
15071da177e4SLinus Torvalds 		NULL
15081da177e4SLinus Torvalds 	};
15091da177e4SLinus Torvalds 	static char *audigy_rename_ctls[] = {
15101da177e4SLinus Torvalds 		/* use conventional names */
15111da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
15121da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
15131da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
15141da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
15151da177e4SLinus Torvalds 		NULL
15161da177e4SLinus Torvalds 	};
1517184c1e2cSJames Courtier-Dutton 	static char *audigy_rename_ctls_i2c_adc[] = {
1518184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1519184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1520184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1521184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1522184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1523eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1524184c1e2cSJames Courtier-Dutton 		NULL
1525184c1e2cSJames Courtier-Dutton 	};
1526184c1e2cSJames Courtier-Dutton 	static char *audigy_remove_ctls_i2c_adc[] = {
1527184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1528184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1529184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1530184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1531184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1532eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1533184c1e2cSJames Courtier-Dutton 		NULL
1534184c1e2cSJames Courtier-Dutton 	};
153521fdddeaSJames Courtier-Dutton 	static char *audigy_remove_ctls_1361t_adc[] = {
153621fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
153721fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
153821fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
153921fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
154021fdddeaSJames Courtier-Dutton 		"Master Mono Playback Switch",
154121fdddeaSJames Courtier-Dutton 		"Master Mono Playback Volume",
154221fdddeaSJames Courtier-Dutton 		"Capture Source",
154321fdddeaSJames Courtier-Dutton 		"Capture Switch",
154421fdddeaSJames Courtier-Dutton 		"Capture Volume",
154521fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
154621fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
154721fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
154821fdddeaSJames Courtier-Dutton 		"3D Control - Center",
154921fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
155021fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
155121fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
155221fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
155321fdddeaSJames Courtier-Dutton 		NULL
155421fdddeaSJames Courtier-Dutton 	};
155521fdddeaSJames Courtier-Dutton 	static char *audigy_rename_ctls_1361t_adc[] = {
155621fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
155721fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
155821fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
155921fdddeaSJames Courtier-Dutton 		"PC Speaker Playback Switch", "PC Speaker Capture Switch",
156021fdddeaSJames Courtier-Dutton 		"PC Speaker Playback Volume", "PC Speaker Capture Volume",
156121fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
156221fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
156321fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
156421fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
156521fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
156621fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
156721fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
156821fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
156921fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
157021fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
157121fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
157221fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
157321fdddeaSJames Courtier-Dutton 
157421fdddeaSJames Courtier-Dutton 		NULL
157521fdddeaSJames Courtier-Dutton 	};
15761da177e4SLinus Torvalds 
15772b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1578eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1579eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
1580eb4698f3STakashi Iwai 		static struct snd_ac97_bus_ops ops = {
15811da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
15821da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
15831da177e4SLinus Torvalds 		};
15841da177e4SLinus Torvalds 
1585b1508693STakashi Iwai 		if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0)
15861da177e4SLinus Torvalds 			return err;
15871da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
15881da177e4SLinus Torvalds 
15891da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
15901da177e4SLinus Torvalds 		ac97.private_data = emu;
15911da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
15921da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
1593b1508693STakashi Iwai 		if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
1594b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
15951da177e4SLinus Torvalds 				return err;
1596b1508693STakashi Iwai 			snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n");
1597b1508693STakashi Iwai 			snd_printd(KERN_INFO"          Proceeding without ac97 mixers...\n");
1598b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1599b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1600b1508693STakashi Iwai 		}
16011da177e4SLinus Torvalds 		if (emu->audigy) {
16021da177e4SLinus Torvalds 			/* set master volume to 0 dB */
16034d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
16041da177e4SLinus Torvalds 			/* set capture source to mic */
16054d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
160621fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
160721fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
160821fdddeaSJames Courtier-Dutton 			else
16091da177e4SLinus Torvalds 				c = audigy_remove_ctls;
16101da177e4SLinus Torvalds 		} else {
16111da177e4SLinus Torvalds 			/*
16121da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
16131da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
16141da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
16151da177e4SLinus Torvalds 			 */
16161da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
16171da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
16181da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
16192594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
16201da177e4SLinus Torvalds 			}
16211da177e4SLinus Torvalds 			/* remove unused AC97 controls */
16224d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
16234d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
16241da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
16251da177e4SLinus Torvalds 		}
16261da177e4SLinus Torvalds 		for (; *c; c++)
16271da177e4SLinus Torvalds 			remove_ctl(card, *c);
1628184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1629184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1630184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1631184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
16321da177e4SLinus Torvalds 	} else {
1633f12aa40cSTakashi Iwai 	no_ac97:
16342b637da5SLee Revell 		if (emu->card_capabilities->ecard)
16351da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
16361da177e4SLinus Torvalds 		else if (emu->audigy)
16371da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
16381da177e4SLinus Torvalds 		else
16391da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
16401da177e4SLinus Torvalds 	}
16411da177e4SLinus Torvalds 
16421da177e4SLinus Torvalds 	if (emu->audigy)
164321fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
164421fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1645184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1646184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
164721fdddeaSJames Courtier-Dutton 		else
16481da177e4SLinus Torvalds 			c = audigy_rename_ctls;
16491da177e4SLinus Torvalds 	else
16501da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
16511da177e4SLinus Torvalds 	for (; *c; c += 2)
16521da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
165321fdddeaSJames Courtier-Dutton 
1654e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1655e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1656e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1657e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1658e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1659e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Switch");
1660e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Volume");
1661e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Center");
1662e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Depth");
1663e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Switch");
1664e3b9bc0eSJames Courtier-Dutton 	}
16651da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
16661da177e4SLinus Torvalds 		return -ENOMEM;
166767ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
16681da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16691da177e4SLinus Torvalds 		return err;
16701da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
16711da177e4SLinus Torvalds 		return -ENOMEM;
167267ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
16731da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16741da177e4SLinus Torvalds 		return err;
16751da177e4SLinus Torvalds 	if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
16761da177e4SLinus Torvalds 		return -ENOMEM;
167767ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
16781da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16791da177e4SLinus Torvalds 		return err;
16801da177e4SLinus Torvalds 
16811da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
16821da177e4SLinus Torvalds 		return -ENOMEM;
168367ed4161SClemens Ladisch 	kctl->id.device = multi_device;
16841da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16851da177e4SLinus Torvalds 		return err;
16861da177e4SLinus Torvalds 
16871da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
16881da177e4SLinus Torvalds 		return -ENOMEM;
168967ed4161SClemens Ladisch 	kctl->id.device = multi_device;
16901da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16911da177e4SLinus Torvalds 		return err;
16921da177e4SLinus Torvalds 
16931da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
16941da177e4SLinus Torvalds 		return -ENOMEM;
169567ed4161SClemens Ladisch 	kctl->id.device = multi_device;
16961da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16971da177e4SLinus Torvalds 		return err;
16981da177e4SLinus Torvalds 
16991da177e4SLinus Torvalds 	/* initialize the routing and volume table for each pcm playback stream */
17001da177e4SLinus Torvalds 	for (pcm = 0; pcm < 32; pcm++) {
1701eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
17021da177e4SLinus Torvalds 		int v;
17031da177e4SLinus Torvalds 
17041da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[pcm];
17051da177e4SLinus Torvalds 		mix->epcm = NULL;
17061da177e4SLinus Torvalds 
17071da177e4SLinus Torvalds 		for (v = 0; v < 4; v++)
17081da177e4SLinus Torvalds 			mix->send_routing[0][v] =
17091da177e4SLinus Torvalds 				mix->send_routing[1][v] =
17101da177e4SLinus Torvalds 				mix->send_routing[2][v] = v;
17111da177e4SLinus Torvalds 
17121da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
17131da177e4SLinus Torvalds 		mix->send_volume[0][0] = mix->send_volume[0][1] =
17141da177e4SLinus Torvalds 		mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
17151da177e4SLinus Torvalds 
17161da177e4SLinus Torvalds 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
17171da177e4SLinus Torvalds 	}
17181da177e4SLinus Torvalds 
17191da177e4SLinus Torvalds 	/* initialize the routing and volume table for the multichannel playback stream */
17201da177e4SLinus Torvalds 	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
1721eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
17221da177e4SLinus Torvalds 		int v;
17231da177e4SLinus Torvalds 
17241da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[pcm];
17251da177e4SLinus Torvalds 		mix->epcm = NULL;
17261da177e4SLinus Torvalds 
17271da177e4SLinus Torvalds 		mix->send_routing[0][0] = pcm;
17281da177e4SLinus Torvalds 		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
17291da177e4SLinus Torvalds 		for (v = 0; v < 2; v++)
17301da177e4SLinus Torvalds 			mix->send_routing[0][2+v] = 13+v;
17311da177e4SLinus Torvalds 		if (emu->audigy)
17321da177e4SLinus Torvalds 			for (v = 0; v < 4; v++)
17331da177e4SLinus Torvalds 				mix->send_routing[0][4+v] = 60+v;
17341da177e4SLinus Torvalds 
17351da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
17361da177e4SLinus Torvalds 		mix->send_volume[0][0]  = 255;
17371da177e4SLinus Torvalds 
17381da177e4SLinus Torvalds 		mix->attn[0] = 0xffff;
17391da177e4SLinus Torvalds 	}
17401da177e4SLinus Torvalds 
17412b637da5SLee Revell 	if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
17421da177e4SLinus Torvalds 		/* sb live! and audigy */
17431da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
17441da177e4SLinus Torvalds 			return -ENOMEM;
17455549d549SClemens Ladisch 		if (!emu->audigy)
17465549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
17471da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17481da177e4SLinus Torvalds 			return err;
17491da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
17501da177e4SLinus Torvalds 			return -ENOMEM;
17515549d549SClemens Ladisch 		if (!emu->audigy)
17525549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
17531da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17541da177e4SLinus Torvalds 			return err;
17551da177e4SLinus Torvalds 	}
17561da177e4SLinus Torvalds 
17579f4bd5ddSJames Courtier-Dutton 	if ( emu->card_capabilities->emu1010) {
175819b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
175919b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
17601da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
17611da177e4SLinus Torvalds 			return -ENOMEM;
17621da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17631da177e4SLinus Torvalds 			return err;
1764001f7589SJames Courtier-Dutton #if 0
17651da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
17661da177e4SLinus Torvalds 			return -ENOMEM;
17671da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17681da177e4SLinus Torvalds 			return err;
1769001f7589SJames Courtier-Dutton #endif
17702b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
17711da177e4SLinus Torvalds 		/* sb live! */
17721da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
17731da177e4SLinus Torvalds 			return -ENOMEM;
17741da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17751da177e4SLinus Torvalds 			return err;
17761da177e4SLinus Torvalds 	}
17772b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
17781da177e4SLinus Torvalds 		if ((err = snd_p16v_mixer(emu)))
17791da177e4SLinus Torvalds 			return err;
17801da177e4SLinus Torvalds 	}
17811da177e4SLinus Torvalds 
17829f4bd5ddSJames Courtier-Dutton 	if ( emu->card_capabilities->emu1010) {
17839f4bd5ddSJames Courtier-Dutton 		int i;
17849f4bd5ddSJames Courtier-Dutton 
17859f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
17869f4bd5ddSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu));
17879f4bd5ddSJames Courtier-Dutton 			if (err < 0)
17889f4bd5ddSJames Courtier-Dutton 				return err;
17899f4bd5ddSJames Courtier-Dutton 		}
17909f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
17919f4bd5ddSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu));
17929f4bd5ddSJames Courtier-Dutton 			if (err < 0)
17939f4bd5ddSJames Courtier-Dutton 				return err;
17949f4bd5ddSJames Courtier-Dutton 		}
17959148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
17969148cc50SJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
17979148cc50SJames Courtier-Dutton 			if (err < 0)
17989148cc50SJames Courtier-Dutton 				return err;
17999148cc50SJames Courtier-Dutton 		}
18009148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
18019148cc50SJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
18029148cc50SJames Courtier-Dutton 			if (err < 0)
18039148cc50SJames Courtier-Dutton 				return err;
18049148cc50SJames Courtier-Dutton 		}
1805b0dbdaeaSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu));
1806b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
1807b0dbdaeaSJames Courtier-Dutton 			return err;
18089f4bd5ddSJames Courtier-Dutton 	}
18099f4bd5ddSJames Courtier-Dutton 
1810184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1811184c1e2cSJames Courtier-Dutton 		int i;
1812184c1e2cSJames Courtier-Dutton 
1813184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
1814184c1e2cSJames Courtier-Dutton 		if (err < 0)
1815184c1e2cSJames Courtier-Dutton 			return err;
1816184c1e2cSJames Courtier-Dutton 
1817184c1e2cSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
1818184c1e2cSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
1819184c1e2cSJames Courtier-Dutton 			if (err < 0)
1820184c1e2cSJames Courtier-Dutton 				return err;
1821184c1e2cSJames Courtier-Dutton 		}
1822184c1e2cSJames Courtier-Dutton 	}
1823184c1e2cSJames Courtier-Dutton 
18241da177e4SLinus Torvalds 	return 0;
18251da177e4SLinus Torvalds }
1826