11da177e4SLinus Torvalds /* 2c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, 31da177e4SLinus Torvalds * Takashi Iwai <tiwai@suse.de> 41da177e4SLinus Torvalds * Creative Labs, Inc. 51da177e4SLinus Torvalds * Routines for control of EMU10K1 chips / mixer routines 61da177e4SLinus Torvalds * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> 71da177e4SLinus Torvalds * 89f4bd5ddSJames Courtier-Dutton * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> 99f4bd5ddSJames Courtier-Dutton * Added EMU 1010 support. 109f4bd5ddSJames Courtier-Dutton * 111da177e4SLinus Torvalds * BUGS: 121da177e4SLinus Torvalds * -- 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * TODO: 151da177e4SLinus Torvalds * -- 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 181da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 191da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 201da177e4SLinus Torvalds * (at your option) any later version. 211da177e4SLinus Torvalds * 221da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 231da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 241da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 251da177e4SLinus Torvalds * GNU General Public License for more details. 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 281da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 291da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds */ 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds #include <sound/driver.h> 341da177e4SLinus Torvalds #include <linux/time.h> 351da177e4SLinus Torvalds #include <linux/init.h> 361da177e4SLinus Torvalds #include <sound/core.h> 371da177e4SLinus Torvalds #include <sound/emu10k1.h> 38b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h> 39184c1e2cSJames Courtier-Dutton #include <sound/tlv.h> 40184c1e2cSJames Courtier-Dutton 41184c1e2cSJames Courtier-Dutton #include "p17v.h" 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds #define AC97_ID_STAC9758 0x83847658 441da177e4SLinus Torvalds 450cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ 46184c1e2cSJames Courtier-Dutton 47eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 481da177e4SLinus Torvalds { 491da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 501da177e4SLinus Torvalds uinfo->count = 1; 511da177e4SLinus Torvalds return 0; 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 54eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol, 55eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 561da177e4SLinus Torvalds { 57eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 581da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 591da177e4SLinus Torvalds unsigned long flags; 601da177e4SLinus Torvalds 6174415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 6274415a36SJames Courtier-Dutton if (idx >= 3) 6374415a36SJames Courtier-Dutton return -EINVAL; 641da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 651da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 661da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 671da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 681da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 691da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 701da177e4SLinus Torvalds return 0; 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds 73eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, 74eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = 0xff; 771da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = 0xff; 781da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = 0xff; 791da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = 0xff; 801da177e4SLinus Torvalds return 0; 811da177e4SLinus Torvalds } 821da177e4SLinus Torvalds 8313d45709SPavel Hofman /* 8413d45709SPavel Hofman * Items labels in enum mixer controls assigning source data to 8513d45709SPavel Hofman * each destination 8613d45709SPavel Hofman */ 879f4bd5ddSJames Courtier-Dutton static char *emu1010_src_texts[] = { 889f4bd5ddSJames Courtier-Dutton "Silence", 899f4bd5ddSJames Courtier-Dutton "Dock Mic A", 909f4bd5ddSJames Courtier-Dutton "Dock Mic B", 919f4bd5ddSJames Courtier-Dutton "Dock ADC1 Left", 929f4bd5ddSJames Courtier-Dutton "Dock ADC1 Right", 939f4bd5ddSJames Courtier-Dutton "Dock ADC2 Left", 949f4bd5ddSJames Courtier-Dutton "Dock ADC2 Right", 959f4bd5ddSJames Courtier-Dutton "Dock ADC3 Left", 969f4bd5ddSJames Courtier-Dutton "Dock ADC3 Right", 979f4bd5ddSJames Courtier-Dutton "0202 ADC Left", 989f4bd5ddSJames Courtier-Dutton "0202 ADC Right", 999f4bd5ddSJames Courtier-Dutton "0202 SPDIF Left", 1009f4bd5ddSJames Courtier-Dutton "0202 SPDIF Right", 1019f4bd5ddSJames Courtier-Dutton "ADAT 0", 1029f4bd5ddSJames Courtier-Dutton "ADAT 1", 1039f4bd5ddSJames Courtier-Dutton "ADAT 2", 1049f4bd5ddSJames Courtier-Dutton "ADAT 3", 1059f4bd5ddSJames Courtier-Dutton "ADAT 4", 1069f4bd5ddSJames Courtier-Dutton "ADAT 5", 1079f4bd5ddSJames Courtier-Dutton "ADAT 6", 1089f4bd5ddSJames Courtier-Dutton "ADAT 7", 1099f4bd5ddSJames Courtier-Dutton "DSP 0", 1109f4bd5ddSJames Courtier-Dutton "DSP 1", 1119f4bd5ddSJames Courtier-Dutton "DSP 2", 1129f4bd5ddSJames Courtier-Dutton "DSP 3", 1139f4bd5ddSJames Courtier-Dutton "DSP 4", 1149f4bd5ddSJames Courtier-Dutton "DSP 5", 1159f4bd5ddSJames Courtier-Dutton "DSP 6", 1169f4bd5ddSJames Courtier-Dutton "DSP 7", 1179f4bd5ddSJames Courtier-Dutton "DSP 8", 1189f4bd5ddSJames Courtier-Dutton "DSP 9", 1199f4bd5ddSJames Courtier-Dutton "DSP 10", 1209f4bd5ddSJames Courtier-Dutton "DSP 11", 1219f4bd5ddSJames Courtier-Dutton "DSP 12", 1229f4bd5ddSJames Courtier-Dutton "DSP 13", 1239f4bd5ddSJames Courtier-Dutton "DSP 14", 1249f4bd5ddSJames Courtier-Dutton "DSP 15", 1259f4bd5ddSJames Courtier-Dutton "DSP 16", 1269f4bd5ddSJames Courtier-Dutton "DSP 17", 1279f4bd5ddSJames Courtier-Dutton "DSP 18", 1289f4bd5ddSJames Courtier-Dutton "DSP 19", 1299f4bd5ddSJames Courtier-Dutton "DSP 20", 1309f4bd5ddSJames Courtier-Dutton "DSP 21", 1319f4bd5ddSJames Courtier-Dutton "DSP 22", 1329f4bd5ddSJames Courtier-Dutton "DSP 23", 1339f4bd5ddSJames Courtier-Dutton "DSP 24", 1349f4bd5ddSJames Courtier-Dutton "DSP 25", 1359f4bd5ddSJames Courtier-Dutton "DSP 26", 1369f4bd5ddSJames Courtier-Dutton "DSP 27", 1379f4bd5ddSJames Courtier-Dutton "DSP 28", 1389f4bd5ddSJames Courtier-Dutton "DSP 29", 1399f4bd5ddSJames Courtier-Dutton "DSP 30", 1409f4bd5ddSJames Courtier-Dutton "DSP 31", 1419f4bd5ddSJames Courtier-Dutton }; 1429f4bd5ddSJames Courtier-Dutton 14313d45709SPavel Hofman /* 14413d45709SPavel Hofman * List of data sources available for each destination 14513d45709SPavel Hofman */ 1469f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_src_regs[] = { 1479f4bd5ddSJames Courtier-Dutton EMU_SRC_SILENCE,/* 0 */ 1489f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_MIC_A1, /* 1 */ 1499f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_MIC_B1, /* 2 */ 1509f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */ 1519f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */ 1529f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */ 1539f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */ 1549f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */ 1559f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */ 1569f4bd5ddSJames Courtier-Dutton EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */ 1579f4bd5ddSJames Courtier-Dutton EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */ 1589f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */ 1599f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */ 1609f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT, /* 13 */ 1619f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+1, /* 14 */ 1629f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+2, /* 15 */ 1639f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+3, /* 16 */ 1649f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+4, /* 17 */ 1659f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+5, /* 18 */ 1669f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+6, /* 19 */ 1679f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+7, /* 20 */ 1689f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A, /* 21 */ 1699f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+1, /* 22 */ 1709f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+2, /* 23 */ 1719f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+3, /* 24 */ 1729f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+4, /* 25 */ 1739f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+5, /* 26 */ 1749f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+6, /* 27 */ 1759f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+7, /* 28 */ 1769f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+8, /* 29 */ 1779f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+9, /* 30 */ 1789f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xa, /* 31 */ 1799f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xb, /* 32 */ 1809f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xc, /* 33 */ 1819f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xd, /* 34 */ 1829f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xe, /* 35 */ 1839f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xf, /* 36 */ 1849f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B, /* 37 */ 1859f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+1, /* 38 */ 1869f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+2, /* 39 */ 1879f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+3, /* 40 */ 1889f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+4, /* 41 */ 1899f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+5, /* 42 */ 1909f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+6, /* 43 */ 1919f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+7, /* 44 */ 1929f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+8, /* 45 */ 1939f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+9, /* 46 */ 1949f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xa, /* 47 */ 1959f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xb, /* 48 */ 1969f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xc, /* 49 */ 1979f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xd, /* 50 */ 1989f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xe, /* 51 */ 1999f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ 2009f4bd5ddSJames Courtier-Dutton }; 2019f4bd5ddSJames Courtier-Dutton 20213d45709SPavel Hofman /* 20313d45709SPavel Hofman * Data destinations - physical EMU outputs. 20413d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 20513d45709SPavel Hofman */ 2069f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_output_dst[] = { 2079f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ 2089f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ 2099f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ 2109f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ 2119f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ 2129f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ 2139f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ 2149f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ 2159f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ 2169f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ 2179f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ 2189f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ 2199f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ 2209f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ 2219f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ 2229f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ 2239f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT, /* 16 */ 2249f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+1, /* 17 */ 2259f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+2, /* 18 */ 2269f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+3, /* 19 */ 2279f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+4, /* 20 */ 2289f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+5, /* 21 */ 2299f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+6, /* 22 */ 2309f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+7, /* 23 */ 2319f4bd5ddSJames Courtier-Dutton }; 2329f4bd5ddSJames Courtier-Dutton 23313d45709SPavel Hofman /* 23413d45709SPavel Hofman * Data destinations - HANA outputs going to Alice2 (audigy) for 23513d45709SPavel Hofman * capture (EMU32 + I2S links) 23613d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 23713d45709SPavel Hofman */ 2389f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_input_dst[] = { 2399f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_0, 2409f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_1, 2419f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_2, 2429f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_3, 2439f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_4, 2449f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_5, 2459f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_6, 2469f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_7, 2479f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_8, 2489f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_9, 2499f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_A, 2509f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_B, 2519f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_C, 2529f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_D, 2539f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_E, 2549f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_F, 2559f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_LEFT, 2569f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_RIGHT, 2579f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_LEFT, 2589f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_RIGHT, 2599f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_LEFT, 2609f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_RIGHT, 2619f4bd5ddSJames Courtier-Dutton }; 2629f4bd5ddSJames Courtier-Dutton 2639f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 2649f4bd5ddSJames Courtier-Dutton { 2659f4bd5ddSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2669f4bd5ddSJames Courtier-Dutton uinfo->count = 1; 2679f4bd5ddSJames Courtier-Dutton uinfo->value.enumerated.items = 53; 2689f4bd5ddSJames Courtier-Dutton if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 2699f4bd5ddSJames Courtier-Dutton uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 2709f4bd5ddSJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]); 2719f4bd5ddSJames Courtier-Dutton return 0; 2729f4bd5ddSJames Courtier-Dutton } 2739f4bd5ddSJames Courtier-Dutton 2749f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, 2759f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 2769f4bd5ddSJames Courtier-Dutton { 2779f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 27874415a36SJames Courtier-Dutton unsigned int channel; 2799f4bd5ddSJames Courtier-Dutton 2809f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 28174415a36SJames Courtier-Dutton /* Limit: emu1010_output_dst, emu->emu1010.output_source */ 28274415a36SJames Courtier-Dutton if (channel >= 24) 28374415a36SJames Courtier-Dutton return -EINVAL; 2849f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; 2859f4bd5ddSJames Courtier-Dutton return 0; 2869f4bd5ddSJames Courtier-Dutton } 2879f4bd5ddSJames Courtier-Dutton 2889f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, 2899f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 2909f4bd5ddSJames Courtier-Dutton { 2919f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 2929f4bd5ddSJames Courtier-Dutton int change = 0; 2939f4bd5ddSJames Courtier-Dutton unsigned int val; 29474415a36SJames Courtier-Dutton unsigned int channel; 2959f4bd5ddSJames Courtier-Dutton 296*aa299d01STakashi Iwai val = ucontrol->value.enumerated.item[0]; 297*aa299d01STakashi Iwai if (val >= 53) 298*aa299d01STakashi Iwai return -EINVAL; 2999f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 30074415a36SJames Courtier-Dutton /* Limit: emu1010_output_dst, emu->emu1010.output_source */ 30174415a36SJames Courtier-Dutton if (channel >= 24) 30274415a36SJames Courtier-Dutton return -EINVAL; 303*aa299d01STakashi Iwai if (emu->emu1010.output_source[channel] != val) { 304*aa299d01STakashi Iwai emu->emu1010.output_source[channel] = val; 3059f4bd5ddSJames Courtier-Dutton change = 1; 3069f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 3079f4bd5ddSJames Courtier-Dutton emu1010_output_dst[channel], emu1010_src_regs[val]); 3089f4bd5ddSJames Courtier-Dutton } 3099f4bd5ddSJames Courtier-Dutton return change; 3109f4bd5ddSJames Courtier-Dutton } 3119f4bd5ddSJames Courtier-Dutton 3129f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, 3139f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 3149f4bd5ddSJames Courtier-Dutton { 3159f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 31674415a36SJames Courtier-Dutton unsigned int channel; 3179f4bd5ddSJames Courtier-Dutton 3189f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 31974415a36SJames Courtier-Dutton /* Limit: emu1010_input_dst, emu->emu1010.input_source */ 32074415a36SJames Courtier-Dutton if (channel >= 22) 32174415a36SJames Courtier-Dutton return -EINVAL; 3229f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; 3239f4bd5ddSJames Courtier-Dutton return 0; 3249f4bd5ddSJames Courtier-Dutton } 3259f4bd5ddSJames Courtier-Dutton 3269f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, 3279f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 3289f4bd5ddSJames Courtier-Dutton { 3299f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 3309f4bd5ddSJames Courtier-Dutton int change = 0; 3319f4bd5ddSJames Courtier-Dutton unsigned int val; 33274415a36SJames Courtier-Dutton unsigned int channel; 3339f4bd5ddSJames Courtier-Dutton 334*aa299d01STakashi Iwai val = ucontrol->value.enumerated.item[0]; 335*aa299d01STakashi Iwai if (val >= 53) 336*aa299d01STakashi Iwai return -EINVAL; 3379f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 33874415a36SJames Courtier-Dutton /* Limit: emu1010_input_dst, emu->emu1010.input_source */ 33974415a36SJames Courtier-Dutton if (channel >= 22) 34074415a36SJames Courtier-Dutton return -EINVAL; 341*aa299d01STakashi Iwai if (emu->emu1010.input_source[channel] != val) { 342*aa299d01STakashi Iwai emu->emu1010.input_source[channel] = val; 3439f4bd5ddSJames Courtier-Dutton change = 1; 3449f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 3459f4bd5ddSJames Courtier-Dutton emu1010_input_dst[channel], emu1010_src_regs[val]); 3469f4bd5ddSJames Courtier-Dutton } 3479f4bd5ddSJames Courtier-Dutton return change; 3489f4bd5ddSJames Courtier-Dutton } 3499f4bd5ddSJames Courtier-Dutton 3509f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \ 3519f4bd5ddSJames Courtier-Dutton { \ 3529f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 3539f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 3549f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 3559f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_output_source_get, \ 3569f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_output_source_put, \ 3579f4bd5ddSJames Courtier-Dutton .private_value = chid \ 3589f4bd5ddSJames Courtier-Dutton } 3599f4bd5ddSJames Courtier-Dutton 3609f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { 3614c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), 3624c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), 3634c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), 3644c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), 3654c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), 3664c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), 3674c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6), 3684c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7), 3694c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8), 3704c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9), 3714c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa), 3724c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb), 3734c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc), 3744c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd), 3754c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe), 3764c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf), 3774c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10), 3784c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11), 3794c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12), 3804c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13), 3814c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14), 3824c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15), 3834c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16), 3844c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), 3859f4bd5ddSJames Courtier-Dutton }; 3869f4bd5ddSJames Courtier-Dutton 3879f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \ 3889f4bd5ddSJames Courtier-Dutton { \ 3899f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 3909f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 3919f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 3929f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_input_source_get, \ 3939f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_input_source_put, \ 3949f4bd5ddSJames Courtier-Dutton .private_value = chid \ 3959f4bd5ddSJames Courtier-Dutton } 3969f4bd5ddSJames Courtier-Dutton 3979f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { 3984c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), 3994c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), 4004c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), 4014c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3), 4024c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4), 4034c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5), 4044c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6), 4054c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7), 4064c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8), 4074c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9), 4084c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa), 4094c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb), 4104c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc), 4114c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd), 4124c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe), 4134c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf), 4144c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10), 4154c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11), 4164c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12), 4174c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13), 4184c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14), 4194c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15), 4209148cc50SJames Courtier-Dutton }; 4219148cc50SJames Courtier-Dutton 4229148cc50SJames Courtier-Dutton 4239148cc50SJames Courtier-Dutton 424a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info 4259148cc50SJames Courtier-Dutton 4269148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4279148cc50SJames Courtier-Dutton { 4289148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4299148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 4309148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; 4319148cc50SJames Courtier-Dutton return 0; 4329148cc50SJames Courtier-Dutton } 4339148cc50SJames Courtier-Dutton 4349148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4359148cc50SJames Courtier-Dutton { 4369148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4379148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 4389148cc50SJames Courtier-Dutton unsigned int val, cache; 4399148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 4409148cc50SJames Courtier-Dutton cache = emu->emu1010.adc_pads; 4419148cc50SJames Courtier-Dutton if (val == 1) 4429148cc50SJames Courtier-Dutton cache = cache | mask; 4439148cc50SJames Courtier-Dutton else 4449148cc50SJames Courtier-Dutton cache = cache & ~mask; 4459148cc50SJames Courtier-Dutton if (cache != emu->emu1010.adc_pads) { 4469148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); 4479148cc50SJames Courtier-Dutton emu->emu1010.adc_pads = cache; 4489148cc50SJames Courtier-Dutton } 4499148cc50SJames Courtier-Dutton 4509148cc50SJames Courtier-Dutton return 0; 4519148cc50SJames Courtier-Dutton } 4529148cc50SJames Courtier-Dutton 4539148cc50SJames Courtier-Dutton 4549148cc50SJames Courtier-Dutton 4559148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \ 4569148cc50SJames Courtier-Dutton { \ 4579148cc50SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 4589148cc50SJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 4599148cc50SJames Courtier-Dutton .info = snd_emu1010_adc_pads_info, \ 4609148cc50SJames Courtier-Dutton .get = snd_emu1010_adc_pads_get, \ 4619148cc50SJames Courtier-Dutton .put = snd_emu1010_adc_pads_put, \ 4629148cc50SJames Courtier-Dutton .private_value = chid \ 4639148cc50SJames Courtier-Dutton } 4649148cc50SJames Courtier-Dutton 4659148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = { 4669148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), 4679148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), 4689148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), 4699148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), 4709148cc50SJames Courtier-Dutton }; 4719148cc50SJames Courtier-Dutton 472a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info 4739148cc50SJames Courtier-Dutton 4749148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4759148cc50SJames Courtier-Dutton { 4769148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4779148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 4789148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; 4799148cc50SJames Courtier-Dutton return 0; 4809148cc50SJames Courtier-Dutton } 4819148cc50SJames Courtier-Dutton 4829148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4839148cc50SJames Courtier-Dutton { 4849148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4859148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 4869148cc50SJames Courtier-Dutton unsigned int val, cache; 4879148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 4889148cc50SJames Courtier-Dutton cache = emu->emu1010.dac_pads; 4899148cc50SJames Courtier-Dutton if (val == 1) 4909148cc50SJames Courtier-Dutton cache = cache | mask; 4919148cc50SJames Courtier-Dutton else 4929148cc50SJames Courtier-Dutton cache = cache & ~mask; 4939148cc50SJames Courtier-Dutton if (cache != emu->emu1010.dac_pads) { 4949148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); 4959148cc50SJames Courtier-Dutton emu->emu1010.dac_pads = cache; 4969148cc50SJames Courtier-Dutton } 4979148cc50SJames Courtier-Dutton 4989148cc50SJames Courtier-Dutton return 0; 4999148cc50SJames Courtier-Dutton } 5009148cc50SJames Courtier-Dutton 5019148cc50SJames Courtier-Dutton 5029148cc50SJames Courtier-Dutton 5039148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \ 5049148cc50SJames Courtier-Dutton { \ 5059148cc50SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 5069148cc50SJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 5079148cc50SJames Courtier-Dutton .info = snd_emu1010_dac_pads_info, \ 5089148cc50SJames Courtier-Dutton .get = snd_emu1010_dac_pads_get, \ 5099148cc50SJames Courtier-Dutton .put = snd_emu1010_dac_pads_put, \ 5109148cc50SJames Courtier-Dutton .private_value = chid \ 5119148cc50SJames Courtier-Dutton } 5129148cc50SJames Courtier-Dutton 5139148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = { 5149148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), 5159148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), 5169148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), 5179148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4), 5189148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), 5199f4bd5ddSJames Courtier-Dutton }; 5209f4bd5ddSJames Courtier-Dutton 521b0dbdaeaSJames Courtier-Dutton 522b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, 523b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 524b0dbdaeaSJames Courtier-Dutton { 525edec7bbbSJames Courtier-Dutton static char *texts[4] = { 526edec7bbbSJames Courtier-Dutton "44100", "48000", "SPDIF", "ADAT" 527b0dbdaeaSJames Courtier-Dutton }; 528b0dbdaeaSJames Courtier-Dutton 529b0dbdaeaSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 530b0dbdaeaSJames Courtier-Dutton uinfo->count = 1; 531edec7bbbSJames Courtier-Dutton uinfo->value.enumerated.items = 4; 532edec7bbbSJames Courtier-Dutton if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 533edec7bbbSJames Courtier-Dutton uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 534b0dbdaeaSJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 535b0dbdaeaSJames Courtier-Dutton return 0; 536edec7bbbSJames Courtier-Dutton 537edec7bbbSJames Courtier-Dutton 538b0dbdaeaSJames Courtier-Dutton } 539b0dbdaeaSJames Courtier-Dutton 540b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, 541b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 542b0dbdaeaSJames Courtier-Dutton { 543b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 544b0dbdaeaSJames Courtier-Dutton 545b0dbdaeaSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; 546b0dbdaeaSJames Courtier-Dutton return 0; 547b0dbdaeaSJames Courtier-Dutton } 548b0dbdaeaSJames Courtier-Dutton 549b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, 550b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 551b0dbdaeaSJames Courtier-Dutton { 552b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 553b0dbdaeaSJames Courtier-Dutton unsigned int val; 554b0dbdaeaSJames Courtier-Dutton int change = 0; 555b0dbdaeaSJames Courtier-Dutton 556b0dbdaeaSJames Courtier-Dutton val = ucontrol->value.enumerated.item[0] ; 55774415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 4; */ 55874415a36SJames Courtier-Dutton if (val >= 4) 55974415a36SJames Courtier-Dutton return -EINVAL; 560b0dbdaeaSJames Courtier-Dutton change = (emu->emu1010.internal_clock != val); 561b0dbdaeaSJames Courtier-Dutton if (change) { 562b0dbdaeaSJames Courtier-Dutton emu->emu1010.internal_clock = val; 563b0dbdaeaSJames Courtier-Dutton switch (val) { 564b0dbdaeaSJames Courtier-Dutton case 0: 565b0dbdaeaSJames Courtier-Dutton /* 44100 */ 566b0dbdaeaSJames Courtier-Dutton /* Mute all */ 567b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 568b0dbdaeaSJames Courtier-Dutton /* Default fallback clock 48kHz */ 569b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); 570b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 44.1kHz x1 */ 571b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 572b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); 573b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 574b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 575b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); 576b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 577e40a0b2eSJames Courtier-Dutton msleep(10); 578b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 579b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 580b0dbdaeaSJames Courtier-Dutton break; 581b0dbdaeaSJames Courtier-Dutton case 1: 582b0dbdaeaSJames Courtier-Dutton /* 48000 */ 583b0dbdaeaSJames Courtier-Dutton /* Mute all */ 584b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 585b0dbdaeaSJames Courtier-Dutton /* Default fallback clock 48kHz */ 586b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 587b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 48kHz x1 */ 588b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 589b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); 590b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 591b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 592b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); 593b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 594e40a0b2eSJames Courtier-Dutton msleep(10); 595b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 596b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 597b0dbdaeaSJames Courtier-Dutton break; 598edec7bbbSJames Courtier-Dutton 599edec7bbbSJames Courtier-Dutton case 2: /* Take clock from S/PDIF IN */ 600edec7bbbSJames Courtier-Dutton /* Mute all */ 601edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 602edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 603edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 604edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to S/PDIF input */ 605edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 606edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); 607edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 608edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 609edec7bbbSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 610edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 611edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 612edec7bbbSJames Courtier-Dutton msleep(10); 613edec7bbbSJames Courtier-Dutton /* Unmute all */ 614edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 615edec7bbbSJames Courtier-Dutton break; 616edec7bbbSJames Courtier-Dutton 617edec7bbbSJames Courtier-Dutton case 3: 618edec7bbbSJames Courtier-Dutton /* Take clock from ADAT IN */ 619edec7bbbSJames Courtier-Dutton /* Mute all */ 620edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 621edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 622edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 623edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to ADAT input */ 624edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 625edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); 626edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 627edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 628edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 629edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 630edec7bbbSJames Courtier-Dutton msleep(10); 631edec7bbbSJames Courtier-Dutton /* Unmute all */ 632edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 633edec7bbbSJames Courtier-Dutton 634edec7bbbSJames Courtier-Dutton 635edec7bbbSJames Courtier-Dutton break; 636b0dbdaeaSJames Courtier-Dutton } 637b0dbdaeaSJames Courtier-Dutton } 638b0dbdaeaSJames Courtier-Dutton return change; 639b0dbdaeaSJames Courtier-Dutton } 640b0dbdaeaSJames Courtier-Dutton 641b0dbdaeaSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_internal_clock = 642b0dbdaeaSJames Courtier-Dutton { 643b0dbdaeaSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 644b0dbdaeaSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 645b0dbdaeaSJames Courtier-Dutton .name = "Clock Internal Rate", 646b0dbdaeaSJames Courtier-Dutton .count = 1, 647b0dbdaeaSJames Courtier-Dutton .info = snd_emu1010_internal_clock_info, 648b0dbdaeaSJames Courtier-Dutton .get = snd_emu1010_internal_clock_get, 649b0dbdaeaSJames Courtier-Dutton .put = snd_emu1010_internal_clock_put 650b0dbdaeaSJames Courtier-Dutton }; 651b0dbdaeaSJames Courtier-Dutton 652184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, 653184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 654184c1e2cSJames Courtier-Dutton { 655184c1e2cSJames Courtier-Dutton #if 0 656184c1e2cSJames Courtier-Dutton static char *texts[4] = { 657184c1e2cSJames Courtier-Dutton "Unknown1", "Unknown2", "Mic", "Line" 658184c1e2cSJames Courtier-Dutton }; 659184c1e2cSJames Courtier-Dutton #endif 660184c1e2cSJames Courtier-Dutton static char *texts[2] = { 661184c1e2cSJames Courtier-Dutton "Mic", "Line" 662184c1e2cSJames Courtier-Dutton }; 663184c1e2cSJames Courtier-Dutton 664184c1e2cSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 665184c1e2cSJames Courtier-Dutton uinfo->count = 1; 666184c1e2cSJames Courtier-Dutton uinfo->value.enumerated.items = 2; 667184c1e2cSJames Courtier-Dutton if (uinfo->value.enumerated.item > 1) 668184c1e2cSJames Courtier-Dutton uinfo->value.enumerated.item = 1; 669184c1e2cSJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 670184c1e2cSJames Courtier-Dutton return 0; 671184c1e2cSJames Courtier-Dutton } 672184c1e2cSJames Courtier-Dutton 673184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, 674184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 675184c1e2cSJames Courtier-Dutton { 676184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 677184c1e2cSJames Courtier-Dutton 678184c1e2cSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; 679184c1e2cSJames Courtier-Dutton return 0; 680184c1e2cSJames Courtier-Dutton } 681184c1e2cSJames Courtier-Dutton 682184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, 683184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 684184c1e2cSJames Courtier-Dutton { 685184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 686184c1e2cSJames Courtier-Dutton unsigned int source_id; 687184c1e2cSJames Courtier-Dutton unsigned int ngain, ogain; 688184c1e2cSJames Courtier-Dutton u32 gpio; 689184c1e2cSJames Courtier-Dutton int change = 0; 690184c1e2cSJames Courtier-Dutton unsigned long flags; 691184c1e2cSJames Courtier-Dutton u32 source; 692184c1e2cSJames Courtier-Dutton /* If the capture source has changed, 693184c1e2cSJames Courtier-Dutton * update the capture volume from the cached value 694184c1e2cSJames Courtier-Dutton * for the particular source. 695184c1e2cSJames Courtier-Dutton */ 69674415a36SJames Courtier-Dutton source_id = ucontrol->value.enumerated.item[0]; 69774415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 2; */ 69874415a36SJames Courtier-Dutton /* emu->i2c_capture_volume */ 69974415a36SJames Courtier-Dutton if (source_id >= 2) 70074415a36SJames Courtier-Dutton return -EINVAL; 701184c1e2cSJames Courtier-Dutton change = (emu->i2c_capture_source != source_id); 702184c1e2cSJames Courtier-Dutton if (change) { 703184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 704184c1e2cSJames Courtier-Dutton spin_lock_irqsave(&emu->emu_lock, flags); 705184c1e2cSJames Courtier-Dutton gpio = inl(emu->port + A_IOCFG); 706184c1e2cSJames Courtier-Dutton if (source_id==0) 707184c1e2cSJames Courtier-Dutton outl(gpio | 0x4, emu->port + A_IOCFG); 708184c1e2cSJames Courtier-Dutton else 709184c1e2cSJames Courtier-Dutton outl(gpio & ~0x4, emu->port + A_IOCFG); 710184c1e2cSJames Courtier-Dutton spin_unlock_irqrestore(&emu->emu_lock, flags); 711184c1e2cSJames Courtier-Dutton 712184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ 713184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ 714184c1e2cSJames Courtier-Dutton if (ngain != ogain) 715184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); 716184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ 717184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ 718184c1e2cSJames Courtier-Dutton if (ngain != ogain) 719184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 720184c1e2cSJames Courtier-Dutton 721184c1e2cSJames Courtier-Dutton source = 1 << (source_id + 2); 722184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ 723184c1e2cSJames Courtier-Dutton emu->i2c_capture_source = source_id; 724184c1e2cSJames Courtier-Dutton } 725184c1e2cSJames Courtier-Dutton return change; 726184c1e2cSJames Courtier-Dutton } 727184c1e2cSJames Courtier-Dutton 728184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_capture_source = 729184c1e2cSJames Courtier-Dutton { 730184c1e2cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 731184c1e2cSJames Courtier-Dutton .name = "Capture Source", 732184c1e2cSJames Courtier-Dutton .info = snd_audigy_i2c_capture_source_info, 733184c1e2cSJames Courtier-Dutton .get = snd_audigy_i2c_capture_source_get, 734184c1e2cSJames Courtier-Dutton .put = snd_audigy_i2c_capture_source_put 735184c1e2cSJames Courtier-Dutton }; 736184c1e2cSJames Courtier-Dutton 737184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, 738184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 739184c1e2cSJames Courtier-Dutton { 740184c1e2cSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 741184c1e2cSJames Courtier-Dutton uinfo->count = 2; 742184c1e2cSJames Courtier-Dutton uinfo->value.integer.min = 0; 743184c1e2cSJames Courtier-Dutton uinfo->value.integer.max = 255; 744184c1e2cSJames Courtier-Dutton return 0; 745184c1e2cSJames Courtier-Dutton } 746184c1e2cSJames Courtier-Dutton 747184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, 748184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 749184c1e2cSJames Courtier-Dutton { 750184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 75174415a36SJames Courtier-Dutton unsigned int source_id; 752184c1e2cSJames Courtier-Dutton 753184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 75474415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 75574415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 75674415a36SJames Courtier-Dutton if (source_id >= 2) 75774415a36SJames Courtier-Dutton return -EINVAL; 758184c1e2cSJames Courtier-Dutton 759184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; 760184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; 761184c1e2cSJames Courtier-Dutton return 0; 762184c1e2cSJames Courtier-Dutton } 763184c1e2cSJames Courtier-Dutton 764184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, 765184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 766184c1e2cSJames Courtier-Dutton { 767184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 768184c1e2cSJames Courtier-Dutton unsigned int ogain; 769184c1e2cSJames Courtier-Dutton unsigned int ngain; 77074415a36SJames Courtier-Dutton unsigned int source_id; 771184c1e2cSJames Courtier-Dutton int change = 0; 772184c1e2cSJames Courtier-Dutton 773184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 77474415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 77574415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 77674415a36SJames Courtier-Dutton if (source_id >= 2) 77774415a36SJames Courtier-Dutton return -EINVAL; 778184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ 779184c1e2cSJames Courtier-Dutton ngain = ucontrol->value.integer.value[0]; 780184c1e2cSJames Courtier-Dutton if (ngain > 0xff) 781184c1e2cSJames Courtier-Dutton return 0; 782184c1e2cSJames Courtier-Dutton if (ogain != ngain) { 783184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 784184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); 78574415a36SJames Courtier-Dutton emu->i2c_capture_volume[source_id][0] = ngain; 786184c1e2cSJames Courtier-Dutton change = 1; 787184c1e2cSJames Courtier-Dutton } 788184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ 789184c1e2cSJames Courtier-Dutton ngain = ucontrol->value.integer.value[1]; 790184c1e2cSJames Courtier-Dutton if (ngain > 0xff) 791184c1e2cSJames Courtier-Dutton return 0; 792184c1e2cSJames Courtier-Dutton if (ogain != ngain) { 793184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 794184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 79574415a36SJames Courtier-Dutton emu->i2c_capture_volume[source_id][1] = ngain; 796184c1e2cSJames Courtier-Dutton change = 1; 797184c1e2cSJames Courtier-Dutton } 798184c1e2cSJames Courtier-Dutton 799184c1e2cSJames Courtier-Dutton return change; 800184c1e2cSJames Courtier-Dutton } 801184c1e2cSJames Courtier-Dutton 802184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \ 803184c1e2cSJames Courtier-Dutton { \ 804184c1e2cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 805184c1e2cSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 806184c1e2cSJames Courtier-Dutton SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 807184c1e2cSJames Courtier-Dutton .info = snd_audigy_i2c_volume_info, \ 808184c1e2cSJames Courtier-Dutton .get = snd_audigy_i2c_volume_get, \ 809184c1e2cSJames Courtier-Dutton .put = snd_audigy_i2c_volume_put, \ 810184c1e2cSJames Courtier-Dutton .tlv = { .p = snd_audigy_db_scale2 }, \ 811184c1e2cSJames Courtier-Dutton .private_value = chid \ 812184c1e2cSJames Courtier-Dutton } 813184c1e2cSJames Courtier-Dutton 814184c1e2cSJames Courtier-Dutton 815184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = { 816184c1e2cSJames Courtier-Dutton I2C_VOLUME("Mic Capture Volume", 0), 817184c1e2cSJames Courtier-Dutton I2C_VOLUME("Line Capture Volume", 0) 818184c1e2cSJames Courtier-Dutton }; 819184c1e2cSJames Courtier-Dutton 8200af68e5eSTakashi Iwai #if 0 821eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 8221da177e4SLinus Torvalds { 8231da177e4SLinus Torvalds static char *texts[] = {"44100", "48000", "96000"}; 8241da177e4SLinus Torvalds 8251da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 8261da177e4SLinus Torvalds uinfo->count = 1; 8271da177e4SLinus Torvalds uinfo->value.enumerated.items = 3; 8281da177e4SLinus Torvalds if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 8291da177e4SLinus Torvalds uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 8301da177e4SLinus Torvalds strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 8311da177e4SLinus Torvalds return 0; 8321da177e4SLinus Torvalds } 8331da177e4SLinus Torvalds 834eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, 835eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 8361da177e4SLinus Torvalds { 837eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 8381da177e4SLinus Torvalds unsigned int tmp; 8391da177e4SLinus Torvalds unsigned long flags; 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds 8421da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 8431da177e4SLinus Torvalds tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 8441da177e4SLinus Torvalds switch (tmp & A_SPDIF_RATE_MASK) { 8451da177e4SLinus Torvalds case A_SPDIF_44100: 8461da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 8471da177e4SLinus Torvalds break; 8481da177e4SLinus Torvalds case A_SPDIF_48000: 8491da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 8501da177e4SLinus Torvalds break; 8511da177e4SLinus Torvalds case A_SPDIF_96000: 8521da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 8531da177e4SLinus Torvalds break; 8541da177e4SLinus Torvalds default: 8551da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 8561da177e4SLinus Torvalds } 8571da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 8581da177e4SLinus Torvalds return 0; 8591da177e4SLinus Torvalds } 8601da177e4SLinus Torvalds 861eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, 862eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 8631da177e4SLinus Torvalds { 864eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 8651da177e4SLinus Torvalds int change; 8661da177e4SLinus Torvalds unsigned int reg, val, tmp; 8671da177e4SLinus Torvalds unsigned long flags; 8681da177e4SLinus Torvalds 8691da177e4SLinus Torvalds switch(ucontrol->value.enumerated.item[0]) { 8701da177e4SLinus Torvalds case 0: 8711da177e4SLinus Torvalds val = A_SPDIF_44100; 8721da177e4SLinus Torvalds break; 8731da177e4SLinus Torvalds case 1: 8741da177e4SLinus Torvalds val = A_SPDIF_48000; 8751da177e4SLinus Torvalds break; 8761da177e4SLinus Torvalds case 2: 8771da177e4SLinus Torvalds val = A_SPDIF_96000; 8781da177e4SLinus Torvalds break; 8791da177e4SLinus Torvalds default: 8801da177e4SLinus Torvalds val = A_SPDIF_48000; 8811da177e4SLinus Torvalds break; 8821da177e4SLinus Torvalds } 8831da177e4SLinus Torvalds 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 8861da177e4SLinus Torvalds reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 8871da177e4SLinus Torvalds tmp = reg & ~A_SPDIF_RATE_MASK; 8881da177e4SLinus Torvalds tmp |= val; 8891da177e4SLinus Torvalds if ((change = (tmp != reg))) 8901da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); 8911da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 8921da177e4SLinus Torvalds return change; 8931da177e4SLinus Torvalds } 8941da177e4SLinus Torvalds 895eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_spdif_output_rate = 8961da177e4SLinus Torvalds { 8971da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8981da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8991da177e4SLinus Torvalds .name = "Audigy SPDIF Output Sample Rate", 9001da177e4SLinus Torvalds .count = 1, 9011da177e4SLinus Torvalds .info = snd_audigy_spdif_output_rate_info, 9021da177e4SLinus Torvalds .get = snd_audigy_spdif_output_rate_get, 9031da177e4SLinus Torvalds .put = snd_audigy_spdif_output_rate_put 9041da177e4SLinus Torvalds }; 9050af68e5eSTakashi Iwai #endif 9061da177e4SLinus Torvalds 907eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, 908eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9091da177e4SLinus Torvalds { 910eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9111da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 9121da177e4SLinus Torvalds int change; 9131da177e4SLinus Torvalds unsigned int val; 9141da177e4SLinus Torvalds unsigned long flags; 9151da177e4SLinus Torvalds 91674415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 91774415a36SJames Courtier-Dutton if (idx >= 3) 91874415a36SJames Courtier-Dutton return -EINVAL; 9191da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 9201da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 9211da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 9221da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 9231da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 9241da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 9251da177e4SLinus Torvalds if (change) { 9261da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); 9271da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 9281da177e4SLinus Torvalds } 9291da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 9301da177e4SLinus Torvalds return change; 9311da177e4SLinus Torvalds } 9321da177e4SLinus Torvalds 933eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = 9341da177e4SLinus Torvalds { 9351da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 9365549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 9371da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 9387583cb51STakashi Iwai .count = 3, 9391da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 9401da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get_mask 9411da177e4SLinus Torvalds }; 9421da177e4SLinus Torvalds 943eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_control = 9441da177e4SLinus Torvalds { 9455549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 9461da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 9477583cb51STakashi Iwai .count = 3, 9481da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 9491da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get, 9501da177e4SLinus Torvalds .put = snd_emu10k1_spdif_put 9511da177e4SLinus Torvalds }; 9521da177e4SLinus Torvalds 9531da177e4SLinus Torvalds 954eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route) 9551da177e4SLinus Torvalds { 9561da177e4SLinus Torvalds if (emu->audigy) { 9571da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT1, voice, 9581da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt1(route)); 9591da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 9601da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt2(route)); 9611da177e4SLinus Torvalds } else { 9621da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXRT, voice, 9631da177e4SLinus Torvalds snd_emu10k1_compose_send_routing(route)); 9641da177e4SLinus Torvalds } 9651da177e4SLinus Torvalds } 9661da177e4SLinus Torvalds 967eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume) 9681da177e4SLinus Torvalds { 9691da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); 9701da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); 9711da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); 9721da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); 9731da177e4SLinus Torvalds if (emu->audigy) { 9741da177e4SLinus Torvalds unsigned int val = ((unsigned int)volume[4] << 24) | 9751da177e4SLinus Torvalds ((unsigned int)volume[5] << 16) | 9761da177e4SLinus Torvalds ((unsigned int)volume[6] << 8) | 9771da177e4SLinus Torvalds (unsigned int)volume[7]; 9781da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val); 9791da177e4SLinus Torvalds } 9801da177e4SLinus Torvalds } 9811da177e4SLinus Torvalds 9821da177e4SLinus Torvalds /* PCM stream controls */ 9831da177e4SLinus Torvalds 984eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 9851da177e4SLinus Torvalds { 986eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9871da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 9881da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 9891da177e4SLinus Torvalds uinfo->value.integer.min = 0; 9901da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 9911da177e4SLinus Torvalds return 0; 9921da177e4SLinus Torvalds } 9931da177e4SLinus Torvalds 994eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, 995eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9961da177e4SLinus Torvalds { 9971da177e4SLinus Torvalds unsigned long flags; 998eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 999eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1000eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 10011da177e4SLinus Torvalds int voice, idx; 10021da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 10031da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 10041da177e4SLinus Torvalds 10051da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 10061da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 10071da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 10081da177e4SLinus Torvalds ucontrol->value.integer.value[(voice * num_efx) + idx] = 10091da177e4SLinus Torvalds mix->send_routing[voice][idx] & mask; 10101da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 10111da177e4SLinus Torvalds return 0; 10121da177e4SLinus Torvalds } 10131da177e4SLinus Torvalds 1014eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, 1015eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10161da177e4SLinus Torvalds { 10171da177e4SLinus Torvalds unsigned long flags; 1018eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1019eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1020eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 10211da177e4SLinus Torvalds int change = 0, voice, idx, val; 10221da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 10231da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 10241da177e4SLinus Torvalds 10251da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 10261da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 10271da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 10281da177e4SLinus Torvalds val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; 10291da177e4SLinus Torvalds if (mix->send_routing[voice][idx] != val) { 10301da177e4SLinus Torvalds mix->send_routing[voice][idx] = val; 10311da177e4SLinus Torvalds change = 1; 10321da177e4SLinus Torvalds } 10331da177e4SLinus Torvalds } 10341da177e4SLinus Torvalds if (change && mix->epcm) { 10351da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 10361da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 10371da177e4SLinus Torvalds &mix->send_routing[1][0]); 10381da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, 10391da177e4SLinus Torvalds &mix->send_routing[2][0]); 10401da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 10411da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 10421da177e4SLinus Torvalds &mix->send_routing[0][0]); 10431da177e4SLinus Torvalds } 10441da177e4SLinus Torvalds } 10451da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 10461da177e4SLinus Torvalds return change; 10471da177e4SLinus Torvalds } 10481da177e4SLinus Torvalds 1049eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_routing_control = 10501da177e4SLinus Torvalds { 10511da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 105267ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10531da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Routing", 10541da177e4SLinus Torvalds .count = 32, 10551da177e4SLinus Torvalds .info = snd_emu10k1_send_routing_info, 10561da177e4SLinus Torvalds .get = snd_emu10k1_send_routing_get, 10571da177e4SLinus Torvalds .put = snd_emu10k1_send_routing_put 10581da177e4SLinus Torvalds }; 10591da177e4SLinus Torvalds 1060eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 10611da177e4SLinus Torvalds { 1062eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10631da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 10641da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 10651da177e4SLinus Torvalds uinfo->value.integer.min = 0; 10661da177e4SLinus Torvalds uinfo->value.integer.max = 255; 10671da177e4SLinus Torvalds return 0; 10681da177e4SLinus Torvalds } 10691da177e4SLinus Torvalds 1070eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, 1071eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10721da177e4SLinus Torvalds { 10731da177e4SLinus Torvalds unsigned long flags; 1074eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1075eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1076eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 10771da177e4SLinus Torvalds int idx; 10781da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 10791da177e4SLinus Torvalds 10801da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 10811da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) 10821da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; 10831da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 10841da177e4SLinus Torvalds return 0; 10851da177e4SLinus Torvalds } 10861da177e4SLinus Torvalds 1087eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, 1088eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10891da177e4SLinus Torvalds { 10901da177e4SLinus Torvalds unsigned long flags; 1091eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1092eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1093eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 10941da177e4SLinus Torvalds int change = 0, idx, val; 10951da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 10981da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) { 10991da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 11001da177e4SLinus Torvalds if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { 11011da177e4SLinus Torvalds mix->send_volume[idx/num_efx][idx%num_efx] = val; 11021da177e4SLinus Torvalds change = 1; 11031da177e4SLinus Torvalds } 11041da177e4SLinus Torvalds } 11051da177e4SLinus Torvalds if (change && mix->epcm) { 11061da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 11071da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 11081da177e4SLinus Torvalds &mix->send_volume[1][0]); 11091da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, 11101da177e4SLinus Torvalds &mix->send_volume[2][0]); 11111da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 11121da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 11131da177e4SLinus Torvalds &mix->send_volume[0][0]); 11141da177e4SLinus Torvalds } 11151da177e4SLinus Torvalds } 11161da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11171da177e4SLinus Torvalds return change; 11181da177e4SLinus Torvalds } 11191da177e4SLinus Torvalds 1120eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_volume_control = 11211da177e4SLinus Torvalds { 11221da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 112367ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 11241da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Volume", 11251da177e4SLinus Torvalds .count = 32, 11261da177e4SLinus Torvalds .info = snd_emu10k1_send_volume_info, 11271da177e4SLinus Torvalds .get = snd_emu10k1_send_volume_get, 11281da177e4SLinus Torvalds .put = snd_emu10k1_send_volume_put 11291da177e4SLinus Torvalds }; 11301da177e4SLinus Torvalds 1131eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 11321da177e4SLinus Torvalds { 11331da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 11341da177e4SLinus Torvalds uinfo->count = 3; 11351da177e4SLinus Torvalds uinfo->value.integer.min = 0; 11361da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 11371da177e4SLinus Torvalds return 0; 11381da177e4SLinus Torvalds } 11391da177e4SLinus Torvalds 1140eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, 1141eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11421da177e4SLinus Torvalds { 1143eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1144eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1145eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 11461da177e4SLinus Torvalds unsigned long flags; 11471da177e4SLinus Torvalds int idx; 11481da177e4SLinus Torvalds 11491da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11501da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) 11511da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->attn[idx]; 11521da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11531da177e4SLinus Torvalds return 0; 11541da177e4SLinus Torvalds } 11551da177e4SLinus Torvalds 1156eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, 1157eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11581da177e4SLinus Torvalds { 11591da177e4SLinus Torvalds unsigned long flags; 1160eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1161eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1162eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 11631da177e4SLinus Torvalds int change = 0, idx, val; 11641da177e4SLinus Torvalds 11651da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11661da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) { 11671da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 0xffff; 11681da177e4SLinus Torvalds if (mix->attn[idx] != val) { 11691da177e4SLinus Torvalds mix->attn[idx] = val; 11701da177e4SLinus Torvalds change = 1; 11711da177e4SLinus Torvalds } 11721da177e4SLinus Torvalds } 11731da177e4SLinus Torvalds if (change && mix->epcm) { 11741da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 11751da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); 11761da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); 11771da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 11781da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); 11791da177e4SLinus Torvalds } 11801da177e4SLinus Torvalds } 11811da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11821da177e4SLinus Torvalds return change; 11831da177e4SLinus Torvalds } 11841da177e4SLinus Torvalds 1185eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_attn_control = 11861da177e4SLinus Torvalds { 11871da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 118867ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 11891da177e4SLinus Torvalds .name = "EMU10K1 PCM Volume", 11901da177e4SLinus Torvalds .count = 32, 11911da177e4SLinus Torvalds .info = snd_emu10k1_attn_info, 11921da177e4SLinus Torvalds .get = snd_emu10k1_attn_get, 11931da177e4SLinus Torvalds .put = snd_emu10k1_attn_put 11941da177e4SLinus Torvalds }; 11951da177e4SLinus Torvalds 11961da177e4SLinus Torvalds /* Mutichannel PCM stream controls */ 11971da177e4SLinus Torvalds 1198eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 11991da177e4SLinus Torvalds { 1200eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 12011da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 12021da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 12031da177e4SLinus Torvalds uinfo->value.integer.min = 0; 12041da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 12051da177e4SLinus Torvalds return 0; 12061da177e4SLinus Torvalds } 12071da177e4SLinus Torvalds 1208eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, 1209eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12101da177e4SLinus Torvalds { 12111da177e4SLinus Torvalds unsigned long flags; 1212eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1213eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1214eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12151da177e4SLinus Torvalds int idx; 12161da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12171da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 12181da177e4SLinus Torvalds 12191da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12201da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 12211da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = 12221da177e4SLinus Torvalds mix->send_routing[0][idx] & mask; 12231da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 12241da177e4SLinus Torvalds return 0; 12251da177e4SLinus Torvalds } 12261da177e4SLinus Torvalds 1227eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, 1228eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12291da177e4SLinus Torvalds { 12301da177e4SLinus Torvalds unsigned long flags; 1231eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 12321da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1233eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 12341da177e4SLinus Torvalds int change = 0, idx, val; 12351da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12361da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 12371da177e4SLinus Torvalds 12381da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12391da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 12401da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & mask; 12411da177e4SLinus Torvalds if (mix->send_routing[0][idx] != val) { 12421da177e4SLinus Torvalds mix->send_routing[0][idx] = val; 12431da177e4SLinus Torvalds change = 1; 12441da177e4SLinus Torvalds } 12451da177e4SLinus Torvalds } 12461da177e4SLinus Torvalds 12471da177e4SLinus Torvalds if (change && mix->epcm) { 12481da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 12491da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, 12501da177e4SLinus Torvalds &mix->send_routing[0][0]); 12511da177e4SLinus Torvalds } 12521da177e4SLinus Torvalds } 12531da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 12541da177e4SLinus Torvalds return change; 12551da177e4SLinus Torvalds } 12561da177e4SLinus Torvalds 1257eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = 12581da177e4SLinus Torvalds { 12591da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 12601da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 12611da177e4SLinus Torvalds .name = "Multichannel PCM Send Routing", 12621da177e4SLinus Torvalds .count = 16, 12631da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_routing_info, 12641da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_routing_get, 12651da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_routing_put 12661da177e4SLinus Torvalds }; 12671da177e4SLinus Torvalds 1268eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 12691da177e4SLinus Torvalds { 1270eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 12711da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 12721da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 12731da177e4SLinus Torvalds uinfo->value.integer.min = 0; 12741da177e4SLinus Torvalds uinfo->value.integer.max = 255; 12751da177e4SLinus Torvalds return 0; 12761da177e4SLinus Torvalds } 12771da177e4SLinus Torvalds 1278eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, 1279eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12801da177e4SLinus Torvalds { 12811da177e4SLinus Torvalds unsigned long flags; 1282eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1283eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1284eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12851da177e4SLinus Torvalds int idx; 12861da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12871da177e4SLinus Torvalds 12881da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12891da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 12901da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; 12911da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 12921da177e4SLinus Torvalds return 0; 12931da177e4SLinus Torvalds } 12941da177e4SLinus Torvalds 1295eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, 1296eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12971da177e4SLinus Torvalds { 12981da177e4SLinus Torvalds unsigned long flags; 1299eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13001da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1301eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 13021da177e4SLinus Torvalds int change = 0, idx, val; 13031da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13041da177e4SLinus Torvalds 13051da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13061da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 13071da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 13081da177e4SLinus Torvalds if (mix->send_volume[0][idx] != val) { 13091da177e4SLinus Torvalds mix->send_volume[0][idx] = val; 13101da177e4SLinus Torvalds change = 1; 13111da177e4SLinus Torvalds } 13121da177e4SLinus Torvalds } 13131da177e4SLinus Torvalds if (change && mix->epcm) { 13141da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 13151da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, 13161da177e4SLinus Torvalds &mix->send_volume[0][0]); 13171da177e4SLinus Torvalds } 13181da177e4SLinus Torvalds } 13191da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13201da177e4SLinus Torvalds return change; 13211da177e4SLinus Torvalds } 13221da177e4SLinus Torvalds 13231da177e4SLinus Torvalds 1324eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = 13251da177e4SLinus Torvalds { 13261da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 13271da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 13281da177e4SLinus Torvalds .name = "Multichannel PCM Send Volume", 13291da177e4SLinus Torvalds .count = 16, 13301da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_volume_info, 13311da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_volume_get, 13321da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_volume_put 13331da177e4SLinus Torvalds }; 13341da177e4SLinus Torvalds 1335eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13361da177e4SLinus Torvalds { 13371da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13381da177e4SLinus Torvalds uinfo->count = 1; 13391da177e4SLinus Torvalds uinfo->value.integer.min = 0; 13401da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 13411da177e4SLinus Torvalds return 0; 13421da177e4SLinus Torvalds } 13431da177e4SLinus Torvalds 1344eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, 1345eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13461da177e4SLinus Torvalds { 1347eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1348eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1349eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13501da177e4SLinus Torvalds unsigned long flags; 13511da177e4SLinus Torvalds 13521da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13531da177e4SLinus Torvalds ucontrol->value.integer.value[0] = mix->attn[0]; 13541da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13551da177e4SLinus Torvalds return 0; 13561da177e4SLinus Torvalds } 13571da177e4SLinus Torvalds 1358eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, 1359eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13601da177e4SLinus Torvalds { 13611da177e4SLinus Torvalds unsigned long flags; 1362eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13631da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1364eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 13651da177e4SLinus Torvalds int change = 0, val; 13661da177e4SLinus Torvalds 13671da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13681da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] & 0xffff; 13691da177e4SLinus Torvalds if (mix->attn[0] != val) { 13701da177e4SLinus Torvalds mix->attn[0] = val; 13711da177e4SLinus Torvalds change = 1; 13721da177e4SLinus Torvalds } 13731da177e4SLinus Torvalds if (change && mix->epcm) { 13741da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 13751da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); 13761da177e4SLinus Torvalds } 13771da177e4SLinus Torvalds } 13781da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13791da177e4SLinus Torvalds return change; 13801da177e4SLinus Torvalds } 13811da177e4SLinus Torvalds 1382eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_attn_control = 13831da177e4SLinus Torvalds { 13841da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 13851da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 13861da177e4SLinus Torvalds .name = "Multichannel PCM Volume", 13871da177e4SLinus Torvalds .count = 16, 13881da177e4SLinus Torvalds .info = snd_emu10k1_efx_attn_info, 13891da177e4SLinus Torvalds .get = snd_emu10k1_efx_attn_get, 13901da177e4SLinus Torvalds .put = snd_emu10k1_efx_attn_put 13911da177e4SLinus Torvalds }; 13921da177e4SLinus Torvalds 1393a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info snd_ctl_boolean_mono_info 13941da177e4SLinus Torvalds 1395eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, 1396eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13971da177e4SLinus Torvalds { 1398eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13991da177e4SLinus Torvalds 14001da177e4SLinus Torvalds if (emu->audigy) 14011da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; 14021da177e4SLinus Torvalds else 14031da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; 14041da177e4SLinus Torvalds return 0; 14051da177e4SLinus Torvalds } 14061da177e4SLinus Torvalds 1407eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, 1408eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14091da177e4SLinus Torvalds { 14101da177e4SLinus Torvalds unsigned long flags; 1411eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14121da177e4SLinus Torvalds unsigned int reg, val; 14131da177e4SLinus Torvalds int change = 0; 14141da177e4SLinus Torvalds 14151da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 1416184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 1417184c1e2cSJames Courtier-Dutton /* Do nothing for Audigy 2 ZS Notebook */ 1418184c1e2cSJames Courtier-Dutton } else if (emu->audigy) { 14191da177e4SLinus Torvalds reg = inl(emu->port + A_IOCFG); 14201da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; 14211da177e4SLinus Torvalds change = (reg & A_IOCFG_GPOUT0) != val; 14221da177e4SLinus Torvalds if (change) { 14231da177e4SLinus Torvalds reg &= ~A_IOCFG_GPOUT0; 14241da177e4SLinus Torvalds reg |= val; 14251da177e4SLinus Torvalds outl(reg | val, emu->port + A_IOCFG); 14261da177e4SLinus Torvalds } 14271da177e4SLinus Torvalds } 14281da177e4SLinus Torvalds reg = inl(emu->port + HCFG); 14291da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0; 14301da177e4SLinus Torvalds change |= (reg & HCFG_GPOUT0) != val; 14311da177e4SLinus Torvalds if (change) { 14321da177e4SLinus Torvalds reg &= ~HCFG_GPOUT0; 14331da177e4SLinus Torvalds reg |= val; 14341da177e4SLinus Torvalds outl(reg | val, emu->port + HCFG); 14351da177e4SLinus Torvalds } 14361da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 14371da177e4SLinus Torvalds return change; 14381da177e4SLinus Torvalds } 14391da177e4SLinus Torvalds 1440eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata = 14411da177e4SLinus Torvalds { 14421da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 14431da177e4SLinus Torvalds .name = "SB Live Analog/Digital Output Jack", 14441da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 14451da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 14461da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 14471da177e4SLinus Torvalds }; 14481da177e4SLinus Torvalds 1449eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata = 14501da177e4SLinus Torvalds { 14511da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 14521da177e4SLinus Torvalds .name = "Audigy Analog/Digital Output Jack", 14531da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 14541da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 14551da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 14561da177e4SLinus Torvalds }; 14571da177e4SLinus Torvalds 14581da177e4SLinus Torvalds /* 14591da177e4SLinus Torvalds */ 1460eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) 14611da177e4SLinus Torvalds { 1462eb4698f3STakashi Iwai struct snd_emu10k1 *emu = ac97->private_data; 14631da177e4SLinus Torvalds emu->ac97 = NULL; 14641da177e4SLinus Torvalds } 14651da177e4SLinus Torvalds 14661da177e4SLinus Torvalds /* 14671da177e4SLinus Torvalds */ 1468eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name) 14691da177e4SLinus Torvalds { 1470eb4698f3STakashi Iwai struct snd_ctl_elem_id id; 14711da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 14721da177e4SLinus Torvalds strcpy(id.name, name); 14731da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 14741da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 14751da177e4SLinus Torvalds } 14761da177e4SLinus Torvalds 1477eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) 14781da177e4SLinus Torvalds { 1479eb4698f3STakashi Iwai struct snd_ctl_elem_id sid; 14801da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 14811da177e4SLinus Torvalds strcpy(sid.name, name); 14821da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 14831da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 14841da177e4SLinus Torvalds } 14851da177e4SLinus Torvalds 1486eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst) 14871da177e4SLinus Torvalds { 1488eb4698f3STakashi Iwai struct snd_kcontrol *kctl = ctl_find(card, src); 14891da177e4SLinus Torvalds if (kctl) { 14901da177e4SLinus Torvalds strcpy(kctl->id.name, dst); 14911da177e4SLinus Torvalds return 0; 14921da177e4SLinus Torvalds } 14931da177e4SLinus Torvalds return -ENOENT; 14941da177e4SLinus Torvalds } 14951da177e4SLinus Torvalds 1496eb4698f3STakashi Iwai int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, 149767ed4161SClemens Ladisch int pcm_device, int multi_device) 14981da177e4SLinus Torvalds { 14991da177e4SLinus Torvalds int err, pcm; 1500eb4698f3STakashi Iwai struct snd_kcontrol *kctl; 1501eb4698f3STakashi Iwai struct snd_card *card = emu->card; 15021da177e4SLinus Torvalds char **c; 15031da177e4SLinus Torvalds static char *emu10k1_remove_ctls[] = { 15041da177e4SLinus Torvalds /* no AC97 mono, surround, center/lfe */ 15051da177e4SLinus Torvalds "Master Mono Playback Switch", 15061da177e4SLinus Torvalds "Master Mono Playback Volume", 15071da177e4SLinus Torvalds "PCM Out Path & Mute", 15081da177e4SLinus Torvalds "Mono Output Select", 15097eae36fbSTakashi Iwai "Front Playback Switch", 15107eae36fbSTakashi Iwai "Front Playback Volume", 15111da177e4SLinus Torvalds "Surround Playback Switch", 15121da177e4SLinus Torvalds "Surround Playback Volume", 15131da177e4SLinus Torvalds "Center Playback Switch", 15141da177e4SLinus Torvalds "Center Playback Volume", 15151da177e4SLinus Torvalds "LFE Playback Switch", 15161da177e4SLinus Torvalds "LFE Playback Volume", 15171da177e4SLinus Torvalds NULL 15181da177e4SLinus Torvalds }; 15191da177e4SLinus Torvalds static char *emu10k1_rename_ctls[] = { 15201da177e4SLinus Torvalds "Surround Digital Playback Volume", "Surround Playback Volume", 15211da177e4SLinus Torvalds "Center Digital Playback Volume", "Center Playback Volume", 15221da177e4SLinus Torvalds "LFE Digital Playback Volume", "LFE Playback Volume", 15231da177e4SLinus Torvalds NULL 15241da177e4SLinus Torvalds }; 15251da177e4SLinus Torvalds static char *audigy_remove_ctls[] = { 15261da177e4SLinus Torvalds /* Master/PCM controls on ac97 of Audigy has no effect */ 152721fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 152821fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 15291da177e4SLinus Torvalds "PCM Playback Switch", 15301da177e4SLinus Torvalds "PCM Playback Volume", 15311da177e4SLinus Torvalds "Master Mono Playback Switch", 15321da177e4SLinus Torvalds "Master Mono Playback Volume", 15331da177e4SLinus Torvalds "Master Playback Switch", 15341da177e4SLinus Torvalds "Master Playback Volume", 15351da177e4SLinus Torvalds "PCM Out Path & Mute", 15361da177e4SLinus Torvalds "Mono Output Select", 15371da177e4SLinus Torvalds /* remove unused AC97 capture controls */ 15381da177e4SLinus Torvalds "Capture Source", 15391da177e4SLinus Torvalds "Capture Switch", 15401da177e4SLinus Torvalds "Capture Volume", 15411da177e4SLinus Torvalds "Mic Select", 15421da177e4SLinus Torvalds "Video Playback Switch", 15431da177e4SLinus Torvalds "Video Playback Volume", 15441da177e4SLinus Torvalds "Mic Playback Switch", 15451da177e4SLinus Torvalds "Mic Playback Volume", 15461da177e4SLinus Torvalds NULL 15471da177e4SLinus Torvalds }; 15481da177e4SLinus Torvalds static char *audigy_rename_ctls[] = { 15491da177e4SLinus Torvalds /* use conventional names */ 15501da177e4SLinus Torvalds "Wave Playback Volume", "PCM Playback Volume", 15511da177e4SLinus Torvalds /* "Wave Capture Volume", "PCM Capture Volume", */ 15521da177e4SLinus Torvalds "Wave Master Playback Volume", "Master Playback Volume", 15531da177e4SLinus Torvalds "AMic Playback Volume", "Mic Playback Volume", 15541da177e4SLinus Torvalds NULL 15551da177e4SLinus Torvalds }; 1556184c1e2cSJames Courtier-Dutton static char *audigy_rename_ctls_i2c_adc[] = { 1557184c1e2cSJames Courtier-Dutton //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", 1558184c1e2cSJames Courtier-Dutton "Line Capture Volume", "Analog Mix Capture Volume", 1559184c1e2cSJames Courtier-Dutton "Wave Playback Volume", "OLD PCM Playback Volume", 1560184c1e2cSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 1561184c1e2cSJames Courtier-Dutton "AMic Playback Volume", "Old Mic Playback Volume", 1562eb41dab6SJames Courtier-Dutton "CD Capture Volume", "IEC958 Optical Capture Volume", 1563184c1e2cSJames Courtier-Dutton NULL 1564184c1e2cSJames Courtier-Dutton }; 1565184c1e2cSJames Courtier-Dutton static char *audigy_remove_ctls_i2c_adc[] = { 1566184c1e2cSJames Courtier-Dutton /* On the Audigy2 ZS Notebook 1567184c1e2cSJames Courtier-Dutton * Capture via WM8775 */ 1568184c1e2cSJames Courtier-Dutton "Mic Capture Volume", 1569184c1e2cSJames Courtier-Dutton "Analog Mix Capture Volume", 1570184c1e2cSJames Courtier-Dutton "Aux Capture Volume", 1571eb41dab6SJames Courtier-Dutton "IEC958 Optical Capture Volume", 1572184c1e2cSJames Courtier-Dutton NULL 1573184c1e2cSJames Courtier-Dutton }; 157421fdddeaSJames Courtier-Dutton static char *audigy_remove_ctls_1361t_adc[] = { 157521fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 157621fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 157721fdddeaSJames Courtier-Dutton "PCM Playback Switch", 157821fdddeaSJames Courtier-Dutton "PCM Playback Volume", 157921fdddeaSJames Courtier-Dutton "Master Mono Playback Switch", 158021fdddeaSJames Courtier-Dutton "Master Mono Playback Volume", 158121fdddeaSJames Courtier-Dutton "Capture Source", 158221fdddeaSJames Courtier-Dutton "Capture Switch", 158321fdddeaSJames Courtier-Dutton "Capture Volume", 158421fdddeaSJames Courtier-Dutton "Mic Capture Volume", 158521fdddeaSJames Courtier-Dutton "Headphone Playback Switch", 158621fdddeaSJames Courtier-Dutton "Headphone Playback Volume", 158721fdddeaSJames Courtier-Dutton "3D Control - Center", 158821fdddeaSJames Courtier-Dutton "3D Control - Depth", 158921fdddeaSJames Courtier-Dutton "3D Control - Switch", 159021fdddeaSJames Courtier-Dutton "Line2 Playback Volume", 159121fdddeaSJames Courtier-Dutton "Line2 Capture Volume", 159221fdddeaSJames Courtier-Dutton NULL 159321fdddeaSJames Courtier-Dutton }; 159421fdddeaSJames Courtier-Dutton static char *audigy_rename_ctls_1361t_adc[] = { 159521fdddeaSJames Courtier-Dutton "Master Playback Switch", "Master Capture Switch", 159621fdddeaSJames Courtier-Dutton "Master Playback Volume", "Master Capture Volume", 159721fdddeaSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 159821fdddeaSJames Courtier-Dutton "PC Speaker Playback Switch", "PC Speaker Capture Switch", 159921fdddeaSJames Courtier-Dutton "PC Speaker Playback Volume", "PC Speaker Capture Volume", 160021fdddeaSJames Courtier-Dutton "Phone Playback Switch", "Phone Capture Switch", 160121fdddeaSJames Courtier-Dutton "Phone Playback Volume", "Phone Capture Volume", 160221fdddeaSJames Courtier-Dutton "Mic Playback Switch", "Mic Capture Switch", 160321fdddeaSJames Courtier-Dutton "Mic Playback Volume", "Mic Capture Volume", 160421fdddeaSJames Courtier-Dutton "Line Playback Switch", "Line Capture Switch", 160521fdddeaSJames Courtier-Dutton "Line Playback Volume", "Line Capture Volume", 160621fdddeaSJames Courtier-Dutton "CD Playback Switch", "CD Capture Switch", 160721fdddeaSJames Courtier-Dutton "CD Playback Volume", "CD Capture Volume", 160821fdddeaSJames Courtier-Dutton "Aux Playback Switch", "Aux Capture Switch", 160921fdddeaSJames Courtier-Dutton "Aux Playback Volume", "Aux Capture Volume", 161021fdddeaSJames Courtier-Dutton "Video Playback Switch", "Video Capture Switch", 161121fdddeaSJames Courtier-Dutton "Video Playback Volume", "Video Capture Volume", 161221fdddeaSJames Courtier-Dutton 161321fdddeaSJames Courtier-Dutton NULL 161421fdddeaSJames Courtier-Dutton }; 16151da177e4SLinus Torvalds 16162b637da5SLee Revell if (emu->card_capabilities->ac97_chip) { 1617eb4698f3STakashi Iwai struct snd_ac97_bus *pbus; 1618eb4698f3STakashi Iwai struct snd_ac97_template ac97; 1619eb4698f3STakashi Iwai static struct snd_ac97_bus_ops ops = { 16201da177e4SLinus Torvalds .write = snd_emu10k1_ac97_write, 16211da177e4SLinus Torvalds .read = snd_emu10k1_ac97_read, 16221da177e4SLinus Torvalds }; 16231da177e4SLinus Torvalds 1624b1508693STakashi Iwai if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0) 16251da177e4SLinus Torvalds return err; 16261da177e4SLinus Torvalds pbus->no_vra = 1; /* we don't need VRA */ 16271da177e4SLinus Torvalds 16281da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97)); 16291da177e4SLinus Torvalds ac97.private_data = emu; 16301da177e4SLinus Torvalds ac97.private_free = snd_emu10k1_mixer_free_ac97; 16311da177e4SLinus Torvalds ac97.scaps = AC97_SCAP_NO_SPDIF; 1632b1508693STakashi Iwai if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) { 1633b1508693STakashi Iwai if (emu->card_capabilities->ac97_chip == 1) 16341da177e4SLinus Torvalds return err; 1635b1508693STakashi Iwai snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n"); 1636b1508693STakashi Iwai snd_printd(KERN_INFO" Proceeding without ac97 mixers...\n"); 1637b1508693STakashi Iwai snd_device_free(emu->card, pbus); 1638b1508693STakashi Iwai goto no_ac97; /* FIXME: get rid of ugly gotos.. */ 1639b1508693STakashi Iwai } 16401da177e4SLinus Torvalds if (emu->audigy) { 16411da177e4SLinus Torvalds /* set master volume to 0 dB */ 16424d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); 16431da177e4SLinus Torvalds /* set capture source to mic */ 16444d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); 164521fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 164621fdddeaSJames Courtier-Dutton c = audigy_remove_ctls_1361t_adc; 164721fdddeaSJames Courtier-Dutton else 16481da177e4SLinus Torvalds c = audigy_remove_ctls; 16491da177e4SLinus Torvalds } else { 16501da177e4SLinus Torvalds /* 16511da177e4SLinus Torvalds * Credits for cards based on STAC9758: 16521da177e4SLinus Torvalds * James Courtier-Dutton <James@superbug.demon.co.uk> 16531da177e4SLinus Torvalds * Voluspa <voluspa@comhem.se> 16541da177e4SLinus Torvalds */ 16551da177e4SLinus Torvalds if (emu->ac97->id == AC97_ID_STAC9758) { 16561da177e4SLinus Torvalds emu->rear_ac97 = 1; 16571da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); 16582594d960SRolf Stefan Wilke snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); 16591da177e4SLinus Torvalds } 16601da177e4SLinus Torvalds /* remove unused AC97 controls */ 16614d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); 16624d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); 16631da177e4SLinus Torvalds c = emu10k1_remove_ctls; 16641da177e4SLinus Torvalds } 16651da177e4SLinus Torvalds for (; *c; c++) 16661da177e4SLinus Torvalds remove_ctl(card, *c); 1667184c1e2cSJames Courtier-Dutton } else if (emu->card_capabilities->i2c_adc) { 1668184c1e2cSJames Courtier-Dutton c = audigy_remove_ctls_i2c_adc; 1669184c1e2cSJames Courtier-Dutton for (; *c; c++) 1670184c1e2cSJames Courtier-Dutton remove_ctl(card, *c); 16711da177e4SLinus Torvalds } else { 1672f12aa40cSTakashi Iwai no_ac97: 16732b637da5SLee Revell if (emu->card_capabilities->ecard) 16741da177e4SLinus Torvalds strcpy(emu->card->mixername, "EMU APS"); 16751da177e4SLinus Torvalds else if (emu->audigy) 16761da177e4SLinus Torvalds strcpy(emu->card->mixername, "SB Audigy"); 16771da177e4SLinus Torvalds else 16781da177e4SLinus Torvalds strcpy(emu->card->mixername, "Emu10k1"); 16791da177e4SLinus Torvalds } 16801da177e4SLinus Torvalds 16811da177e4SLinus Torvalds if (emu->audigy) 168221fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 168321fdddeaSJames Courtier-Dutton c = audigy_rename_ctls_1361t_adc; 1684184c1e2cSJames Courtier-Dutton else if (emu->card_capabilities->i2c_adc) 1685184c1e2cSJames Courtier-Dutton c = audigy_rename_ctls_i2c_adc; 168621fdddeaSJames Courtier-Dutton else 16871da177e4SLinus Torvalds c = audigy_rename_ctls; 16881da177e4SLinus Torvalds else 16891da177e4SLinus Torvalds c = emu10k1_rename_ctls; 16901da177e4SLinus Torvalds for (; *c; c += 2) 16911da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 169221fdddeaSJames Courtier-Dutton 1693e3b9bc0eSJames Courtier-Dutton if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ 1694e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); 1695e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); 1696e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); 1697e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); 1698e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "Headphone Playback Switch"); 1699e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "Headphone Playback Volume"); 1700e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "3D Control - Center"); 1701e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "3D Control - Depth"); 1702e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "3D Control - Switch"); 1703e3b9bc0eSJames Courtier-Dutton } 17041da177e4SLinus Torvalds if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) 17051da177e4SLinus Torvalds return -ENOMEM; 170667ed4161SClemens Ladisch kctl->id.device = pcm_device; 17071da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 17081da177e4SLinus Torvalds return err; 17091da177e4SLinus Torvalds if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL) 17101da177e4SLinus Torvalds return -ENOMEM; 171167ed4161SClemens Ladisch kctl->id.device = pcm_device; 17121da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 17131da177e4SLinus Torvalds return err; 17141da177e4SLinus Torvalds if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL) 17151da177e4SLinus Torvalds return -ENOMEM; 171667ed4161SClemens Ladisch kctl->id.device = pcm_device; 17171da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 17181da177e4SLinus Torvalds return err; 17191da177e4SLinus Torvalds 17201da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL) 17211da177e4SLinus Torvalds return -ENOMEM; 172267ed4161SClemens Ladisch kctl->id.device = multi_device; 17231da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 17241da177e4SLinus Torvalds return err; 17251da177e4SLinus Torvalds 17261da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL) 17271da177e4SLinus Torvalds return -ENOMEM; 172867ed4161SClemens Ladisch kctl->id.device = multi_device; 17291da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 17301da177e4SLinus Torvalds return err; 17311da177e4SLinus Torvalds 17321da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL) 17331da177e4SLinus Torvalds return -ENOMEM; 173467ed4161SClemens Ladisch kctl->id.device = multi_device; 17351da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 17361da177e4SLinus Torvalds return err; 17371da177e4SLinus Torvalds 17381da177e4SLinus Torvalds /* initialize the routing and volume table for each pcm playback stream */ 17391da177e4SLinus Torvalds for (pcm = 0; pcm < 32; pcm++) { 1740eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 17411da177e4SLinus Torvalds int v; 17421da177e4SLinus Torvalds 17431da177e4SLinus Torvalds mix = &emu->pcm_mixer[pcm]; 17441da177e4SLinus Torvalds mix->epcm = NULL; 17451da177e4SLinus Torvalds 17461da177e4SLinus Torvalds for (v = 0; v < 4; v++) 17471da177e4SLinus Torvalds mix->send_routing[0][v] = 17481da177e4SLinus Torvalds mix->send_routing[1][v] = 17491da177e4SLinus Torvalds mix->send_routing[2][v] = v; 17501da177e4SLinus Torvalds 17511da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 17521da177e4SLinus Torvalds mix->send_volume[0][0] = mix->send_volume[0][1] = 17531da177e4SLinus Torvalds mix->send_volume[1][0] = mix->send_volume[2][1] = 255; 17541da177e4SLinus Torvalds 17551da177e4SLinus Torvalds mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; 17561da177e4SLinus Torvalds } 17571da177e4SLinus Torvalds 17581da177e4SLinus Torvalds /* initialize the routing and volume table for the multichannel playback stream */ 17591da177e4SLinus Torvalds for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) { 1760eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 17611da177e4SLinus Torvalds int v; 17621da177e4SLinus Torvalds 17631da177e4SLinus Torvalds mix = &emu->efx_pcm_mixer[pcm]; 17641da177e4SLinus Torvalds mix->epcm = NULL; 17651da177e4SLinus Torvalds 17661da177e4SLinus Torvalds mix->send_routing[0][0] = pcm; 17671da177e4SLinus Torvalds mix->send_routing[0][1] = (pcm == 0) ? 1 : 0; 17681da177e4SLinus Torvalds for (v = 0; v < 2; v++) 17691da177e4SLinus Torvalds mix->send_routing[0][2+v] = 13+v; 17701da177e4SLinus Torvalds if (emu->audigy) 17711da177e4SLinus Torvalds for (v = 0; v < 4; v++) 17721da177e4SLinus Torvalds mix->send_routing[0][4+v] = 60+v; 17731da177e4SLinus Torvalds 17741da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 17751da177e4SLinus Torvalds mix->send_volume[0][0] = 255; 17761da177e4SLinus Torvalds 17771da177e4SLinus Torvalds mix->attn[0] = 0xffff; 17781da177e4SLinus Torvalds } 17791da177e4SLinus Torvalds 17802b637da5SLee Revell if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */ 17811da177e4SLinus Torvalds /* sb live! and audigy */ 17821da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) 17831da177e4SLinus Torvalds return -ENOMEM; 17845549d549SClemens Ladisch if (!emu->audigy) 17855549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 17861da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 17871da177e4SLinus Torvalds return err; 17881da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) 17891da177e4SLinus Torvalds return -ENOMEM; 17905549d549SClemens Ladisch if (!emu->audigy) 17915549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 17921da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 17931da177e4SLinus Torvalds return err; 17941da177e4SLinus Torvalds } 17951da177e4SLinus Torvalds 17969f4bd5ddSJames Courtier-Dutton if ( emu->card_capabilities->emu1010) { 179719b99fbaSJames Courtier-Dutton ; /* Disable the snd_audigy_spdif_shared_spdif */ 179819b99fbaSJames Courtier-Dutton } else if (emu->audigy) { 17991da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) 18001da177e4SLinus Torvalds return -ENOMEM; 18011da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 18021da177e4SLinus Torvalds return err; 1803001f7589SJames Courtier-Dutton #if 0 18041da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) 18051da177e4SLinus Torvalds return -ENOMEM; 18061da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 18071da177e4SLinus Torvalds return err; 1808001f7589SJames Courtier-Dutton #endif 18092b637da5SLee Revell } else if (! emu->card_capabilities->ecard) { 18101da177e4SLinus Torvalds /* sb live! */ 18111da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) 18121da177e4SLinus Torvalds return -ENOMEM; 18131da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 18141da177e4SLinus Torvalds return err; 18151da177e4SLinus Torvalds } 18162b637da5SLee Revell if (emu->card_capabilities->ca0151_chip) { /* P16V */ 18171da177e4SLinus Torvalds if ((err = snd_p16v_mixer(emu))) 18181da177e4SLinus Torvalds return err; 18191da177e4SLinus Torvalds } 18201da177e4SLinus Torvalds 18219f4bd5ddSJames Courtier-Dutton if ( emu->card_capabilities->emu1010) { 18229f4bd5ddSJames Courtier-Dutton int i; 18239f4bd5ddSJames Courtier-Dutton 18249f4bd5ddSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { 18259f4bd5ddSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu)); 18269f4bd5ddSJames Courtier-Dutton if (err < 0) 18279f4bd5ddSJames Courtier-Dutton return err; 18289f4bd5ddSJames Courtier-Dutton } 18299f4bd5ddSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { 18309f4bd5ddSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu)); 18319f4bd5ddSJames Courtier-Dutton if (err < 0) 18329f4bd5ddSJames Courtier-Dutton return err; 18339f4bd5ddSJames Courtier-Dutton } 18349148cc50SJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { 18359148cc50SJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); 18369148cc50SJames Courtier-Dutton if (err < 0) 18379148cc50SJames Courtier-Dutton return err; 18389148cc50SJames Courtier-Dutton } 18399148cc50SJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { 18409148cc50SJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); 18419148cc50SJames Courtier-Dutton if (err < 0) 18429148cc50SJames Courtier-Dutton return err; 18439148cc50SJames Courtier-Dutton } 1844b0dbdaeaSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 1845b0dbdaeaSJames Courtier-Dutton if (err < 0) 1846b0dbdaeaSJames Courtier-Dutton return err; 18479f4bd5ddSJames Courtier-Dutton } 18489f4bd5ddSJames Courtier-Dutton 1849184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 1850184c1e2cSJames Courtier-Dutton int i; 1851184c1e2cSJames Courtier-Dutton 1852184c1e2cSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); 1853184c1e2cSJames Courtier-Dutton if (err < 0) 1854184c1e2cSJames Courtier-Dutton return err; 1855184c1e2cSJames Courtier-Dutton 1856184c1e2cSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { 1857184c1e2cSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); 1858184c1e2cSJames Courtier-Dutton if (err < 0) 1859184c1e2cSJames Courtier-Dutton return err; 1860184c1e2cSJames Courtier-Dutton } 1861184c1e2cSJames Courtier-Dutton } 1862184c1e2cSJames Courtier-Dutton 18631da177e4SLinus Torvalds return 0; 18641da177e4SLinus Torvalds } 1865