11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (c) by Jaroslav Kysela <perex@suse.cz>, 31da177e4SLinus Torvalds * Takashi Iwai <tiwai@suse.de> 41da177e4SLinus Torvalds * Creative Labs, Inc. 51da177e4SLinus Torvalds * Routines for control of EMU10K1 chips / mixer routines 61da177e4SLinus Torvalds * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> 71da177e4SLinus Torvalds * 89f4bd5ddSJames Courtier-Dutton * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> 99f4bd5ddSJames Courtier-Dutton * Added EMU 1010 support. 109f4bd5ddSJames Courtier-Dutton * 111da177e4SLinus Torvalds * BUGS: 121da177e4SLinus Torvalds * -- 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * TODO: 151da177e4SLinus Torvalds * -- 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 181da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 191da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 201da177e4SLinus Torvalds * (at your option) any later version. 211da177e4SLinus Torvalds * 221da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 231da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 241da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 251da177e4SLinus Torvalds * GNU General Public License for more details. 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 281da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 291da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds */ 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds #include <sound/driver.h> 341da177e4SLinus Torvalds #include <linux/time.h> 351da177e4SLinus Torvalds #include <linux/init.h> 361da177e4SLinus Torvalds #include <sound/core.h> 371da177e4SLinus Torvalds #include <sound/emu10k1.h> 38*b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h> 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds #define AC97_ID_STAC9758 0x83847658 411da177e4SLinus Torvalds 42eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 431da177e4SLinus Torvalds { 441da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 451da177e4SLinus Torvalds uinfo->count = 1; 461da177e4SLinus Torvalds return 0; 471da177e4SLinus Torvalds } 481da177e4SLinus Torvalds 49eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol, 50eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 511da177e4SLinus Torvalds { 52eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 531da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 541da177e4SLinus Torvalds unsigned long flags; 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 571da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 581da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 591da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 601da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 611da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 621da177e4SLinus Torvalds return 0; 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 65eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, 66eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 671da177e4SLinus Torvalds { 681da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = 0xff; 691da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = 0xff; 701da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = 0xff; 711da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = 0xff; 721da177e4SLinus Torvalds return 0; 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 759f4bd5ddSJames Courtier-Dutton static char *emu1010_src_texts[] = { 769f4bd5ddSJames Courtier-Dutton "Silence", 779f4bd5ddSJames Courtier-Dutton "Dock Mic A", 789f4bd5ddSJames Courtier-Dutton "Dock Mic B", 799f4bd5ddSJames Courtier-Dutton "Dock ADC1 Left", 809f4bd5ddSJames Courtier-Dutton "Dock ADC1 Right", 819f4bd5ddSJames Courtier-Dutton "Dock ADC2 Left", 829f4bd5ddSJames Courtier-Dutton "Dock ADC2 Right", 839f4bd5ddSJames Courtier-Dutton "Dock ADC3 Left", 849f4bd5ddSJames Courtier-Dutton "Dock ADC3 Right", 859f4bd5ddSJames Courtier-Dutton "0202 ADC Left", 869f4bd5ddSJames Courtier-Dutton "0202 ADC Right", 879f4bd5ddSJames Courtier-Dutton "0202 SPDIF Left", 889f4bd5ddSJames Courtier-Dutton "0202 SPDIF Right", 899f4bd5ddSJames Courtier-Dutton "ADAT 0", 909f4bd5ddSJames Courtier-Dutton "ADAT 1", 919f4bd5ddSJames Courtier-Dutton "ADAT 2", 929f4bd5ddSJames Courtier-Dutton "ADAT 3", 939f4bd5ddSJames Courtier-Dutton "ADAT 4", 949f4bd5ddSJames Courtier-Dutton "ADAT 5", 959f4bd5ddSJames Courtier-Dutton "ADAT 6", 969f4bd5ddSJames Courtier-Dutton "ADAT 7", 979f4bd5ddSJames Courtier-Dutton "DSP 0", 989f4bd5ddSJames Courtier-Dutton "DSP 1", 999f4bd5ddSJames Courtier-Dutton "DSP 2", 1009f4bd5ddSJames Courtier-Dutton "DSP 3", 1019f4bd5ddSJames Courtier-Dutton "DSP 4", 1029f4bd5ddSJames Courtier-Dutton "DSP 5", 1039f4bd5ddSJames Courtier-Dutton "DSP 6", 1049f4bd5ddSJames Courtier-Dutton "DSP 7", 1059f4bd5ddSJames Courtier-Dutton "DSP 8", 1069f4bd5ddSJames Courtier-Dutton "DSP 9", 1079f4bd5ddSJames Courtier-Dutton "DSP 10", 1089f4bd5ddSJames Courtier-Dutton "DSP 11", 1099f4bd5ddSJames Courtier-Dutton "DSP 12", 1109f4bd5ddSJames Courtier-Dutton "DSP 13", 1119f4bd5ddSJames Courtier-Dutton "DSP 14", 1129f4bd5ddSJames Courtier-Dutton "DSP 15", 1139f4bd5ddSJames Courtier-Dutton "DSP 16", 1149f4bd5ddSJames Courtier-Dutton "DSP 17", 1159f4bd5ddSJames Courtier-Dutton "DSP 18", 1169f4bd5ddSJames Courtier-Dutton "DSP 19", 1179f4bd5ddSJames Courtier-Dutton "DSP 20", 1189f4bd5ddSJames Courtier-Dutton "DSP 21", 1199f4bd5ddSJames Courtier-Dutton "DSP 22", 1209f4bd5ddSJames Courtier-Dutton "DSP 23", 1219f4bd5ddSJames Courtier-Dutton "DSP 24", 1229f4bd5ddSJames Courtier-Dutton "DSP 25", 1239f4bd5ddSJames Courtier-Dutton "DSP 26", 1249f4bd5ddSJames Courtier-Dutton "DSP 27", 1259f4bd5ddSJames Courtier-Dutton "DSP 28", 1269f4bd5ddSJames Courtier-Dutton "DSP 29", 1279f4bd5ddSJames Courtier-Dutton "DSP 30", 1289f4bd5ddSJames Courtier-Dutton "DSP 31", 1299f4bd5ddSJames Courtier-Dutton }; 1309f4bd5ddSJames Courtier-Dutton 1319f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_src_regs[] = { 1329f4bd5ddSJames Courtier-Dutton EMU_SRC_SILENCE,/* 0 */ 1339f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_MIC_A1, /* 1 */ 1349f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_MIC_B1, /* 2 */ 1359f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */ 1369f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */ 1379f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */ 1389f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */ 1399f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */ 1409f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */ 1419f4bd5ddSJames Courtier-Dutton EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */ 1429f4bd5ddSJames Courtier-Dutton EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */ 1439f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */ 1449f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */ 1459f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT, /* 13 */ 1469f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+1, /* 14 */ 1479f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+2, /* 15 */ 1489f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+3, /* 16 */ 1499f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+4, /* 17 */ 1509f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+5, /* 18 */ 1519f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+6, /* 19 */ 1529f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+7, /* 20 */ 1539f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A, /* 21 */ 1549f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+1, /* 22 */ 1559f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+2, /* 23 */ 1569f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+3, /* 24 */ 1579f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+4, /* 25 */ 1589f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+5, /* 26 */ 1599f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+6, /* 27 */ 1609f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+7, /* 28 */ 1619f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+8, /* 29 */ 1629f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+9, /* 30 */ 1639f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xa, /* 31 */ 1649f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xb, /* 32 */ 1659f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xc, /* 33 */ 1669f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xd, /* 34 */ 1679f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xe, /* 35 */ 1689f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xf, /* 36 */ 1699f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B, /* 37 */ 1709f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+1, /* 38 */ 1719f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+2, /* 39 */ 1729f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+3, /* 40 */ 1739f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+4, /* 41 */ 1749f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+5, /* 42 */ 1759f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+6, /* 43 */ 1769f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+7, /* 44 */ 1779f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+8, /* 45 */ 1789f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+9, /* 46 */ 1799f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xa, /* 47 */ 1809f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xb, /* 48 */ 1819f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xc, /* 49 */ 1829f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xd, /* 50 */ 1839f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xe, /* 51 */ 1849f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ 1859f4bd5ddSJames Courtier-Dutton }; 1869f4bd5ddSJames Courtier-Dutton 1879f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_output_dst[] = { 1889f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ 1899f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ 1909f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ 1919f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ 1929f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ 1939f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ 1949f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ 1959f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ 1969f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ 1979f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ 1989f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ 1999f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ 2009f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ 2019f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ 2029f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ 2039f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ 2049f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT, /* 16 */ 2059f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+1, /* 17 */ 2069f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+2, /* 18 */ 2079f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+3, /* 19 */ 2089f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+4, /* 20 */ 2099f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+5, /* 21 */ 2109f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+6, /* 22 */ 2119f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+7, /* 23 */ 2129f4bd5ddSJames Courtier-Dutton }; 2139f4bd5ddSJames Courtier-Dutton 2149f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_input_dst[] = { 2159f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_0, 2169f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_1, 2179f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_2, 2189f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_3, 2199f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_4, 2209f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_5, 2219f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_6, 2229f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_7, 2239f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_8, 2249f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_9, 2259f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_A, 2269f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_B, 2279f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_C, 2289f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_D, 2299f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_E, 2309f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_F, 2319f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_LEFT, 2329f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_RIGHT, 2339f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_LEFT, 2349f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_RIGHT, 2359f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_LEFT, 2369f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_RIGHT, 2379f4bd5ddSJames Courtier-Dutton }; 2389f4bd5ddSJames Courtier-Dutton 2399f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 2409f4bd5ddSJames Courtier-Dutton { 2419f4bd5ddSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2429f4bd5ddSJames Courtier-Dutton uinfo->count = 1; 2439f4bd5ddSJames Courtier-Dutton uinfo->value.enumerated.items = 53; 2449f4bd5ddSJames Courtier-Dutton if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 2459f4bd5ddSJames Courtier-Dutton uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 2469f4bd5ddSJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]); 2479f4bd5ddSJames Courtier-Dutton return 0; 2489f4bd5ddSJames Courtier-Dutton } 2499f4bd5ddSJames Courtier-Dutton 2509f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, 2519f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 2529f4bd5ddSJames Courtier-Dutton { 2539f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 2549f4bd5ddSJames Courtier-Dutton int channel; 2559f4bd5ddSJames Courtier-Dutton 2569f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 2579f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; 2589f4bd5ddSJames Courtier-Dutton return 0; 2599f4bd5ddSJames Courtier-Dutton } 2609f4bd5ddSJames Courtier-Dutton 2619f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, 2629f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 2639f4bd5ddSJames Courtier-Dutton { 2649f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 2659f4bd5ddSJames Courtier-Dutton int change = 0; 2669f4bd5ddSJames Courtier-Dutton unsigned int val; 2679f4bd5ddSJames Courtier-Dutton int channel; 2689f4bd5ddSJames Courtier-Dutton 2699f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 2709f4bd5ddSJames Courtier-Dutton if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) { 2719f4bd5ddSJames Courtier-Dutton val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0]; 2729f4bd5ddSJames Courtier-Dutton change = 1; 2739f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 2749f4bd5ddSJames Courtier-Dutton emu1010_output_dst[channel], emu1010_src_regs[val]); 2759f4bd5ddSJames Courtier-Dutton } 2769f4bd5ddSJames Courtier-Dutton return change; 2779f4bd5ddSJames Courtier-Dutton } 2789f4bd5ddSJames Courtier-Dutton 2799f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, 2809f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 2819f4bd5ddSJames Courtier-Dutton { 2829f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 2839f4bd5ddSJames Courtier-Dutton int channel; 2849f4bd5ddSJames Courtier-Dutton 2859f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 2869f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; 2879f4bd5ddSJames Courtier-Dutton return 0; 2889f4bd5ddSJames Courtier-Dutton } 2899f4bd5ddSJames Courtier-Dutton 2909f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, 2919f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 2929f4bd5ddSJames Courtier-Dutton { 2939f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 2949f4bd5ddSJames Courtier-Dutton int change = 0; 2959f4bd5ddSJames Courtier-Dutton unsigned int val; 2969f4bd5ddSJames Courtier-Dutton int channel; 2979f4bd5ddSJames Courtier-Dutton 2989f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 2999f4bd5ddSJames Courtier-Dutton if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) { 3009f4bd5ddSJames Courtier-Dutton val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0]; 3019f4bd5ddSJames Courtier-Dutton change = 1; 3029f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 3039f4bd5ddSJames Courtier-Dutton emu1010_input_dst[channel], emu1010_src_regs[val]); 3049f4bd5ddSJames Courtier-Dutton } 3059f4bd5ddSJames Courtier-Dutton return change; 3069f4bd5ddSJames Courtier-Dutton } 3079f4bd5ddSJames Courtier-Dutton 3089f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \ 3099f4bd5ddSJames Courtier-Dutton { \ 3109f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 3119f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 3129f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 3139f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_output_source_get, \ 3149f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_output_source_put, \ 3159f4bd5ddSJames Courtier-Dutton .private_value = chid \ 3169f4bd5ddSJames Courtier-Dutton } 3179f4bd5ddSJames Courtier-Dutton 3189f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { 3199148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Switch", 0), 3209148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Switch", 1), 3219148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Switch", 2), 3229148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Switch", 3), 3239148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Switch", 4), 3249148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Switch", 5), 3259148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Switch", 6), 3269148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Switch", 7), 3279148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Switch", 8), 3289148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Switch", 9), 3299148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Switch", 0xa), 3309148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Switch", 0xb), 3319148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Switch", 0xc), 3329148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Switch", 0xd), 3339148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Switch", 0xe), 3349148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Switch", 0xf), 3359148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Switch", 0x10), 3369148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Switch", 0x11), 3379148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Switch", 0x12), 3389148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Switch", 0x13), 3399148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Switch", 0x14), 3409148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Switch", 0x15), 3419148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Switch", 0x16), 3429148cc50SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Switch", 0x17), 3439f4bd5ddSJames Courtier-Dutton }; 3449f4bd5ddSJames Courtier-Dutton 3459f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \ 3469f4bd5ddSJames Courtier-Dutton { \ 3479f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 3489f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 3499f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 3509f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_input_source_get, \ 3519f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_input_source_put, \ 3529f4bd5ddSJames Courtier-Dutton .private_value = chid \ 3539f4bd5ddSJames Courtier-Dutton } 3549f4bd5ddSJames Courtier-Dutton 3559f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { 3569148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 0 Capture Switch", 0), 3579148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 1 Capture Switch", 1), 3589148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 2 Capture Switch", 2), 3599148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 3 Capture Switch", 3), 3609148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 4 Capture Switch", 4), 3619148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 5 Capture Switch", 5), 3629148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 6 Capture Switch", 6), 3639148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 7 Capture Switch", 7), 3649148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 8 Capture Switch", 8), 3659148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 9 Capture Switch", 9), 3669148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP A Capture Switch", 0xa), 3679148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP B Capture Switch", 0xb), 3689148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP C Capture Switch", 0xc), 3699148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP D Capture Switch", 0xd), 3709148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP E Capture Switch", 0xe), 3719148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP F Capture Switch", 0xf), 3729148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 10 Capture Switch", 0x10), 3739148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 11 Capture Switch", 0x11), 3749148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 12 Capture Switch", 0x12), 3759148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 13 Capture Switch", 0x13), 3769148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 14 Capture Switch", 0x14), 3779148cc50SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 15 Capture Switch", 0x15), 3789148cc50SJames Courtier-Dutton }; 3799148cc50SJames Courtier-Dutton 3809148cc50SJames Courtier-Dutton 3819148cc50SJames Courtier-Dutton 3829148cc50SJames Courtier-Dutton 3839148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 3849148cc50SJames Courtier-Dutton { 3859148cc50SJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 3869148cc50SJames Courtier-Dutton uinfo->count = 1; 3879148cc50SJames Courtier-Dutton uinfo->value.integer.min = 0; 3889148cc50SJames Courtier-Dutton uinfo->value.integer.max = 1; 3899148cc50SJames Courtier-Dutton return 0; 3909148cc50SJames Courtier-Dutton } 3919148cc50SJames Courtier-Dutton 3929148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 3939148cc50SJames Courtier-Dutton { 3949148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 3959148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 3969148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; 3979148cc50SJames Courtier-Dutton return 0; 3989148cc50SJames Courtier-Dutton } 3999148cc50SJames Courtier-Dutton 4009148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4019148cc50SJames Courtier-Dutton { 4029148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4039148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 4049148cc50SJames Courtier-Dutton unsigned int val, cache; 4059148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 4069148cc50SJames Courtier-Dutton cache = emu->emu1010.adc_pads; 4079148cc50SJames Courtier-Dutton if (val == 1) 4089148cc50SJames Courtier-Dutton cache = cache | mask; 4099148cc50SJames Courtier-Dutton else 4109148cc50SJames Courtier-Dutton cache = cache & ~mask; 4119148cc50SJames Courtier-Dutton if (cache != emu->emu1010.adc_pads) { 4129148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); 4139148cc50SJames Courtier-Dutton emu->emu1010.adc_pads = cache; 4149148cc50SJames Courtier-Dutton } 4159148cc50SJames Courtier-Dutton 4169148cc50SJames Courtier-Dutton return 0; 4179148cc50SJames Courtier-Dutton } 4189148cc50SJames Courtier-Dutton 4199148cc50SJames Courtier-Dutton 4209148cc50SJames Courtier-Dutton 4219148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \ 4229148cc50SJames Courtier-Dutton { \ 4239148cc50SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 4249148cc50SJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 4259148cc50SJames Courtier-Dutton .info = snd_emu1010_adc_pads_info, \ 4269148cc50SJames Courtier-Dutton .get = snd_emu1010_adc_pads_get, \ 4279148cc50SJames Courtier-Dutton .put = snd_emu1010_adc_pads_put, \ 4289148cc50SJames Courtier-Dutton .private_value = chid \ 4299148cc50SJames Courtier-Dutton } 4309148cc50SJames Courtier-Dutton 4319148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = { 4329148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), 4339148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), 4349148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), 4359148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), 4369148cc50SJames Courtier-Dutton }; 4379148cc50SJames Courtier-Dutton 4389148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 4399148cc50SJames Courtier-Dutton { 4409148cc50SJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 4419148cc50SJames Courtier-Dutton uinfo->count = 1; 4429148cc50SJames Courtier-Dutton uinfo->value.integer.min = 0; 4439148cc50SJames Courtier-Dutton uinfo->value.integer.max = 1; 4449148cc50SJames Courtier-Dutton return 0; 4459148cc50SJames Courtier-Dutton } 4469148cc50SJames Courtier-Dutton 4479148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4489148cc50SJames Courtier-Dutton { 4499148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4509148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 4519148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; 4529148cc50SJames Courtier-Dutton return 0; 4539148cc50SJames Courtier-Dutton } 4549148cc50SJames Courtier-Dutton 4559148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4569148cc50SJames Courtier-Dutton { 4579148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4589148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 4599148cc50SJames Courtier-Dutton unsigned int val, cache; 4609148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 4619148cc50SJames Courtier-Dutton cache = emu->emu1010.dac_pads; 4629148cc50SJames Courtier-Dutton if (val == 1) 4639148cc50SJames Courtier-Dutton cache = cache | mask; 4649148cc50SJames Courtier-Dutton else 4659148cc50SJames Courtier-Dutton cache = cache & ~mask; 4669148cc50SJames Courtier-Dutton if (cache != emu->emu1010.dac_pads) { 4679148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); 4689148cc50SJames Courtier-Dutton emu->emu1010.dac_pads = cache; 4699148cc50SJames Courtier-Dutton } 4709148cc50SJames Courtier-Dutton 4719148cc50SJames Courtier-Dutton return 0; 4729148cc50SJames Courtier-Dutton } 4739148cc50SJames Courtier-Dutton 4749148cc50SJames Courtier-Dutton 4759148cc50SJames Courtier-Dutton 4769148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \ 4779148cc50SJames Courtier-Dutton { \ 4789148cc50SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 4799148cc50SJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 4809148cc50SJames Courtier-Dutton .info = snd_emu1010_dac_pads_info, \ 4819148cc50SJames Courtier-Dutton .get = snd_emu1010_dac_pads_get, \ 4829148cc50SJames Courtier-Dutton .put = snd_emu1010_dac_pads_put, \ 4839148cc50SJames Courtier-Dutton .private_value = chid \ 4849148cc50SJames Courtier-Dutton } 4859148cc50SJames Courtier-Dutton 4869148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = { 4879148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), 4889148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), 4899148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), 4909148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4), 4919148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), 4929f4bd5ddSJames Courtier-Dutton }; 4939f4bd5ddSJames Courtier-Dutton 494*b0dbdaeaSJames Courtier-Dutton 495*b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, 496*b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 497*b0dbdaeaSJames Courtier-Dutton { 498*b0dbdaeaSJames Courtier-Dutton static char *texts[2] = { 499*b0dbdaeaSJames Courtier-Dutton "44100", "48000" 500*b0dbdaeaSJames Courtier-Dutton }; 501*b0dbdaeaSJames Courtier-Dutton 502*b0dbdaeaSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 503*b0dbdaeaSJames Courtier-Dutton uinfo->count = 1; 504*b0dbdaeaSJames Courtier-Dutton uinfo->value.enumerated.items = 2; 505*b0dbdaeaSJames Courtier-Dutton if (uinfo->value.enumerated.item > 1) 506*b0dbdaeaSJames Courtier-Dutton uinfo->value.enumerated.item = 1; 507*b0dbdaeaSJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 508*b0dbdaeaSJames Courtier-Dutton return 0; 509*b0dbdaeaSJames Courtier-Dutton } 510*b0dbdaeaSJames Courtier-Dutton 511*b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, 512*b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 513*b0dbdaeaSJames Courtier-Dutton { 514*b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 515*b0dbdaeaSJames Courtier-Dutton 516*b0dbdaeaSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; 517*b0dbdaeaSJames Courtier-Dutton return 0; 518*b0dbdaeaSJames Courtier-Dutton } 519*b0dbdaeaSJames Courtier-Dutton 520*b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, 521*b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 522*b0dbdaeaSJames Courtier-Dutton { 523*b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 524*b0dbdaeaSJames Courtier-Dutton unsigned int val; 525*b0dbdaeaSJames Courtier-Dutton int change = 0; 526*b0dbdaeaSJames Courtier-Dutton 527*b0dbdaeaSJames Courtier-Dutton val = ucontrol->value.enumerated.item[0] ; 528*b0dbdaeaSJames Courtier-Dutton change = (emu->emu1010.internal_clock != val); 529*b0dbdaeaSJames Courtier-Dutton if (change) { 530*b0dbdaeaSJames Courtier-Dutton emu->emu1010.internal_clock = val; 531*b0dbdaeaSJames Courtier-Dutton switch (val) { 532*b0dbdaeaSJames Courtier-Dutton case 0: 533*b0dbdaeaSJames Courtier-Dutton /* 44100 */ 534*b0dbdaeaSJames Courtier-Dutton /* Mute all */ 535*b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 536*b0dbdaeaSJames Courtier-Dutton /* Default fallback clock 48kHz */ 537*b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); 538*b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 44.1kHz x1 */ 539*b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 540*b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); 541*b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 542*b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 543*b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); 544*b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 545*b0dbdaeaSJames Courtier-Dutton udelay(10000); 546*b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 547*b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 548*b0dbdaeaSJames Courtier-Dutton break; 549*b0dbdaeaSJames Courtier-Dutton case 1: 550*b0dbdaeaSJames Courtier-Dutton /* 48000 */ 551*b0dbdaeaSJames Courtier-Dutton /* Mute all */ 552*b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 553*b0dbdaeaSJames Courtier-Dutton /* Default fallback clock 48kHz */ 554*b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 555*b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 48kHz x1 */ 556*b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 557*b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); 558*b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 559*b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 560*b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); 561*b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 562*b0dbdaeaSJames Courtier-Dutton udelay(10000); 563*b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 564*b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 565*b0dbdaeaSJames Courtier-Dutton break; 566*b0dbdaeaSJames Courtier-Dutton } 567*b0dbdaeaSJames Courtier-Dutton } 568*b0dbdaeaSJames Courtier-Dutton return change; 569*b0dbdaeaSJames Courtier-Dutton } 570*b0dbdaeaSJames Courtier-Dutton 571*b0dbdaeaSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_internal_clock = 572*b0dbdaeaSJames Courtier-Dutton { 573*b0dbdaeaSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 574*b0dbdaeaSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 575*b0dbdaeaSJames Courtier-Dutton .name = "Clock Internal Rate", 576*b0dbdaeaSJames Courtier-Dutton .count = 1, 577*b0dbdaeaSJames Courtier-Dutton .info = snd_emu1010_internal_clock_info, 578*b0dbdaeaSJames Courtier-Dutton .get = snd_emu1010_internal_clock_get, 579*b0dbdaeaSJames Courtier-Dutton .put = snd_emu1010_internal_clock_put 580*b0dbdaeaSJames Courtier-Dutton }; 581*b0dbdaeaSJames Courtier-Dutton 5820af68e5eSTakashi Iwai #if 0 583eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 5841da177e4SLinus Torvalds { 5851da177e4SLinus Torvalds static char *texts[] = {"44100", "48000", "96000"}; 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 5881da177e4SLinus Torvalds uinfo->count = 1; 5891da177e4SLinus Torvalds uinfo->value.enumerated.items = 3; 5901da177e4SLinus Torvalds if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 5911da177e4SLinus Torvalds uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 5921da177e4SLinus Torvalds strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 5931da177e4SLinus Torvalds return 0; 5941da177e4SLinus Torvalds } 5951da177e4SLinus Torvalds 596eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, 597eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 5981da177e4SLinus Torvalds { 599eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6001da177e4SLinus Torvalds unsigned int tmp; 6011da177e4SLinus Torvalds unsigned long flags; 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds 6041da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 6051da177e4SLinus Torvalds tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 6061da177e4SLinus Torvalds switch (tmp & A_SPDIF_RATE_MASK) { 6071da177e4SLinus Torvalds case A_SPDIF_44100: 6081da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 6091da177e4SLinus Torvalds break; 6101da177e4SLinus Torvalds case A_SPDIF_48000: 6111da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 6121da177e4SLinus Torvalds break; 6131da177e4SLinus Torvalds case A_SPDIF_96000: 6141da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 6151da177e4SLinus Torvalds break; 6161da177e4SLinus Torvalds default: 6171da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 6201da177e4SLinus Torvalds return 0; 6211da177e4SLinus Torvalds } 6221da177e4SLinus Torvalds 623eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, 624eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 6251da177e4SLinus Torvalds { 626eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6271da177e4SLinus Torvalds int change; 6281da177e4SLinus Torvalds unsigned int reg, val, tmp; 6291da177e4SLinus Torvalds unsigned long flags; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds switch(ucontrol->value.enumerated.item[0]) { 6321da177e4SLinus Torvalds case 0: 6331da177e4SLinus Torvalds val = A_SPDIF_44100; 6341da177e4SLinus Torvalds break; 6351da177e4SLinus Torvalds case 1: 6361da177e4SLinus Torvalds val = A_SPDIF_48000; 6371da177e4SLinus Torvalds break; 6381da177e4SLinus Torvalds case 2: 6391da177e4SLinus Torvalds val = A_SPDIF_96000; 6401da177e4SLinus Torvalds break; 6411da177e4SLinus Torvalds default: 6421da177e4SLinus Torvalds val = A_SPDIF_48000; 6431da177e4SLinus Torvalds break; 6441da177e4SLinus Torvalds } 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds 6471da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 6481da177e4SLinus Torvalds reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 6491da177e4SLinus Torvalds tmp = reg & ~A_SPDIF_RATE_MASK; 6501da177e4SLinus Torvalds tmp |= val; 6511da177e4SLinus Torvalds if ((change = (tmp != reg))) 6521da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); 6531da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 6541da177e4SLinus Torvalds return change; 6551da177e4SLinus Torvalds } 6561da177e4SLinus Torvalds 657eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_spdif_output_rate = 6581da177e4SLinus Torvalds { 6591da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 6601da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 6611da177e4SLinus Torvalds .name = "Audigy SPDIF Output Sample Rate", 6621da177e4SLinus Torvalds .count = 1, 6631da177e4SLinus Torvalds .info = snd_audigy_spdif_output_rate_info, 6641da177e4SLinus Torvalds .get = snd_audigy_spdif_output_rate_get, 6651da177e4SLinus Torvalds .put = snd_audigy_spdif_output_rate_put 6661da177e4SLinus Torvalds }; 6670af68e5eSTakashi Iwai #endif 6681da177e4SLinus Torvalds 669eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, 670eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 6711da177e4SLinus Torvalds { 672eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6731da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 6741da177e4SLinus Torvalds int change; 6751da177e4SLinus Torvalds unsigned int val; 6761da177e4SLinus Torvalds unsigned long flags; 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 6791da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 6801da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 6811da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 6821da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 6831da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 6841da177e4SLinus Torvalds if (change) { 6851da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); 6861da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 6891da177e4SLinus Torvalds return change; 6901da177e4SLinus Torvalds } 6911da177e4SLinus Torvalds 692eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = 6931da177e4SLinus Torvalds { 6941da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 6955549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 6961da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 6971da177e4SLinus Torvalds .count = 4, 6981da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 6991da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get_mask 7001da177e4SLinus Torvalds }; 7011da177e4SLinus Torvalds 702eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_control = 7031da177e4SLinus Torvalds { 7045549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 7051da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 7061da177e4SLinus Torvalds .count = 4, 7071da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 7081da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get, 7091da177e4SLinus Torvalds .put = snd_emu10k1_spdif_put 7101da177e4SLinus Torvalds }; 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds 713eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route) 7141da177e4SLinus Torvalds { 7151da177e4SLinus Torvalds if (emu->audigy) { 7161da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT1, voice, 7171da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt1(route)); 7181da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 7191da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt2(route)); 7201da177e4SLinus Torvalds } else { 7211da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXRT, voice, 7221da177e4SLinus Torvalds snd_emu10k1_compose_send_routing(route)); 7231da177e4SLinus Torvalds } 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds 726eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume) 7271da177e4SLinus Torvalds { 7281da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); 7291da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); 7301da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); 7311da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); 7321da177e4SLinus Torvalds if (emu->audigy) { 7331da177e4SLinus Torvalds unsigned int val = ((unsigned int)volume[4] << 24) | 7341da177e4SLinus Torvalds ((unsigned int)volume[5] << 16) | 7351da177e4SLinus Torvalds ((unsigned int)volume[6] << 8) | 7361da177e4SLinus Torvalds (unsigned int)volume[7]; 7371da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val); 7381da177e4SLinus Torvalds } 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds /* PCM stream controls */ 7421da177e4SLinus Torvalds 743eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 7441da177e4SLinus Torvalds { 745eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 7461da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 7471da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 7481da177e4SLinus Torvalds uinfo->value.integer.min = 0; 7491da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 7501da177e4SLinus Torvalds return 0; 7511da177e4SLinus Torvalds } 7521da177e4SLinus Torvalds 753eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, 754eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 7551da177e4SLinus Torvalds { 7561da177e4SLinus Torvalds unsigned long flags; 757eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 758eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 759eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 7601da177e4SLinus Torvalds int voice, idx; 7611da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 7621da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 7651da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 7661da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 7671da177e4SLinus Torvalds ucontrol->value.integer.value[(voice * num_efx) + idx] = 7681da177e4SLinus Torvalds mix->send_routing[voice][idx] & mask; 7691da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 7701da177e4SLinus Torvalds return 0; 7711da177e4SLinus Torvalds } 7721da177e4SLinus Torvalds 773eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, 774eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 7751da177e4SLinus Torvalds { 7761da177e4SLinus Torvalds unsigned long flags; 777eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 778eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 779eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 7801da177e4SLinus Torvalds int change = 0, voice, idx, val; 7811da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 7821da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 7851da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 7861da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 7871da177e4SLinus Torvalds val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; 7881da177e4SLinus Torvalds if (mix->send_routing[voice][idx] != val) { 7891da177e4SLinus Torvalds mix->send_routing[voice][idx] = val; 7901da177e4SLinus Torvalds change = 1; 7911da177e4SLinus Torvalds } 7921da177e4SLinus Torvalds } 7931da177e4SLinus Torvalds if (change && mix->epcm) { 7941da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 7951da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 7961da177e4SLinus Torvalds &mix->send_routing[1][0]); 7971da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, 7981da177e4SLinus Torvalds &mix->send_routing[2][0]); 7991da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 8001da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 8011da177e4SLinus Torvalds &mix->send_routing[0][0]); 8021da177e4SLinus Torvalds } 8031da177e4SLinus Torvalds } 8041da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 8051da177e4SLinus Torvalds return change; 8061da177e4SLinus Torvalds } 8071da177e4SLinus Torvalds 808eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_routing_control = 8091da177e4SLinus Torvalds { 8101da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 81167ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8121da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Routing", 8131da177e4SLinus Torvalds .count = 32, 8141da177e4SLinus Torvalds .info = snd_emu10k1_send_routing_info, 8151da177e4SLinus Torvalds .get = snd_emu10k1_send_routing_get, 8161da177e4SLinus Torvalds .put = snd_emu10k1_send_routing_put 8171da177e4SLinus Torvalds }; 8181da177e4SLinus Torvalds 819eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 8201da177e4SLinus Torvalds { 821eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 8221da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 8231da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 8241da177e4SLinus Torvalds uinfo->value.integer.min = 0; 8251da177e4SLinus Torvalds uinfo->value.integer.max = 255; 8261da177e4SLinus Torvalds return 0; 8271da177e4SLinus Torvalds } 8281da177e4SLinus Torvalds 829eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, 830eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 8311da177e4SLinus Torvalds { 8321da177e4SLinus Torvalds unsigned long flags; 833eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 834eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 835eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 8361da177e4SLinus Torvalds int idx; 8371da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 8401da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) 8411da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; 8421da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 8431da177e4SLinus Torvalds return 0; 8441da177e4SLinus Torvalds } 8451da177e4SLinus Torvalds 846eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, 847eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 8481da177e4SLinus Torvalds { 8491da177e4SLinus Torvalds unsigned long flags; 850eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 851eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 852eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 8531da177e4SLinus Torvalds int change = 0, idx, val; 8541da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 8551da177e4SLinus Torvalds 8561da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 8571da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) { 8581da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 8591da177e4SLinus Torvalds if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { 8601da177e4SLinus Torvalds mix->send_volume[idx/num_efx][idx%num_efx] = val; 8611da177e4SLinus Torvalds change = 1; 8621da177e4SLinus Torvalds } 8631da177e4SLinus Torvalds } 8641da177e4SLinus Torvalds if (change && mix->epcm) { 8651da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 8661da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 8671da177e4SLinus Torvalds &mix->send_volume[1][0]); 8681da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, 8691da177e4SLinus Torvalds &mix->send_volume[2][0]); 8701da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 8711da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 8721da177e4SLinus Torvalds &mix->send_volume[0][0]); 8731da177e4SLinus Torvalds } 8741da177e4SLinus Torvalds } 8751da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 8761da177e4SLinus Torvalds return change; 8771da177e4SLinus Torvalds } 8781da177e4SLinus Torvalds 879eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_volume_control = 8801da177e4SLinus Torvalds { 8811da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 88267ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8831da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Volume", 8841da177e4SLinus Torvalds .count = 32, 8851da177e4SLinus Torvalds .info = snd_emu10k1_send_volume_info, 8861da177e4SLinus Torvalds .get = snd_emu10k1_send_volume_get, 8871da177e4SLinus Torvalds .put = snd_emu10k1_send_volume_put 8881da177e4SLinus Torvalds }; 8891da177e4SLinus Torvalds 890eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 8911da177e4SLinus Torvalds { 8921da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 8931da177e4SLinus Torvalds uinfo->count = 3; 8941da177e4SLinus Torvalds uinfo->value.integer.min = 0; 8951da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 8961da177e4SLinus Torvalds return 0; 8971da177e4SLinus Torvalds } 8981da177e4SLinus Torvalds 899eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, 900eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9011da177e4SLinus Torvalds { 902eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 903eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 904eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 9051da177e4SLinus Torvalds unsigned long flags; 9061da177e4SLinus Torvalds int idx; 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 9091da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) 9101da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->attn[idx]; 9111da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 9121da177e4SLinus Torvalds return 0; 9131da177e4SLinus Torvalds } 9141da177e4SLinus Torvalds 915eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, 916eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9171da177e4SLinus Torvalds { 9181da177e4SLinus Torvalds unsigned long flags; 919eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 920eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 921eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 9221da177e4SLinus Torvalds int change = 0, idx, val; 9231da177e4SLinus Torvalds 9241da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 9251da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) { 9261da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 0xffff; 9271da177e4SLinus Torvalds if (mix->attn[idx] != val) { 9281da177e4SLinus Torvalds mix->attn[idx] = val; 9291da177e4SLinus Torvalds change = 1; 9301da177e4SLinus Torvalds } 9311da177e4SLinus Torvalds } 9321da177e4SLinus Torvalds if (change && mix->epcm) { 9331da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 9341da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); 9351da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); 9361da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 9371da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); 9381da177e4SLinus Torvalds } 9391da177e4SLinus Torvalds } 9401da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 9411da177e4SLinus Torvalds return change; 9421da177e4SLinus Torvalds } 9431da177e4SLinus Torvalds 944eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_attn_control = 9451da177e4SLinus Torvalds { 9461da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 94767ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 9481da177e4SLinus Torvalds .name = "EMU10K1 PCM Volume", 9491da177e4SLinus Torvalds .count = 32, 9501da177e4SLinus Torvalds .info = snd_emu10k1_attn_info, 9511da177e4SLinus Torvalds .get = snd_emu10k1_attn_get, 9521da177e4SLinus Torvalds .put = snd_emu10k1_attn_put 9531da177e4SLinus Torvalds }; 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds /* Mutichannel PCM stream controls */ 9561da177e4SLinus Torvalds 957eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 9581da177e4SLinus Torvalds { 959eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9601da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 9611da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 9621da177e4SLinus Torvalds uinfo->value.integer.min = 0; 9631da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 9641da177e4SLinus Torvalds return 0; 9651da177e4SLinus Torvalds } 9661da177e4SLinus Torvalds 967eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, 968eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9691da177e4SLinus Torvalds { 9701da177e4SLinus Torvalds unsigned long flags; 971eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 972eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 973eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 9741da177e4SLinus Torvalds int idx; 9751da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 9761da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 9791da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 9801da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = 9811da177e4SLinus Torvalds mix->send_routing[0][idx] & mask; 9821da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 9831da177e4SLinus Torvalds return 0; 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds 986eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, 987eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9881da177e4SLinus Torvalds { 9891da177e4SLinus Torvalds unsigned long flags; 990eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9911da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 992eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 9931da177e4SLinus Torvalds int change = 0, idx, val; 9941da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 9951da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 9961da177e4SLinus Torvalds 9971da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 9981da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 9991da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & mask; 10001da177e4SLinus Torvalds if (mix->send_routing[0][idx] != val) { 10011da177e4SLinus Torvalds mix->send_routing[0][idx] = val; 10021da177e4SLinus Torvalds change = 1; 10031da177e4SLinus Torvalds } 10041da177e4SLinus Torvalds } 10051da177e4SLinus Torvalds 10061da177e4SLinus Torvalds if (change && mix->epcm) { 10071da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 10081da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, 10091da177e4SLinus Torvalds &mix->send_routing[0][0]); 10101da177e4SLinus Torvalds } 10111da177e4SLinus Torvalds } 10121da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 10131da177e4SLinus Torvalds return change; 10141da177e4SLinus Torvalds } 10151da177e4SLinus Torvalds 1016eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = 10171da177e4SLinus Torvalds { 10181da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 10191da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10201da177e4SLinus Torvalds .name = "Multichannel PCM Send Routing", 10211da177e4SLinus Torvalds .count = 16, 10221da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_routing_info, 10231da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_routing_get, 10241da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_routing_put 10251da177e4SLinus Torvalds }; 10261da177e4SLinus Torvalds 1027eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 10281da177e4SLinus Torvalds { 1029eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10301da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 10311da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 10321da177e4SLinus Torvalds uinfo->value.integer.min = 0; 10331da177e4SLinus Torvalds uinfo->value.integer.max = 255; 10341da177e4SLinus Torvalds return 0; 10351da177e4SLinus Torvalds } 10361da177e4SLinus Torvalds 1037eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, 1038eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10391da177e4SLinus Torvalds { 10401da177e4SLinus Torvalds unsigned long flags; 1041eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1042eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1043eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 10441da177e4SLinus Torvalds int idx; 10451da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 10461da177e4SLinus Torvalds 10471da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 10481da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 10491da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; 10501da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 10511da177e4SLinus Torvalds return 0; 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds 1054eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, 1055eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10561da177e4SLinus Torvalds { 10571da177e4SLinus Torvalds unsigned long flags; 1058eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10591da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1060eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 10611da177e4SLinus Torvalds int change = 0, idx, val; 10621da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 10631da177e4SLinus Torvalds 10641da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 10651da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 10661da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 10671da177e4SLinus Torvalds if (mix->send_volume[0][idx] != val) { 10681da177e4SLinus Torvalds mix->send_volume[0][idx] = val; 10691da177e4SLinus Torvalds change = 1; 10701da177e4SLinus Torvalds } 10711da177e4SLinus Torvalds } 10721da177e4SLinus Torvalds if (change && mix->epcm) { 10731da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 10741da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, 10751da177e4SLinus Torvalds &mix->send_volume[0][0]); 10761da177e4SLinus Torvalds } 10771da177e4SLinus Torvalds } 10781da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 10791da177e4SLinus Torvalds return change; 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds 10821da177e4SLinus Torvalds 1083eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = 10841da177e4SLinus Torvalds { 10851da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 10861da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10871da177e4SLinus Torvalds .name = "Multichannel PCM Send Volume", 10881da177e4SLinus Torvalds .count = 16, 10891da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_volume_info, 10901da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_volume_get, 10911da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_volume_put 10921da177e4SLinus Torvalds }; 10931da177e4SLinus Torvalds 1094eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 10951da177e4SLinus Torvalds { 10961da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 10971da177e4SLinus Torvalds uinfo->count = 1; 10981da177e4SLinus Torvalds uinfo->value.integer.min = 0; 10991da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 11001da177e4SLinus Torvalds return 0; 11011da177e4SLinus Torvalds } 11021da177e4SLinus Torvalds 1103eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, 1104eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11051da177e4SLinus Torvalds { 1106eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1107eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1108eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 11091da177e4SLinus Torvalds unsigned long flags; 11101da177e4SLinus Torvalds 11111da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11121da177e4SLinus Torvalds ucontrol->value.integer.value[0] = mix->attn[0]; 11131da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11141da177e4SLinus Torvalds return 0; 11151da177e4SLinus Torvalds } 11161da177e4SLinus Torvalds 1117eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, 1118eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11191da177e4SLinus Torvalds { 11201da177e4SLinus Torvalds unsigned long flags; 1121eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11221da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1123eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 11241da177e4SLinus Torvalds int change = 0, val; 11251da177e4SLinus Torvalds 11261da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11271da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] & 0xffff; 11281da177e4SLinus Torvalds if (mix->attn[0] != val) { 11291da177e4SLinus Torvalds mix->attn[0] = val; 11301da177e4SLinus Torvalds change = 1; 11311da177e4SLinus Torvalds } 11321da177e4SLinus Torvalds if (change && mix->epcm) { 11331da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 11341da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); 11351da177e4SLinus Torvalds } 11361da177e4SLinus Torvalds } 11371da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11381da177e4SLinus Torvalds return change; 11391da177e4SLinus Torvalds } 11401da177e4SLinus Torvalds 1141eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_attn_control = 11421da177e4SLinus Torvalds { 11431da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 11441da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 11451da177e4SLinus Torvalds .name = "Multichannel PCM Volume", 11461da177e4SLinus Torvalds .count = 16, 11471da177e4SLinus Torvalds .info = snd_emu10k1_efx_attn_info, 11481da177e4SLinus Torvalds .get = snd_emu10k1_efx_attn_get, 11491da177e4SLinus Torvalds .put = snd_emu10k1_efx_attn_put 11501da177e4SLinus Torvalds }; 11511da177e4SLinus Torvalds 1152eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 11531da177e4SLinus Torvalds { 11541da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 11551da177e4SLinus Torvalds uinfo->count = 1; 11561da177e4SLinus Torvalds uinfo->value.integer.min = 0; 11571da177e4SLinus Torvalds uinfo->value.integer.max = 1; 11581da177e4SLinus Torvalds return 0; 11591da177e4SLinus Torvalds } 11601da177e4SLinus Torvalds 1161eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, 1162eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11631da177e4SLinus Torvalds { 1164eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11651da177e4SLinus Torvalds 11661da177e4SLinus Torvalds if (emu->audigy) 11671da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; 11681da177e4SLinus Torvalds else 11691da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; 11701da177e4SLinus Torvalds return 0; 11711da177e4SLinus Torvalds } 11721da177e4SLinus Torvalds 1173eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, 1174eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11751da177e4SLinus Torvalds { 11761da177e4SLinus Torvalds unsigned long flags; 1177eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11781da177e4SLinus Torvalds unsigned int reg, val; 11791da177e4SLinus Torvalds int change = 0; 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11821da177e4SLinus Torvalds if (emu->audigy) { 11831da177e4SLinus Torvalds reg = inl(emu->port + A_IOCFG); 11841da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; 11851da177e4SLinus Torvalds change = (reg & A_IOCFG_GPOUT0) != val; 11861da177e4SLinus Torvalds if (change) { 11871da177e4SLinus Torvalds reg &= ~A_IOCFG_GPOUT0; 11881da177e4SLinus Torvalds reg |= val; 11891da177e4SLinus Torvalds outl(reg | val, emu->port + A_IOCFG); 11901da177e4SLinus Torvalds } 11911da177e4SLinus Torvalds } 11921da177e4SLinus Torvalds reg = inl(emu->port + HCFG); 11931da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0; 11941da177e4SLinus Torvalds change |= (reg & HCFG_GPOUT0) != val; 11951da177e4SLinus Torvalds if (change) { 11961da177e4SLinus Torvalds reg &= ~HCFG_GPOUT0; 11971da177e4SLinus Torvalds reg |= val; 11981da177e4SLinus Torvalds outl(reg | val, emu->port + HCFG); 11991da177e4SLinus Torvalds } 12001da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 12011da177e4SLinus Torvalds return change; 12021da177e4SLinus Torvalds } 12031da177e4SLinus Torvalds 1204eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata = 12051da177e4SLinus Torvalds { 12061da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 12071da177e4SLinus Torvalds .name = "SB Live Analog/Digital Output Jack", 12081da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 12091da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 12101da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 12111da177e4SLinus Torvalds }; 12121da177e4SLinus Torvalds 1213eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata = 12141da177e4SLinus Torvalds { 12151da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 12161da177e4SLinus Torvalds .name = "Audigy Analog/Digital Output Jack", 12171da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 12181da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 12191da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 12201da177e4SLinus Torvalds }; 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds /* 12231da177e4SLinus Torvalds */ 1224eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) 12251da177e4SLinus Torvalds { 1226eb4698f3STakashi Iwai struct snd_emu10k1 *emu = ac97->private_data; 12271da177e4SLinus Torvalds emu->ac97 = NULL; 12281da177e4SLinus Torvalds } 12291da177e4SLinus Torvalds 12301da177e4SLinus Torvalds /* 12311da177e4SLinus Torvalds */ 1232eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name) 12331da177e4SLinus Torvalds { 1234eb4698f3STakashi Iwai struct snd_ctl_elem_id id; 12351da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 12361da177e4SLinus Torvalds strcpy(id.name, name); 12371da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 12381da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 12391da177e4SLinus Torvalds } 12401da177e4SLinus Torvalds 1241eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) 12421da177e4SLinus Torvalds { 1243eb4698f3STakashi Iwai struct snd_ctl_elem_id sid; 12441da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 12451da177e4SLinus Torvalds strcpy(sid.name, name); 12461da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 12471da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 12481da177e4SLinus Torvalds } 12491da177e4SLinus Torvalds 1250eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst) 12511da177e4SLinus Torvalds { 1252eb4698f3STakashi Iwai struct snd_kcontrol *kctl = ctl_find(card, src); 12531da177e4SLinus Torvalds if (kctl) { 12541da177e4SLinus Torvalds strcpy(kctl->id.name, dst); 12551da177e4SLinus Torvalds return 0; 12561da177e4SLinus Torvalds } 12571da177e4SLinus Torvalds return -ENOENT; 12581da177e4SLinus Torvalds } 12591da177e4SLinus Torvalds 1260eb4698f3STakashi Iwai int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, 126167ed4161SClemens Ladisch int pcm_device, int multi_device) 12621da177e4SLinus Torvalds { 12631da177e4SLinus Torvalds int err, pcm; 1264eb4698f3STakashi Iwai struct snd_kcontrol *kctl; 1265eb4698f3STakashi Iwai struct snd_card *card = emu->card; 12661da177e4SLinus Torvalds char **c; 12671da177e4SLinus Torvalds static char *emu10k1_remove_ctls[] = { 12681da177e4SLinus Torvalds /* no AC97 mono, surround, center/lfe */ 12691da177e4SLinus Torvalds "Master Mono Playback Switch", 12701da177e4SLinus Torvalds "Master Mono Playback Volume", 12711da177e4SLinus Torvalds "PCM Out Path & Mute", 12721da177e4SLinus Torvalds "Mono Output Select", 12737eae36fbSTakashi Iwai "Front Playback Switch", 12747eae36fbSTakashi Iwai "Front Playback Volume", 12751da177e4SLinus Torvalds "Surround Playback Switch", 12761da177e4SLinus Torvalds "Surround Playback Volume", 12771da177e4SLinus Torvalds "Center Playback Switch", 12781da177e4SLinus Torvalds "Center Playback Volume", 12791da177e4SLinus Torvalds "LFE Playback Switch", 12801da177e4SLinus Torvalds "LFE Playback Volume", 12811da177e4SLinus Torvalds NULL 12821da177e4SLinus Torvalds }; 12831da177e4SLinus Torvalds static char *emu10k1_rename_ctls[] = { 12841da177e4SLinus Torvalds "Surround Digital Playback Volume", "Surround Playback Volume", 12851da177e4SLinus Torvalds "Center Digital Playback Volume", "Center Playback Volume", 12861da177e4SLinus Torvalds "LFE Digital Playback Volume", "LFE Playback Volume", 12871da177e4SLinus Torvalds NULL 12881da177e4SLinus Torvalds }; 12891da177e4SLinus Torvalds static char *audigy_remove_ctls[] = { 12901da177e4SLinus Torvalds /* Master/PCM controls on ac97 of Audigy has no effect */ 129121fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 129221fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 12931da177e4SLinus Torvalds "PCM Playback Switch", 12941da177e4SLinus Torvalds "PCM Playback Volume", 12951da177e4SLinus Torvalds "Master Mono Playback Switch", 12961da177e4SLinus Torvalds "Master Mono Playback Volume", 12971da177e4SLinus Torvalds "Master Playback Switch", 12981da177e4SLinus Torvalds "Master Playback Volume", 12991da177e4SLinus Torvalds "PCM Out Path & Mute", 13001da177e4SLinus Torvalds "Mono Output Select", 13011da177e4SLinus Torvalds /* remove unused AC97 capture controls */ 13021da177e4SLinus Torvalds "Capture Source", 13031da177e4SLinus Torvalds "Capture Switch", 13041da177e4SLinus Torvalds "Capture Volume", 13051da177e4SLinus Torvalds "Mic Select", 13061da177e4SLinus Torvalds "Video Playback Switch", 13071da177e4SLinus Torvalds "Video Playback Volume", 13081da177e4SLinus Torvalds "Mic Playback Switch", 13091da177e4SLinus Torvalds "Mic Playback Volume", 13101da177e4SLinus Torvalds NULL 13111da177e4SLinus Torvalds }; 13121da177e4SLinus Torvalds static char *audigy_rename_ctls[] = { 13131da177e4SLinus Torvalds /* use conventional names */ 13141da177e4SLinus Torvalds "Wave Playback Volume", "PCM Playback Volume", 13151da177e4SLinus Torvalds /* "Wave Capture Volume", "PCM Capture Volume", */ 13161da177e4SLinus Torvalds "Wave Master Playback Volume", "Master Playback Volume", 13171da177e4SLinus Torvalds "AMic Playback Volume", "Mic Playback Volume", 13181da177e4SLinus Torvalds NULL 13191da177e4SLinus Torvalds }; 132021fdddeaSJames Courtier-Dutton static char *audigy_remove_ctls_1361t_adc[] = { 132121fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 132221fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 132321fdddeaSJames Courtier-Dutton "PCM Playback Switch", 132421fdddeaSJames Courtier-Dutton "PCM Playback Volume", 132521fdddeaSJames Courtier-Dutton "Master Mono Playback Switch", 132621fdddeaSJames Courtier-Dutton "Master Mono Playback Volume", 132721fdddeaSJames Courtier-Dutton "Capture Source", 132821fdddeaSJames Courtier-Dutton "Capture Switch", 132921fdddeaSJames Courtier-Dutton "Capture Volume", 133021fdddeaSJames Courtier-Dutton "Mic Capture Volume", 133121fdddeaSJames Courtier-Dutton "Headphone Playback Switch", 133221fdddeaSJames Courtier-Dutton "Headphone Playback Volume", 133321fdddeaSJames Courtier-Dutton "3D Control - Center", 133421fdddeaSJames Courtier-Dutton "3D Control - Depth", 133521fdddeaSJames Courtier-Dutton "3D Control - Switch", 133621fdddeaSJames Courtier-Dutton "Line2 Playback Volume", 133721fdddeaSJames Courtier-Dutton "Line2 Capture Volume", 133821fdddeaSJames Courtier-Dutton NULL 133921fdddeaSJames Courtier-Dutton }; 134021fdddeaSJames Courtier-Dutton static char *audigy_rename_ctls_1361t_adc[] = { 134121fdddeaSJames Courtier-Dutton "Master Playback Switch", "Master Capture Switch", 134221fdddeaSJames Courtier-Dutton "Master Playback Volume", "Master Capture Volume", 134321fdddeaSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 134421fdddeaSJames Courtier-Dutton "PC Speaker Playback Switch", "PC Speaker Capture Switch", 134521fdddeaSJames Courtier-Dutton "PC Speaker Playback Volume", "PC Speaker Capture Volume", 134621fdddeaSJames Courtier-Dutton "Phone Playback Switch", "Phone Capture Switch", 134721fdddeaSJames Courtier-Dutton "Phone Playback Volume", "Phone Capture Volume", 134821fdddeaSJames Courtier-Dutton "Mic Playback Switch", "Mic Capture Switch", 134921fdddeaSJames Courtier-Dutton "Mic Playback Volume", "Mic Capture Volume", 135021fdddeaSJames Courtier-Dutton "Line Playback Switch", "Line Capture Switch", 135121fdddeaSJames Courtier-Dutton "Line Playback Volume", "Line Capture Volume", 135221fdddeaSJames Courtier-Dutton "CD Playback Switch", "CD Capture Switch", 135321fdddeaSJames Courtier-Dutton "CD Playback Volume", "CD Capture Volume", 135421fdddeaSJames Courtier-Dutton "Aux Playback Switch", "Aux Capture Switch", 135521fdddeaSJames Courtier-Dutton "Aux Playback Volume", "Aux Capture Volume", 135621fdddeaSJames Courtier-Dutton "Video Playback Switch", "Video Capture Switch", 135721fdddeaSJames Courtier-Dutton "Video Playback Volume", "Video Capture Volume", 135821fdddeaSJames Courtier-Dutton 135921fdddeaSJames Courtier-Dutton NULL 136021fdddeaSJames Courtier-Dutton }; 13611da177e4SLinus Torvalds 13622b637da5SLee Revell if (emu->card_capabilities->ac97_chip) { 1363eb4698f3STakashi Iwai struct snd_ac97_bus *pbus; 1364eb4698f3STakashi Iwai struct snd_ac97_template ac97; 1365eb4698f3STakashi Iwai static struct snd_ac97_bus_ops ops = { 13661da177e4SLinus Torvalds .write = snd_emu10k1_ac97_write, 13671da177e4SLinus Torvalds .read = snd_emu10k1_ac97_read, 13681da177e4SLinus Torvalds }; 13691da177e4SLinus Torvalds 1370b1508693STakashi Iwai if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0) 13711da177e4SLinus Torvalds return err; 13721da177e4SLinus Torvalds pbus->no_vra = 1; /* we don't need VRA */ 13731da177e4SLinus Torvalds 13741da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97)); 13751da177e4SLinus Torvalds ac97.private_data = emu; 13761da177e4SLinus Torvalds ac97.private_free = snd_emu10k1_mixer_free_ac97; 13771da177e4SLinus Torvalds ac97.scaps = AC97_SCAP_NO_SPDIF; 1378b1508693STakashi Iwai if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) { 1379b1508693STakashi Iwai if (emu->card_capabilities->ac97_chip == 1) 13801da177e4SLinus Torvalds return err; 1381b1508693STakashi Iwai snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n"); 1382b1508693STakashi Iwai snd_printd(KERN_INFO" Proceeding without ac97 mixers...\n"); 1383b1508693STakashi Iwai snd_device_free(emu->card, pbus); 1384b1508693STakashi Iwai goto no_ac97; /* FIXME: get rid of ugly gotos.. */ 1385b1508693STakashi Iwai } 13861da177e4SLinus Torvalds if (emu->audigy) { 13871da177e4SLinus Torvalds /* set master volume to 0 dB */ 13884d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); 13891da177e4SLinus Torvalds /* set capture source to mic */ 13904d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); 139121fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 139221fdddeaSJames Courtier-Dutton c = audigy_remove_ctls_1361t_adc; 139321fdddeaSJames Courtier-Dutton else 13941da177e4SLinus Torvalds c = audigy_remove_ctls; 13951da177e4SLinus Torvalds } else { 13961da177e4SLinus Torvalds /* 13971da177e4SLinus Torvalds * Credits for cards based on STAC9758: 13981da177e4SLinus Torvalds * James Courtier-Dutton <James@superbug.demon.co.uk> 13991da177e4SLinus Torvalds * Voluspa <voluspa@comhem.se> 14001da177e4SLinus Torvalds */ 14011da177e4SLinus Torvalds if (emu->ac97->id == AC97_ID_STAC9758) { 14021da177e4SLinus Torvalds emu->rear_ac97 = 1; 14031da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); 14041da177e4SLinus Torvalds } 14051da177e4SLinus Torvalds /* remove unused AC97 controls */ 14064d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); 14074d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); 14081da177e4SLinus Torvalds c = emu10k1_remove_ctls; 14091da177e4SLinus Torvalds } 14101da177e4SLinus Torvalds for (; *c; c++) 14111da177e4SLinus Torvalds remove_ctl(card, *c); 14121da177e4SLinus Torvalds } else { 1413f12aa40cSTakashi Iwai no_ac97: 14142b637da5SLee Revell if (emu->card_capabilities->ecard) 14151da177e4SLinus Torvalds strcpy(emu->card->mixername, "EMU APS"); 14161da177e4SLinus Torvalds else if (emu->audigy) 14171da177e4SLinus Torvalds strcpy(emu->card->mixername, "SB Audigy"); 14181da177e4SLinus Torvalds else 14191da177e4SLinus Torvalds strcpy(emu->card->mixername, "Emu10k1"); 14201da177e4SLinus Torvalds } 14211da177e4SLinus Torvalds 14221da177e4SLinus Torvalds if (emu->audigy) 142321fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 142421fdddeaSJames Courtier-Dutton c = audigy_rename_ctls_1361t_adc; 142521fdddeaSJames Courtier-Dutton else 14261da177e4SLinus Torvalds c = audigy_rename_ctls; 14271da177e4SLinus Torvalds else 14281da177e4SLinus Torvalds c = emu10k1_rename_ctls; 14291da177e4SLinus Torvalds for (; *c; c += 2) 14301da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 143121fdddeaSJames Courtier-Dutton 1432e3b9bc0eSJames Courtier-Dutton if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ 1433e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); 1434e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); 1435e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); 1436e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); 1437e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "Headphone Playback Switch"); 1438e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "Headphone Playback Volume"); 1439e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "3D Control - Center"); 1440e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "3D Control - Depth"); 1441e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "3D Control - Switch"); 1442e3b9bc0eSJames Courtier-Dutton } 14431da177e4SLinus Torvalds if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) 14441da177e4SLinus Torvalds return -ENOMEM; 144567ed4161SClemens Ladisch kctl->id.device = pcm_device; 14461da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 14471da177e4SLinus Torvalds return err; 14481da177e4SLinus Torvalds if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL) 14491da177e4SLinus Torvalds return -ENOMEM; 145067ed4161SClemens Ladisch kctl->id.device = pcm_device; 14511da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 14521da177e4SLinus Torvalds return err; 14531da177e4SLinus Torvalds if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL) 14541da177e4SLinus Torvalds return -ENOMEM; 145567ed4161SClemens Ladisch kctl->id.device = pcm_device; 14561da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 14571da177e4SLinus Torvalds return err; 14581da177e4SLinus Torvalds 14591da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL) 14601da177e4SLinus Torvalds return -ENOMEM; 146167ed4161SClemens Ladisch kctl->id.device = multi_device; 14621da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 14631da177e4SLinus Torvalds return err; 14641da177e4SLinus Torvalds 14651da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL) 14661da177e4SLinus Torvalds return -ENOMEM; 146767ed4161SClemens Ladisch kctl->id.device = multi_device; 14681da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 14691da177e4SLinus Torvalds return err; 14701da177e4SLinus Torvalds 14711da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL) 14721da177e4SLinus Torvalds return -ENOMEM; 147367ed4161SClemens Ladisch kctl->id.device = multi_device; 14741da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 14751da177e4SLinus Torvalds return err; 14761da177e4SLinus Torvalds 14771da177e4SLinus Torvalds /* initialize the routing and volume table for each pcm playback stream */ 14781da177e4SLinus Torvalds for (pcm = 0; pcm < 32; pcm++) { 1479eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 14801da177e4SLinus Torvalds int v; 14811da177e4SLinus Torvalds 14821da177e4SLinus Torvalds mix = &emu->pcm_mixer[pcm]; 14831da177e4SLinus Torvalds mix->epcm = NULL; 14841da177e4SLinus Torvalds 14851da177e4SLinus Torvalds for (v = 0; v < 4; v++) 14861da177e4SLinus Torvalds mix->send_routing[0][v] = 14871da177e4SLinus Torvalds mix->send_routing[1][v] = 14881da177e4SLinus Torvalds mix->send_routing[2][v] = v; 14891da177e4SLinus Torvalds 14901da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 14911da177e4SLinus Torvalds mix->send_volume[0][0] = mix->send_volume[0][1] = 14921da177e4SLinus Torvalds mix->send_volume[1][0] = mix->send_volume[2][1] = 255; 14931da177e4SLinus Torvalds 14941da177e4SLinus Torvalds mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; 14951da177e4SLinus Torvalds } 14961da177e4SLinus Torvalds 14971da177e4SLinus Torvalds /* initialize the routing and volume table for the multichannel playback stream */ 14981da177e4SLinus Torvalds for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) { 1499eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 15001da177e4SLinus Torvalds int v; 15011da177e4SLinus Torvalds 15021da177e4SLinus Torvalds mix = &emu->efx_pcm_mixer[pcm]; 15031da177e4SLinus Torvalds mix->epcm = NULL; 15041da177e4SLinus Torvalds 15051da177e4SLinus Torvalds mix->send_routing[0][0] = pcm; 15061da177e4SLinus Torvalds mix->send_routing[0][1] = (pcm == 0) ? 1 : 0; 15071da177e4SLinus Torvalds for (v = 0; v < 2; v++) 15081da177e4SLinus Torvalds mix->send_routing[0][2+v] = 13+v; 15091da177e4SLinus Torvalds if (emu->audigy) 15101da177e4SLinus Torvalds for (v = 0; v < 4; v++) 15111da177e4SLinus Torvalds mix->send_routing[0][4+v] = 60+v; 15121da177e4SLinus Torvalds 15131da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 15141da177e4SLinus Torvalds mix->send_volume[0][0] = 255; 15151da177e4SLinus Torvalds 15161da177e4SLinus Torvalds mix->attn[0] = 0xffff; 15171da177e4SLinus Torvalds } 15181da177e4SLinus Torvalds 15192b637da5SLee Revell if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */ 15201da177e4SLinus Torvalds /* sb live! and audigy */ 15211da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) 15221da177e4SLinus Torvalds return -ENOMEM; 15235549d549SClemens Ladisch if (!emu->audigy) 15245549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 15251da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 15261da177e4SLinus Torvalds return err; 15271da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) 15281da177e4SLinus Torvalds return -ENOMEM; 15295549d549SClemens Ladisch if (!emu->audigy) 15305549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 15311da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 15321da177e4SLinus Torvalds return err; 15331da177e4SLinus Torvalds } 15341da177e4SLinus Torvalds 15359f4bd5ddSJames Courtier-Dutton if ( emu->card_capabilities->emu1010) { 153619b99fbaSJames Courtier-Dutton ; /* Disable the snd_audigy_spdif_shared_spdif */ 153719b99fbaSJames Courtier-Dutton } else if (emu->audigy) { 15381da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) 15391da177e4SLinus Torvalds return -ENOMEM; 15401da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 15411da177e4SLinus Torvalds return err; 1542001f7589SJames Courtier-Dutton #if 0 15431da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) 15441da177e4SLinus Torvalds return -ENOMEM; 15451da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 15461da177e4SLinus Torvalds return err; 1547001f7589SJames Courtier-Dutton #endif 15482b637da5SLee Revell } else if (! emu->card_capabilities->ecard) { 15491da177e4SLinus Torvalds /* sb live! */ 15501da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) 15511da177e4SLinus Torvalds return -ENOMEM; 15521da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 15531da177e4SLinus Torvalds return err; 15541da177e4SLinus Torvalds } 15552b637da5SLee Revell if (emu->card_capabilities->ca0151_chip) { /* P16V */ 15561da177e4SLinus Torvalds if ((err = snd_p16v_mixer(emu))) 15571da177e4SLinus Torvalds return err; 15581da177e4SLinus Torvalds } 15591da177e4SLinus Torvalds 15609f4bd5ddSJames Courtier-Dutton if ( emu->card_capabilities->emu1010) { 15619f4bd5ddSJames Courtier-Dutton int i; 15629f4bd5ddSJames Courtier-Dutton 15639f4bd5ddSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { 15649f4bd5ddSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu)); 15659f4bd5ddSJames Courtier-Dutton if (err < 0) 15669f4bd5ddSJames Courtier-Dutton return err; 15679f4bd5ddSJames Courtier-Dutton } 15689f4bd5ddSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { 15699f4bd5ddSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu)); 15709f4bd5ddSJames Courtier-Dutton if (err < 0) 15719f4bd5ddSJames Courtier-Dutton return err; 15729f4bd5ddSJames Courtier-Dutton } 15739148cc50SJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { 15749148cc50SJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); 15759148cc50SJames Courtier-Dutton if (err < 0) 15769148cc50SJames Courtier-Dutton return err; 15779148cc50SJames Courtier-Dutton } 15789148cc50SJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { 15799148cc50SJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); 15809148cc50SJames Courtier-Dutton if (err < 0) 15819148cc50SJames Courtier-Dutton return err; 15829148cc50SJames Courtier-Dutton } 1583*b0dbdaeaSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 1584*b0dbdaeaSJames Courtier-Dutton if (err < 0) 1585*b0dbdaeaSJames Courtier-Dutton return err; 15869f4bd5ddSJames Courtier-Dutton } 15879f4bd5ddSJames Courtier-Dutton 15881da177e4SLinus Torvalds return 0; 15891da177e4SLinus Torvalds } 1590