11da177e4SLinus Torvalds /* 2c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, 31da177e4SLinus Torvalds * Takashi Iwai <tiwai@suse.de> 41da177e4SLinus Torvalds * Creative Labs, Inc. 51da177e4SLinus Torvalds * Routines for control of EMU10K1 chips / mixer routines 61da177e4SLinus Torvalds * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> 71da177e4SLinus Torvalds * 89f4bd5ddSJames Courtier-Dutton * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> 99f4bd5ddSJames Courtier-Dutton * Added EMU 1010 support. 109f4bd5ddSJames Courtier-Dutton * 111da177e4SLinus Torvalds * BUGS: 121da177e4SLinus Torvalds * -- 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * TODO: 151da177e4SLinus Torvalds * -- 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 181da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 191da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 201da177e4SLinus Torvalds * (at your option) any later version. 211da177e4SLinus Torvalds * 221da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 231da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 241da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 251da177e4SLinus Torvalds * GNU General Public License for more details. 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 281da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 291da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds */ 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds #include <linux/time.h> 341da177e4SLinus Torvalds #include <linux/init.h> 351da177e4SLinus Torvalds #include <sound/core.h> 361da177e4SLinus Torvalds #include <sound/emu10k1.h> 37b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h> 38184c1e2cSJames Courtier-Dutton #include <sound/tlv.h> 39184c1e2cSJames Courtier-Dutton 40184c1e2cSJames Courtier-Dutton #include "p17v.h" 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds #define AC97_ID_STAC9758 0x83847658 431da177e4SLinus Torvalds 440cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ 45184c1e2cSJames Courtier-Dutton 46eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 471da177e4SLinus Torvalds { 481da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 491da177e4SLinus Torvalds uinfo->count = 1; 501da177e4SLinus Torvalds return 0; 511da177e4SLinus Torvalds } 521da177e4SLinus Torvalds 53eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol, 54eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 551da177e4SLinus Torvalds { 56eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 571da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 581da177e4SLinus Torvalds unsigned long flags; 591da177e4SLinus Torvalds 6074415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 6174415a36SJames Courtier-Dutton if (idx >= 3) 6274415a36SJames Courtier-Dutton return -EINVAL; 631da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 641da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 651da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 661da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 671da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 681da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 691da177e4SLinus Torvalds return 0; 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 72eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, 73eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 741da177e4SLinus Torvalds { 751da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = 0xff; 761da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = 0xff; 771da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = 0xff; 781da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = 0xff; 791da177e4SLinus Torvalds return 0; 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 8213d45709SPavel Hofman /* 8313d45709SPavel Hofman * Items labels in enum mixer controls assigning source data to 8413d45709SPavel Hofman * each destination 8513d45709SPavel Hofman */ 861541c66dSTakashi Iwai static const char * const emu1010_src_texts[] = { 879f4bd5ddSJames Courtier-Dutton "Silence", 889f4bd5ddSJames Courtier-Dutton "Dock Mic A", 899f4bd5ddSJames Courtier-Dutton "Dock Mic B", 909f4bd5ddSJames Courtier-Dutton "Dock ADC1 Left", 919f4bd5ddSJames Courtier-Dutton "Dock ADC1 Right", 929f4bd5ddSJames Courtier-Dutton "Dock ADC2 Left", 939f4bd5ddSJames Courtier-Dutton "Dock ADC2 Right", 949f4bd5ddSJames Courtier-Dutton "Dock ADC3 Left", 959f4bd5ddSJames Courtier-Dutton "Dock ADC3 Right", 969f4bd5ddSJames Courtier-Dutton "0202 ADC Left", 979f4bd5ddSJames Courtier-Dutton "0202 ADC Right", 989f4bd5ddSJames Courtier-Dutton "0202 SPDIF Left", 999f4bd5ddSJames Courtier-Dutton "0202 SPDIF Right", 1009f4bd5ddSJames Courtier-Dutton "ADAT 0", 1019f4bd5ddSJames Courtier-Dutton "ADAT 1", 1029f4bd5ddSJames Courtier-Dutton "ADAT 2", 1039f4bd5ddSJames Courtier-Dutton "ADAT 3", 1049f4bd5ddSJames Courtier-Dutton "ADAT 4", 1059f4bd5ddSJames Courtier-Dutton "ADAT 5", 1069f4bd5ddSJames Courtier-Dutton "ADAT 6", 1079f4bd5ddSJames Courtier-Dutton "ADAT 7", 1089f4bd5ddSJames Courtier-Dutton "DSP 0", 1099f4bd5ddSJames Courtier-Dutton "DSP 1", 1109f4bd5ddSJames Courtier-Dutton "DSP 2", 1119f4bd5ddSJames Courtier-Dutton "DSP 3", 1129f4bd5ddSJames Courtier-Dutton "DSP 4", 1139f4bd5ddSJames Courtier-Dutton "DSP 5", 1149f4bd5ddSJames Courtier-Dutton "DSP 6", 1159f4bd5ddSJames Courtier-Dutton "DSP 7", 1169f4bd5ddSJames Courtier-Dutton "DSP 8", 1179f4bd5ddSJames Courtier-Dutton "DSP 9", 1189f4bd5ddSJames Courtier-Dutton "DSP 10", 1199f4bd5ddSJames Courtier-Dutton "DSP 11", 1209f4bd5ddSJames Courtier-Dutton "DSP 12", 1219f4bd5ddSJames Courtier-Dutton "DSP 13", 1229f4bd5ddSJames Courtier-Dutton "DSP 14", 1239f4bd5ddSJames Courtier-Dutton "DSP 15", 1249f4bd5ddSJames Courtier-Dutton "DSP 16", 1259f4bd5ddSJames Courtier-Dutton "DSP 17", 1269f4bd5ddSJames Courtier-Dutton "DSP 18", 1279f4bd5ddSJames Courtier-Dutton "DSP 19", 1289f4bd5ddSJames Courtier-Dutton "DSP 20", 1299f4bd5ddSJames Courtier-Dutton "DSP 21", 1309f4bd5ddSJames Courtier-Dutton "DSP 22", 1319f4bd5ddSJames Courtier-Dutton "DSP 23", 1329f4bd5ddSJames Courtier-Dutton "DSP 24", 1339f4bd5ddSJames Courtier-Dutton "DSP 25", 1349f4bd5ddSJames Courtier-Dutton "DSP 26", 1359f4bd5ddSJames Courtier-Dutton "DSP 27", 1369f4bd5ddSJames Courtier-Dutton "DSP 28", 1379f4bd5ddSJames Courtier-Dutton "DSP 29", 1389f4bd5ddSJames Courtier-Dutton "DSP 30", 1399f4bd5ddSJames Courtier-Dutton "DSP 31", 1409f4bd5ddSJames Courtier-Dutton }; 1419f4bd5ddSJames Courtier-Dutton 1421c02e366SCtirad Fertr /* 1616(m) cardbus */ 1431c02e366SCtirad Fertr 1441541c66dSTakashi Iwai static const char * const emu1616_src_texts[] = { 1451c02e366SCtirad Fertr "Silence", 1461c02e366SCtirad Fertr "Dock Mic A", 1471c02e366SCtirad Fertr "Dock Mic B", 1481c02e366SCtirad Fertr "Dock ADC1 Left", 1491c02e366SCtirad Fertr "Dock ADC1 Right", 1501c02e366SCtirad Fertr "Dock ADC2 Left", 1511c02e366SCtirad Fertr "Dock ADC2 Right", 1521c02e366SCtirad Fertr "Dock SPDIF Left", 1531c02e366SCtirad Fertr "Dock SPDIF Right", 1541c02e366SCtirad Fertr "ADAT 0", 1551c02e366SCtirad Fertr "ADAT 1", 1561c02e366SCtirad Fertr "ADAT 2", 1571c02e366SCtirad Fertr "ADAT 3", 1581c02e366SCtirad Fertr "ADAT 4", 1591c02e366SCtirad Fertr "ADAT 5", 1601c02e366SCtirad Fertr "ADAT 6", 1611c02e366SCtirad Fertr "ADAT 7", 1621c02e366SCtirad Fertr "DSP 0", 1631c02e366SCtirad Fertr "DSP 1", 1641c02e366SCtirad Fertr "DSP 2", 1651c02e366SCtirad Fertr "DSP 3", 1661c02e366SCtirad Fertr "DSP 4", 1671c02e366SCtirad Fertr "DSP 5", 1681c02e366SCtirad Fertr "DSP 6", 1691c02e366SCtirad Fertr "DSP 7", 1701c02e366SCtirad Fertr "DSP 8", 1711c02e366SCtirad Fertr "DSP 9", 1721c02e366SCtirad Fertr "DSP 10", 1731c02e366SCtirad Fertr "DSP 11", 1741c02e366SCtirad Fertr "DSP 12", 1751c02e366SCtirad Fertr "DSP 13", 1761c02e366SCtirad Fertr "DSP 14", 1771c02e366SCtirad Fertr "DSP 15", 1781c02e366SCtirad Fertr "DSP 16", 1791c02e366SCtirad Fertr "DSP 17", 1801c02e366SCtirad Fertr "DSP 18", 1811c02e366SCtirad Fertr "DSP 19", 1821c02e366SCtirad Fertr "DSP 20", 1831c02e366SCtirad Fertr "DSP 21", 1841c02e366SCtirad Fertr "DSP 22", 1851c02e366SCtirad Fertr "DSP 23", 1861c02e366SCtirad Fertr "DSP 24", 1871c02e366SCtirad Fertr "DSP 25", 1881c02e366SCtirad Fertr "DSP 26", 1891c02e366SCtirad Fertr "DSP 27", 1901c02e366SCtirad Fertr "DSP 28", 1911c02e366SCtirad Fertr "DSP 29", 1921c02e366SCtirad Fertr "DSP 30", 1931c02e366SCtirad Fertr "DSP 31", 1941c02e366SCtirad Fertr }; 1951c02e366SCtirad Fertr 1961c02e366SCtirad Fertr 19713d45709SPavel Hofman /* 19813d45709SPavel Hofman * List of data sources available for each destination 19913d45709SPavel Hofman */ 2009f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_src_regs[] = { 2019f4bd5ddSJames Courtier-Dutton EMU_SRC_SILENCE,/* 0 */ 2029f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_MIC_A1, /* 1 */ 2039f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_MIC_B1, /* 2 */ 2049f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */ 2059f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */ 2069f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */ 2079f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */ 2089f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */ 2099f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */ 2109f4bd5ddSJames Courtier-Dutton EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */ 2119f4bd5ddSJames Courtier-Dutton EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */ 2129f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */ 2139f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */ 2149f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT, /* 13 */ 2159f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+1, /* 14 */ 2169f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+2, /* 15 */ 2179f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+3, /* 16 */ 2189f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+4, /* 17 */ 2199f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+5, /* 18 */ 2209f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+6, /* 19 */ 2219f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+7, /* 20 */ 2229f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A, /* 21 */ 2239f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+1, /* 22 */ 2249f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+2, /* 23 */ 2259f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+3, /* 24 */ 2269f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+4, /* 25 */ 2279f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+5, /* 26 */ 2289f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+6, /* 27 */ 2299f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+7, /* 28 */ 2309f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+8, /* 29 */ 2319f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+9, /* 30 */ 2329f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xa, /* 31 */ 2339f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xb, /* 32 */ 2349f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xc, /* 33 */ 2359f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xd, /* 34 */ 2369f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xe, /* 35 */ 2379f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xf, /* 36 */ 2389f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B, /* 37 */ 2399f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+1, /* 38 */ 2409f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+2, /* 39 */ 2419f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+3, /* 40 */ 2429f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+4, /* 41 */ 2439f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+5, /* 42 */ 2449f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+6, /* 43 */ 2459f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+7, /* 44 */ 2469f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+8, /* 45 */ 2479f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+9, /* 46 */ 2489f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xa, /* 47 */ 2499f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xb, /* 48 */ 2509f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xc, /* 49 */ 2519f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xd, /* 50 */ 2529f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xe, /* 51 */ 2539f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ 2549f4bd5ddSJames Courtier-Dutton }; 2559f4bd5ddSJames Courtier-Dutton 2561c02e366SCtirad Fertr /* 1616(m) cardbus */ 2571c02e366SCtirad Fertr static unsigned int emu1616_src_regs[] = { 2581c02e366SCtirad Fertr EMU_SRC_SILENCE, 2591c02e366SCtirad Fertr EMU_SRC_DOCK_MIC_A1, 2601c02e366SCtirad Fertr EMU_SRC_DOCK_MIC_B1, 2611c02e366SCtirad Fertr EMU_SRC_DOCK_ADC1_LEFT1, 2621c02e366SCtirad Fertr EMU_SRC_DOCK_ADC1_RIGHT1, 2631c02e366SCtirad Fertr EMU_SRC_DOCK_ADC2_LEFT1, 2641c02e366SCtirad Fertr EMU_SRC_DOCK_ADC2_RIGHT1, 2651c02e366SCtirad Fertr EMU_SRC_MDOCK_SPDIF_LEFT1, 2661c02e366SCtirad Fertr EMU_SRC_MDOCK_SPDIF_RIGHT1, 2671c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT, 2681c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+1, 2691c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+2, 2701c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+3, 2711c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+4, 2721c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+5, 2731c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+6, 2741c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+7, 2751c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A, 2761c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+1, 2771c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+2, 2781c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+3, 2791c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+4, 2801c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+5, 2811c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+6, 2821c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+7, 2831c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+8, 2841c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+9, 2851c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xa, 2861c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xb, 2871c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xc, 2881c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xd, 2891c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xe, 2901c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xf, 2911c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B, 2921c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+1, 2931c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+2, 2941c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+3, 2951c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+4, 2961c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+5, 2971c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+6, 2981c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+7, 2991c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+8, 3001c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+9, 3011c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xa, 3021c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xb, 3031c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xc, 3041c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xd, 3051c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xe, 3061c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xf, 3071c02e366SCtirad Fertr }; 3081c02e366SCtirad Fertr 30913d45709SPavel Hofman /* 31013d45709SPavel Hofman * Data destinations - physical EMU outputs. 31113d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 31213d45709SPavel Hofman */ 3139f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_output_dst[] = { 3149f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ 3159f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ 3169f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ 3179f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ 3189f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ 3199f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ 3209f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ 3219f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ 3229f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ 3239f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ 3249f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ 3259f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ 3269f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ 3279f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ 3289f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ 3299f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ 3309f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT, /* 16 */ 3319f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+1, /* 17 */ 3329f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+2, /* 18 */ 3339f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+3, /* 19 */ 3349f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+4, /* 20 */ 3359f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+5, /* 21 */ 3369f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+6, /* 22 */ 3379f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+7, /* 23 */ 3389f4bd5ddSJames Courtier-Dutton }; 3399f4bd5ddSJames Courtier-Dutton 3401c02e366SCtirad Fertr /* 1616(m) cardbus */ 3411c02e366SCtirad Fertr static unsigned int emu1616_output_dst[] = { 3421c02e366SCtirad Fertr EMU_DST_DOCK_DAC1_LEFT1, 3431c02e366SCtirad Fertr EMU_DST_DOCK_DAC1_RIGHT1, 3441c02e366SCtirad Fertr EMU_DST_DOCK_DAC2_LEFT1, 3451c02e366SCtirad Fertr EMU_DST_DOCK_DAC2_RIGHT1, 3461c02e366SCtirad Fertr EMU_DST_DOCK_DAC3_LEFT1, 3471c02e366SCtirad Fertr EMU_DST_DOCK_DAC3_RIGHT1, 3481c02e366SCtirad Fertr EMU_DST_MDOCK_SPDIF_LEFT1, 3491c02e366SCtirad Fertr EMU_DST_MDOCK_SPDIF_RIGHT1, 3501c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT, 3511c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+1, 3521c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+2, 3531c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+3, 3541c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+4, 3551c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+5, 3561c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+6, 3571c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+7, 3581c02e366SCtirad Fertr EMU_DST_MANA_DAC_LEFT, 3591c02e366SCtirad Fertr EMU_DST_MANA_DAC_RIGHT, 3601c02e366SCtirad Fertr }; 3611c02e366SCtirad Fertr 36213d45709SPavel Hofman /* 36313d45709SPavel Hofman * Data destinations - HANA outputs going to Alice2 (audigy) for 36413d45709SPavel Hofman * capture (EMU32 + I2S links) 36513d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 36613d45709SPavel Hofman */ 3679f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_input_dst[] = { 3689f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_0, 3699f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_1, 3709f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_2, 3719f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_3, 3729f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_4, 3739f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_5, 3749f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_6, 3759f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_7, 3769f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_8, 3779f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_9, 3789f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_A, 3799f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_B, 3809f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_C, 3819f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_D, 3829f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_E, 3839f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_F, 3849f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_LEFT, 3859f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_RIGHT, 3869f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_LEFT, 3879f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_RIGHT, 3889f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_LEFT, 3899f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_RIGHT, 3909f4bd5ddSJames Courtier-Dutton }; 3919f4bd5ddSJames Courtier-Dutton 3921c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, 3931c02e366SCtirad Fertr struct snd_ctl_elem_info *uinfo) 3949f4bd5ddSJames Courtier-Dutton { 3951c02e366SCtirad Fertr struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 3961c02e366SCtirad Fertr 3971541c66dSTakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 3981541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts); 3991541c66dSTakashi Iwai else 4001541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts); 4019f4bd5ddSJames Courtier-Dutton } 4029f4bd5ddSJames Courtier-Dutton 4039f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, 4049f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4059f4bd5ddSJames Courtier-Dutton { 4069f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 40774415a36SJames Courtier-Dutton unsigned int channel; 4089f4bd5ddSJames Courtier-Dutton 4099f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 41074415a36SJames Courtier-Dutton /* Limit: emu1010_output_dst, emu->emu1010.output_source */ 4111c02e366SCtirad Fertr if (channel >= 24 || 4123839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 4133839e4f1STakashi Iwai channel >= 18)) 41474415a36SJames Courtier-Dutton return -EINVAL; 4159f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; 4169f4bd5ddSJames Courtier-Dutton return 0; 4179f4bd5ddSJames Courtier-Dutton } 4189f4bd5ddSJames Courtier-Dutton 4199f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, 4209f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4219f4bd5ddSJames Courtier-Dutton { 4229f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4239f4bd5ddSJames Courtier-Dutton unsigned int val; 42474415a36SJames Courtier-Dutton unsigned int channel; 4259f4bd5ddSJames Courtier-Dutton 426aa299d01STakashi Iwai val = ucontrol->value.enumerated.item[0]; 4271c02e366SCtirad Fertr if (val >= 53 || 4283839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 4293839e4f1STakashi Iwai val >= 49)) 430aa299d01STakashi Iwai return -EINVAL; 4319f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 43274415a36SJames Courtier-Dutton /* Limit: emu1010_output_dst, emu->emu1010.output_source */ 4331c02e366SCtirad Fertr if (channel >= 24 || 4343839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 4353839e4f1STakashi Iwai channel >= 18)) 43674415a36SJames Courtier-Dutton return -EINVAL; 4371c02e366SCtirad Fertr if (emu->emu1010.output_source[channel] == val) 4381c02e366SCtirad Fertr return 0; 439aa299d01STakashi Iwai emu->emu1010.output_source[channel] = val; 4403839e4f1STakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 4411c02e366SCtirad Fertr snd_emu1010_fpga_link_dst_src_write(emu, 4421c02e366SCtirad Fertr emu1616_output_dst[channel], emu1616_src_regs[val]); 4431c02e366SCtirad Fertr else 4449f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 4459f4bd5ddSJames Courtier-Dutton emu1010_output_dst[channel], emu1010_src_regs[val]); 4461c02e366SCtirad Fertr return 1; 4479f4bd5ddSJames Courtier-Dutton } 4489f4bd5ddSJames Courtier-Dutton 4499f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, 4509f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4519f4bd5ddSJames Courtier-Dutton { 4529f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 45374415a36SJames Courtier-Dutton unsigned int channel; 4549f4bd5ddSJames Courtier-Dutton 4559f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 45674415a36SJames Courtier-Dutton /* Limit: emu1010_input_dst, emu->emu1010.input_source */ 45774415a36SJames Courtier-Dutton if (channel >= 22) 45874415a36SJames Courtier-Dutton return -EINVAL; 4599f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; 4609f4bd5ddSJames Courtier-Dutton return 0; 4619f4bd5ddSJames Courtier-Dutton } 4629f4bd5ddSJames Courtier-Dutton 4639f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, 4649f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4659f4bd5ddSJames Courtier-Dutton { 4669f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4679f4bd5ddSJames Courtier-Dutton unsigned int val; 46874415a36SJames Courtier-Dutton unsigned int channel; 4699f4bd5ddSJames Courtier-Dutton 470aa299d01STakashi Iwai val = ucontrol->value.enumerated.item[0]; 4711c02e366SCtirad Fertr if (val >= 53 || 4723839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 4733839e4f1STakashi Iwai val >= 49)) 474aa299d01STakashi Iwai return -EINVAL; 4759f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 47674415a36SJames Courtier-Dutton /* Limit: emu1010_input_dst, emu->emu1010.input_source */ 47774415a36SJames Courtier-Dutton if (channel >= 22) 47874415a36SJames Courtier-Dutton return -EINVAL; 4791c02e366SCtirad Fertr if (emu->emu1010.input_source[channel] == val) 4801c02e366SCtirad Fertr return 0; 481aa299d01STakashi Iwai emu->emu1010.input_source[channel] = val; 4823839e4f1STakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 4831c02e366SCtirad Fertr snd_emu1010_fpga_link_dst_src_write(emu, 4841c02e366SCtirad Fertr emu1010_input_dst[channel], emu1616_src_regs[val]); 4851c02e366SCtirad Fertr else 4869f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 4879f4bd5ddSJames Courtier-Dutton emu1010_input_dst[channel], emu1010_src_regs[val]); 4881c02e366SCtirad Fertr return 1; 4899f4bd5ddSJames Courtier-Dutton } 4909f4bd5ddSJames Courtier-Dutton 4919f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \ 4929f4bd5ddSJames Courtier-Dutton { \ 4939f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 4949f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 4959f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 4969f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_output_source_get, \ 4979f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_output_source_put, \ 4989f4bd5ddSJames Courtier-Dutton .private_value = chid \ 4999f4bd5ddSJames Courtier-Dutton } 5009f4bd5ddSJames Courtier-Dutton 501e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = { 5024c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), 5034c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), 5044c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), 5054c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), 5064c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), 5074c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), 5084c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6), 5094c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7), 5104c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8), 5114c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9), 5124c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa), 5134c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb), 5144c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc), 5154c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd), 5164c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe), 5174c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf), 5184c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10), 5194c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11), 5204c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12), 5214c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13), 5224c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14), 5234c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15), 5244c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16), 5254c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), 5269f4bd5ddSJames Courtier-Dutton }; 5279f4bd5ddSJames Courtier-Dutton 5281c02e366SCtirad Fertr 5291c02e366SCtirad Fertr /* 1616(m) cardbus */ 530e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = { 5311c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), 5321c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), 5331c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), 5341c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), 5351c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), 5361c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), 5371c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6), 5381c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7), 5391c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8), 5401c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9), 5411c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa), 5421c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb), 5431c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc), 5441c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd), 5451c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe), 5461c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf), 5471c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10), 5481c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11), 5491c02e366SCtirad Fertr }; 5501c02e366SCtirad Fertr 5511c02e366SCtirad Fertr 5529f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \ 5539f4bd5ddSJames Courtier-Dutton { \ 5549f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 5559f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 5569f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 5579f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_input_source_get, \ 5589f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_input_source_put, \ 5599f4bd5ddSJames Courtier-Dutton .private_value = chid \ 5609f4bd5ddSJames Courtier-Dutton } 5619f4bd5ddSJames Courtier-Dutton 562e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = { 5634c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), 5644c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), 5654c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), 5664c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3), 5674c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4), 5684c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5), 5694c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6), 5704c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7), 5714c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8), 5724c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9), 5734c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa), 5744c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb), 5754c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc), 5764c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd), 5774c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe), 5784c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf), 5794c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10), 5804c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11), 5814c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12), 5824c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13), 5834c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14), 5844c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15), 5859148cc50SJames Courtier-Dutton }; 5869148cc50SJames Courtier-Dutton 5879148cc50SJames Courtier-Dutton 5889148cc50SJames Courtier-Dutton 589a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info 5909148cc50SJames Courtier-Dutton 5919148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5929148cc50SJames Courtier-Dutton { 5939148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 5949148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 5959148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; 5969148cc50SJames Courtier-Dutton return 0; 5979148cc50SJames Courtier-Dutton } 5989148cc50SJames Courtier-Dutton 5999148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6009148cc50SJames Courtier-Dutton { 6019148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6029148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 6039148cc50SJames Courtier-Dutton unsigned int val, cache; 6049148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 6059148cc50SJames Courtier-Dutton cache = emu->emu1010.adc_pads; 6069148cc50SJames Courtier-Dutton if (val == 1) 6079148cc50SJames Courtier-Dutton cache = cache | mask; 6089148cc50SJames Courtier-Dutton else 6099148cc50SJames Courtier-Dutton cache = cache & ~mask; 6109148cc50SJames Courtier-Dutton if (cache != emu->emu1010.adc_pads) { 6119148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); 6129148cc50SJames Courtier-Dutton emu->emu1010.adc_pads = cache; 6139148cc50SJames Courtier-Dutton } 6149148cc50SJames Courtier-Dutton 6159148cc50SJames Courtier-Dutton return 0; 6169148cc50SJames Courtier-Dutton } 6179148cc50SJames Courtier-Dutton 6189148cc50SJames Courtier-Dutton 6199148cc50SJames Courtier-Dutton 6209148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \ 6219148cc50SJames Courtier-Dutton { \ 6229148cc50SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 6239148cc50SJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 6249148cc50SJames Courtier-Dutton .info = snd_emu1010_adc_pads_info, \ 6259148cc50SJames Courtier-Dutton .get = snd_emu1010_adc_pads_get, \ 6269148cc50SJames Courtier-Dutton .put = snd_emu1010_adc_pads_put, \ 6279148cc50SJames Courtier-Dutton .private_value = chid \ 6289148cc50SJames Courtier-Dutton } 6299148cc50SJames Courtier-Dutton 630e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_emu1010_adc_pads[] = { 6319148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), 6329148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), 6339148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), 6349148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), 6359148cc50SJames Courtier-Dutton }; 6369148cc50SJames Courtier-Dutton 637a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info 6389148cc50SJames Courtier-Dutton 6399148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6409148cc50SJames Courtier-Dutton { 6419148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6429148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 6439148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; 6449148cc50SJames Courtier-Dutton return 0; 6459148cc50SJames Courtier-Dutton } 6469148cc50SJames Courtier-Dutton 6479148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6489148cc50SJames Courtier-Dutton { 6499148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6509148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 6519148cc50SJames Courtier-Dutton unsigned int val, cache; 6529148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 6539148cc50SJames Courtier-Dutton cache = emu->emu1010.dac_pads; 6549148cc50SJames Courtier-Dutton if (val == 1) 6559148cc50SJames Courtier-Dutton cache = cache | mask; 6569148cc50SJames Courtier-Dutton else 6579148cc50SJames Courtier-Dutton cache = cache & ~mask; 6589148cc50SJames Courtier-Dutton if (cache != emu->emu1010.dac_pads) { 6599148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); 6609148cc50SJames Courtier-Dutton emu->emu1010.dac_pads = cache; 6619148cc50SJames Courtier-Dutton } 6629148cc50SJames Courtier-Dutton 6639148cc50SJames Courtier-Dutton return 0; 6649148cc50SJames Courtier-Dutton } 6659148cc50SJames Courtier-Dutton 6669148cc50SJames Courtier-Dutton 6679148cc50SJames Courtier-Dutton 6689148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \ 6699148cc50SJames Courtier-Dutton { \ 6709148cc50SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 6719148cc50SJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 6729148cc50SJames Courtier-Dutton .info = snd_emu1010_dac_pads_info, \ 6739148cc50SJames Courtier-Dutton .get = snd_emu1010_dac_pads_get, \ 6749148cc50SJames Courtier-Dutton .put = snd_emu1010_dac_pads_put, \ 6759148cc50SJames Courtier-Dutton .private_value = chid \ 6769148cc50SJames Courtier-Dutton } 6779148cc50SJames Courtier-Dutton 678e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_emu1010_dac_pads[] = { 6799148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), 6809148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), 6819148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), 6829148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4), 6839148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), 6849f4bd5ddSJames Courtier-Dutton }; 6859f4bd5ddSJames Courtier-Dutton 686b0dbdaeaSJames Courtier-Dutton 687b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, 688b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 689b0dbdaeaSJames Courtier-Dutton { 6901541c66dSTakashi Iwai static const char * const texts[4] = { 691edec7bbbSJames Courtier-Dutton "44100", "48000", "SPDIF", "ADAT" 692b0dbdaeaSJames Courtier-Dutton }; 693b0dbdaeaSJames Courtier-Dutton 6941541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 4, texts); 695b0dbdaeaSJames Courtier-Dutton } 696b0dbdaeaSJames Courtier-Dutton 697b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, 698b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 699b0dbdaeaSJames Courtier-Dutton { 700b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 701b0dbdaeaSJames Courtier-Dutton 702b0dbdaeaSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; 703b0dbdaeaSJames Courtier-Dutton return 0; 704b0dbdaeaSJames Courtier-Dutton } 705b0dbdaeaSJames Courtier-Dutton 706b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, 707b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 708b0dbdaeaSJames Courtier-Dutton { 709b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 710b0dbdaeaSJames Courtier-Dutton unsigned int val; 711b0dbdaeaSJames Courtier-Dutton int change = 0; 712b0dbdaeaSJames Courtier-Dutton 713b0dbdaeaSJames Courtier-Dutton val = ucontrol->value.enumerated.item[0] ; 71474415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 4; */ 71574415a36SJames Courtier-Dutton if (val >= 4) 71674415a36SJames Courtier-Dutton return -EINVAL; 717b0dbdaeaSJames Courtier-Dutton change = (emu->emu1010.internal_clock != val); 718b0dbdaeaSJames Courtier-Dutton if (change) { 719b0dbdaeaSJames Courtier-Dutton emu->emu1010.internal_clock = val; 720b0dbdaeaSJames Courtier-Dutton switch (val) { 721b0dbdaeaSJames Courtier-Dutton case 0: 722b0dbdaeaSJames Courtier-Dutton /* 44100 */ 723b0dbdaeaSJames Courtier-Dutton /* Mute all */ 724b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 725b0dbdaeaSJames Courtier-Dutton /* Default fallback clock 48kHz */ 726b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); 727b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 44.1kHz x1 */ 728b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 729b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); 730b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 731b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 732b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); 733b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 734e40a0b2eSJames Courtier-Dutton msleep(10); 735b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 736b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 737b0dbdaeaSJames Courtier-Dutton break; 738b0dbdaeaSJames Courtier-Dutton case 1: 739b0dbdaeaSJames Courtier-Dutton /* 48000 */ 740b0dbdaeaSJames Courtier-Dutton /* Mute all */ 741b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 742b0dbdaeaSJames Courtier-Dutton /* Default fallback clock 48kHz */ 743b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 744b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 48kHz x1 */ 745b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 746b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); 747b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 748b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 749b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); 750b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 751e40a0b2eSJames Courtier-Dutton msleep(10); 752b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 753b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 754b0dbdaeaSJames Courtier-Dutton break; 755edec7bbbSJames Courtier-Dutton 756edec7bbbSJames Courtier-Dutton case 2: /* Take clock from S/PDIF IN */ 757edec7bbbSJames Courtier-Dutton /* Mute all */ 758edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 759edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 760edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 761edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to S/PDIF input */ 762edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 763edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); 764edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 765edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 766edec7bbbSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 767edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 768edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 769edec7bbbSJames Courtier-Dutton msleep(10); 770edec7bbbSJames Courtier-Dutton /* Unmute all */ 771edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 772edec7bbbSJames Courtier-Dutton break; 773edec7bbbSJames Courtier-Dutton 774edec7bbbSJames Courtier-Dutton case 3: 775edec7bbbSJames Courtier-Dutton /* Take clock from ADAT IN */ 776edec7bbbSJames Courtier-Dutton /* Mute all */ 777edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 778edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 779edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 780edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to ADAT input */ 781edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 782edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); 783edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 784edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 785edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 786edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 787edec7bbbSJames Courtier-Dutton msleep(10); 788edec7bbbSJames Courtier-Dutton /* Unmute all */ 789edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 790edec7bbbSJames Courtier-Dutton 791edec7bbbSJames Courtier-Dutton 792edec7bbbSJames Courtier-Dutton break; 793b0dbdaeaSJames Courtier-Dutton } 794b0dbdaeaSJames Courtier-Dutton } 795b0dbdaeaSJames Courtier-Dutton return change; 796b0dbdaeaSJames Courtier-Dutton } 797b0dbdaeaSJames Courtier-Dutton 798*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock = 799b0dbdaeaSJames Courtier-Dutton { 800b0dbdaeaSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 801b0dbdaeaSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 802b0dbdaeaSJames Courtier-Dutton .name = "Clock Internal Rate", 803b0dbdaeaSJames Courtier-Dutton .count = 1, 804b0dbdaeaSJames Courtier-Dutton .info = snd_emu1010_internal_clock_info, 805b0dbdaeaSJames Courtier-Dutton .get = snd_emu1010_internal_clock_get, 806b0dbdaeaSJames Courtier-Dutton .put = snd_emu1010_internal_clock_put 807b0dbdaeaSJames Courtier-Dutton }; 808b0dbdaeaSJames Courtier-Dutton 80999dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol, 81099dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 81199dcab46SMichael Gernoth { 81299dcab46SMichael Gernoth static const char * const texts[2] = { 81399dcab46SMichael Gernoth "SPDIF", "ADAT" 81499dcab46SMichael Gernoth }; 81599dcab46SMichael Gernoth 81699dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 81799dcab46SMichael Gernoth } 81899dcab46SMichael Gernoth 81999dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol, 82099dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 82199dcab46SMichael Gernoth { 82299dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 82399dcab46SMichael Gernoth 82499dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out; 82599dcab46SMichael Gernoth return 0; 82699dcab46SMichael Gernoth } 82799dcab46SMichael Gernoth 82899dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol, 82999dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 83099dcab46SMichael Gernoth { 83199dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 83299dcab46SMichael Gernoth unsigned int val; 83399dcab46SMichael Gernoth u32 tmp; 83499dcab46SMichael Gernoth int change = 0; 83599dcab46SMichael Gernoth 83699dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 83799dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 83899dcab46SMichael Gernoth if (val >= 2) 83999dcab46SMichael Gernoth return -EINVAL; 84099dcab46SMichael Gernoth change = (emu->emu1010.optical_out != val); 84199dcab46SMichael Gernoth if (change) { 84299dcab46SMichael Gernoth emu->emu1010.optical_out = val; 84399dcab46SMichael Gernoth tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | 84499dcab46SMichael Gernoth (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); 84599dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 84699dcab46SMichael Gernoth } 84799dcab46SMichael Gernoth return change; 84899dcab46SMichael Gernoth } 84999dcab46SMichael Gernoth 850*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = { 85199dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 85299dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 85399dcab46SMichael Gernoth .name = "Optical Output Mode", 85499dcab46SMichael Gernoth .count = 1, 85599dcab46SMichael Gernoth .info = snd_emu1010_optical_out_info, 85699dcab46SMichael Gernoth .get = snd_emu1010_optical_out_get, 85799dcab46SMichael Gernoth .put = snd_emu1010_optical_out_put 85899dcab46SMichael Gernoth }; 85999dcab46SMichael Gernoth 86099dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol, 86199dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 86299dcab46SMichael Gernoth { 86399dcab46SMichael Gernoth static const char * const texts[2] = { 86499dcab46SMichael Gernoth "SPDIF", "ADAT" 86599dcab46SMichael Gernoth }; 86699dcab46SMichael Gernoth 86799dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 86899dcab46SMichael Gernoth } 86999dcab46SMichael Gernoth 87099dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol, 87199dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 87299dcab46SMichael Gernoth { 87399dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 87499dcab46SMichael Gernoth 87599dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in; 87699dcab46SMichael Gernoth return 0; 87799dcab46SMichael Gernoth } 87899dcab46SMichael Gernoth 87999dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol, 88099dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 88199dcab46SMichael Gernoth { 88299dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 88399dcab46SMichael Gernoth unsigned int val; 88499dcab46SMichael Gernoth u32 tmp; 88599dcab46SMichael Gernoth int change = 0; 88699dcab46SMichael Gernoth 88799dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 88899dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 88999dcab46SMichael Gernoth if (val >= 2) 89099dcab46SMichael Gernoth return -EINVAL; 89199dcab46SMichael Gernoth change = (emu->emu1010.optical_in != val); 89299dcab46SMichael Gernoth if (change) { 89399dcab46SMichael Gernoth emu->emu1010.optical_in = val; 89499dcab46SMichael Gernoth tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | 89599dcab46SMichael Gernoth (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); 89699dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 89799dcab46SMichael Gernoth } 89899dcab46SMichael Gernoth return change; 89999dcab46SMichael Gernoth } 90099dcab46SMichael Gernoth 901*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = { 90299dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 90399dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 90499dcab46SMichael Gernoth .name = "Optical Input Mode", 90599dcab46SMichael Gernoth .count = 1, 90699dcab46SMichael Gernoth .info = snd_emu1010_optical_in_info, 90799dcab46SMichael Gernoth .get = snd_emu1010_optical_in_get, 90899dcab46SMichael Gernoth .put = snd_emu1010_optical_in_put 90999dcab46SMichael Gernoth }; 91099dcab46SMichael Gernoth 911184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, 912184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 913184c1e2cSJames Courtier-Dutton { 914184c1e2cSJames Courtier-Dutton #if 0 9151541c66dSTakashi Iwai static const char * const texts[4] = { 916184c1e2cSJames Courtier-Dutton "Unknown1", "Unknown2", "Mic", "Line" 917184c1e2cSJames Courtier-Dutton }; 918184c1e2cSJames Courtier-Dutton #endif 9191541c66dSTakashi Iwai static const char * const texts[2] = { 920184c1e2cSJames Courtier-Dutton "Mic", "Line" 921184c1e2cSJames Courtier-Dutton }; 922184c1e2cSJames Courtier-Dutton 9231541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 2, texts); 924184c1e2cSJames Courtier-Dutton } 925184c1e2cSJames Courtier-Dutton 926184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, 927184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 928184c1e2cSJames Courtier-Dutton { 929184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 930184c1e2cSJames Courtier-Dutton 931184c1e2cSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; 932184c1e2cSJames Courtier-Dutton return 0; 933184c1e2cSJames Courtier-Dutton } 934184c1e2cSJames Courtier-Dutton 935184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, 936184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 937184c1e2cSJames Courtier-Dutton { 938184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 939184c1e2cSJames Courtier-Dutton unsigned int source_id; 940184c1e2cSJames Courtier-Dutton unsigned int ngain, ogain; 941184c1e2cSJames Courtier-Dutton u32 gpio; 942184c1e2cSJames Courtier-Dutton int change = 0; 943184c1e2cSJames Courtier-Dutton unsigned long flags; 944184c1e2cSJames Courtier-Dutton u32 source; 945184c1e2cSJames Courtier-Dutton /* If the capture source has changed, 946184c1e2cSJames Courtier-Dutton * update the capture volume from the cached value 947184c1e2cSJames Courtier-Dutton * for the particular source. 948184c1e2cSJames Courtier-Dutton */ 94974415a36SJames Courtier-Dutton source_id = ucontrol->value.enumerated.item[0]; 95074415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 2; */ 95174415a36SJames Courtier-Dutton /* emu->i2c_capture_volume */ 95274415a36SJames Courtier-Dutton if (source_id >= 2) 95374415a36SJames Courtier-Dutton return -EINVAL; 954184c1e2cSJames Courtier-Dutton change = (emu->i2c_capture_source != source_id); 955184c1e2cSJames Courtier-Dutton if (change) { 956184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 957184c1e2cSJames Courtier-Dutton spin_lock_irqsave(&emu->emu_lock, flags); 958184c1e2cSJames Courtier-Dutton gpio = inl(emu->port + A_IOCFG); 959184c1e2cSJames Courtier-Dutton if (source_id==0) 960184c1e2cSJames Courtier-Dutton outl(gpio | 0x4, emu->port + A_IOCFG); 961184c1e2cSJames Courtier-Dutton else 962184c1e2cSJames Courtier-Dutton outl(gpio & ~0x4, emu->port + A_IOCFG); 963184c1e2cSJames Courtier-Dutton spin_unlock_irqrestore(&emu->emu_lock, flags); 964184c1e2cSJames Courtier-Dutton 965184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ 966184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ 967184c1e2cSJames Courtier-Dutton if (ngain != ogain) 968184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); 969184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ 970184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ 971184c1e2cSJames Courtier-Dutton if (ngain != ogain) 972184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 973184c1e2cSJames Courtier-Dutton 974184c1e2cSJames Courtier-Dutton source = 1 << (source_id + 2); 975184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ 976184c1e2cSJames Courtier-Dutton emu->i2c_capture_source = source_id; 977184c1e2cSJames Courtier-Dutton } 978184c1e2cSJames Courtier-Dutton return change; 979184c1e2cSJames Courtier-Dutton } 980184c1e2cSJames Courtier-Dutton 981*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source = 982184c1e2cSJames Courtier-Dutton { 983184c1e2cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 984184c1e2cSJames Courtier-Dutton .name = "Capture Source", 985184c1e2cSJames Courtier-Dutton .info = snd_audigy_i2c_capture_source_info, 986184c1e2cSJames Courtier-Dutton .get = snd_audigy_i2c_capture_source_get, 987184c1e2cSJames Courtier-Dutton .put = snd_audigy_i2c_capture_source_put 988184c1e2cSJames Courtier-Dutton }; 989184c1e2cSJames Courtier-Dutton 990184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, 991184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 992184c1e2cSJames Courtier-Dutton { 993184c1e2cSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 994184c1e2cSJames Courtier-Dutton uinfo->count = 2; 995184c1e2cSJames Courtier-Dutton uinfo->value.integer.min = 0; 996184c1e2cSJames Courtier-Dutton uinfo->value.integer.max = 255; 997184c1e2cSJames Courtier-Dutton return 0; 998184c1e2cSJames Courtier-Dutton } 999184c1e2cSJames Courtier-Dutton 1000184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, 1001184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 1002184c1e2cSJames Courtier-Dutton { 1003184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 100474415a36SJames Courtier-Dutton unsigned int source_id; 1005184c1e2cSJames Courtier-Dutton 1006184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 100774415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 100874415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 100974415a36SJames Courtier-Dutton if (source_id >= 2) 101074415a36SJames Courtier-Dutton return -EINVAL; 1011184c1e2cSJames Courtier-Dutton 1012184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; 1013184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; 1014184c1e2cSJames Courtier-Dutton return 0; 1015184c1e2cSJames Courtier-Dutton } 1016184c1e2cSJames Courtier-Dutton 1017184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, 1018184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 1019184c1e2cSJames Courtier-Dutton { 1020184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1021184c1e2cSJames Courtier-Dutton unsigned int ogain; 1022184c1e2cSJames Courtier-Dutton unsigned int ngain; 102374415a36SJames Courtier-Dutton unsigned int source_id; 1024184c1e2cSJames Courtier-Dutton int change = 0; 1025184c1e2cSJames Courtier-Dutton 1026184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 102774415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 102874415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 102974415a36SJames Courtier-Dutton if (source_id >= 2) 103074415a36SJames Courtier-Dutton return -EINVAL; 1031184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ 1032184c1e2cSJames Courtier-Dutton ngain = ucontrol->value.integer.value[0]; 1033184c1e2cSJames Courtier-Dutton if (ngain > 0xff) 1034184c1e2cSJames Courtier-Dutton return 0; 1035184c1e2cSJames Courtier-Dutton if (ogain != ngain) { 1036184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 1037184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); 103874415a36SJames Courtier-Dutton emu->i2c_capture_volume[source_id][0] = ngain; 1039184c1e2cSJames Courtier-Dutton change = 1; 1040184c1e2cSJames Courtier-Dutton } 1041184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ 1042184c1e2cSJames Courtier-Dutton ngain = ucontrol->value.integer.value[1]; 1043184c1e2cSJames Courtier-Dutton if (ngain > 0xff) 1044184c1e2cSJames Courtier-Dutton return 0; 1045184c1e2cSJames Courtier-Dutton if (ogain != ngain) { 1046184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 1047184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 104874415a36SJames Courtier-Dutton emu->i2c_capture_volume[source_id][1] = ngain; 1049184c1e2cSJames Courtier-Dutton change = 1; 1050184c1e2cSJames Courtier-Dutton } 1051184c1e2cSJames Courtier-Dutton 1052184c1e2cSJames Courtier-Dutton return change; 1053184c1e2cSJames Courtier-Dutton } 1054184c1e2cSJames Courtier-Dutton 1055184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \ 1056184c1e2cSJames Courtier-Dutton { \ 1057184c1e2cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 1058184c1e2cSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 1059184c1e2cSJames Courtier-Dutton SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 1060184c1e2cSJames Courtier-Dutton .info = snd_audigy_i2c_volume_info, \ 1061184c1e2cSJames Courtier-Dutton .get = snd_audigy_i2c_volume_get, \ 1062184c1e2cSJames Courtier-Dutton .put = snd_audigy_i2c_volume_put, \ 1063184c1e2cSJames Courtier-Dutton .tlv = { .p = snd_audigy_db_scale2 }, \ 1064184c1e2cSJames Courtier-Dutton .private_value = chid \ 1065184c1e2cSJames Courtier-Dutton } 1066184c1e2cSJames Courtier-Dutton 1067184c1e2cSJames Courtier-Dutton 1068e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = { 1069184c1e2cSJames Courtier-Dutton I2C_VOLUME("Mic Capture Volume", 0), 1070184c1e2cSJames Courtier-Dutton I2C_VOLUME("Line Capture Volume", 0) 1071184c1e2cSJames Courtier-Dutton }; 1072184c1e2cSJames Courtier-Dutton 10730af68e5eSTakashi Iwai #if 0 1074eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 10751da177e4SLinus Torvalds { 10761541c66dSTakashi Iwai static const char * const texts[] = {"44100", "48000", "96000"}; 10771da177e4SLinus Torvalds 10781541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 3, texts); 10791da177e4SLinus Torvalds } 10801da177e4SLinus Torvalds 1081eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, 1082eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10831da177e4SLinus Torvalds { 1084eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10851da177e4SLinus Torvalds unsigned int tmp; 10861da177e4SLinus Torvalds unsigned long flags; 10871da177e4SLinus Torvalds 10881da177e4SLinus Torvalds 10891da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 10901da177e4SLinus Torvalds tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 10911da177e4SLinus Torvalds switch (tmp & A_SPDIF_RATE_MASK) { 10921da177e4SLinus Torvalds case A_SPDIF_44100: 10931da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 10941da177e4SLinus Torvalds break; 10951da177e4SLinus Torvalds case A_SPDIF_48000: 10961da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 10971da177e4SLinus Torvalds break; 10981da177e4SLinus Torvalds case A_SPDIF_96000: 10991da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 11001da177e4SLinus Torvalds break; 11011da177e4SLinus Torvalds default: 11021da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 11031da177e4SLinus Torvalds } 11041da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11051da177e4SLinus Torvalds return 0; 11061da177e4SLinus Torvalds } 11071da177e4SLinus Torvalds 1108eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, 1109eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11101da177e4SLinus Torvalds { 1111eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11121da177e4SLinus Torvalds int change; 11131da177e4SLinus Torvalds unsigned int reg, val, tmp; 11141da177e4SLinus Torvalds unsigned long flags; 11151da177e4SLinus Torvalds 11161da177e4SLinus Torvalds switch(ucontrol->value.enumerated.item[0]) { 11171da177e4SLinus Torvalds case 0: 11181da177e4SLinus Torvalds val = A_SPDIF_44100; 11191da177e4SLinus Torvalds break; 11201da177e4SLinus Torvalds case 1: 11211da177e4SLinus Torvalds val = A_SPDIF_48000; 11221da177e4SLinus Torvalds break; 11231da177e4SLinus Torvalds case 2: 11241da177e4SLinus Torvalds val = A_SPDIF_96000; 11251da177e4SLinus Torvalds break; 11261da177e4SLinus Torvalds default: 11271da177e4SLinus Torvalds val = A_SPDIF_48000; 11281da177e4SLinus Torvalds break; 11291da177e4SLinus Torvalds } 11301da177e4SLinus Torvalds 11311da177e4SLinus Torvalds 11321da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11331da177e4SLinus Torvalds reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 11341da177e4SLinus Torvalds tmp = reg & ~A_SPDIF_RATE_MASK; 11351da177e4SLinus Torvalds tmp |= val; 11361da177e4SLinus Torvalds if ((change = (tmp != reg))) 11371da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); 11381da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11391da177e4SLinus Torvalds return change; 11401da177e4SLinus Torvalds } 11411da177e4SLinus Torvalds 1142eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_spdif_output_rate = 11431da177e4SLinus Torvalds { 11441da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 11451da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 11461da177e4SLinus Torvalds .name = "Audigy SPDIF Output Sample Rate", 11471da177e4SLinus Torvalds .count = 1, 11481da177e4SLinus Torvalds .info = snd_audigy_spdif_output_rate_info, 11491da177e4SLinus Torvalds .get = snd_audigy_spdif_output_rate_get, 11501da177e4SLinus Torvalds .put = snd_audigy_spdif_output_rate_put 11511da177e4SLinus Torvalds }; 11520af68e5eSTakashi Iwai #endif 11531da177e4SLinus Torvalds 1154eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, 1155eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11561da177e4SLinus Torvalds { 1157eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11581da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 11591da177e4SLinus Torvalds int change; 11601da177e4SLinus Torvalds unsigned int val; 11611da177e4SLinus Torvalds unsigned long flags; 11621da177e4SLinus Torvalds 116374415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 116474415a36SJames Courtier-Dutton if (idx >= 3) 116574415a36SJames Courtier-Dutton return -EINVAL; 11661da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 11671da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 11681da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 11691da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 11701da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11711da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 11721da177e4SLinus Torvalds if (change) { 11731da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); 11741da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 11751da177e4SLinus Torvalds } 11761da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11771da177e4SLinus Torvalds return change; 11781da177e4SLinus Torvalds } 11791da177e4SLinus Torvalds 1180*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = 11811da177e4SLinus Torvalds { 11821da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 11835549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 11841da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 11857583cb51STakashi Iwai .count = 3, 11861da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 11871da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get_mask 11881da177e4SLinus Torvalds }; 11891da177e4SLinus Torvalds 1190*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control = 11911da177e4SLinus Torvalds { 11925549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 11931da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 11947583cb51STakashi Iwai .count = 3, 11951da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 11961da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get, 11971da177e4SLinus Torvalds .put = snd_emu10k1_spdif_put 11981da177e4SLinus Torvalds }; 11991da177e4SLinus Torvalds 12001da177e4SLinus Torvalds 1201eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route) 12021da177e4SLinus Torvalds { 12031da177e4SLinus Torvalds if (emu->audigy) { 12041da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT1, voice, 12051da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt1(route)); 12061da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 12071da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt2(route)); 12081da177e4SLinus Torvalds } else { 12091da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXRT, voice, 12101da177e4SLinus Torvalds snd_emu10k1_compose_send_routing(route)); 12111da177e4SLinus Torvalds } 12121da177e4SLinus Torvalds } 12131da177e4SLinus Torvalds 1214eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume) 12151da177e4SLinus Torvalds { 12161da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); 12171da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); 12181da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); 12191da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); 12201da177e4SLinus Torvalds if (emu->audigy) { 12211da177e4SLinus Torvalds unsigned int val = ((unsigned int)volume[4] << 24) | 12221da177e4SLinus Torvalds ((unsigned int)volume[5] << 16) | 12231da177e4SLinus Torvalds ((unsigned int)volume[6] << 8) | 12241da177e4SLinus Torvalds (unsigned int)volume[7]; 12251da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val); 12261da177e4SLinus Torvalds } 12271da177e4SLinus Torvalds } 12281da177e4SLinus Torvalds 12291da177e4SLinus Torvalds /* PCM stream controls */ 12301da177e4SLinus Torvalds 1231eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 12321da177e4SLinus Torvalds { 1233eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 12341da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 12351da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 12361da177e4SLinus Torvalds uinfo->value.integer.min = 0; 12371da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 12381da177e4SLinus Torvalds return 0; 12391da177e4SLinus Torvalds } 12401da177e4SLinus Torvalds 1241eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, 1242eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12431da177e4SLinus Torvalds { 12441da177e4SLinus Torvalds unsigned long flags; 1245eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1246eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1247eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12481da177e4SLinus Torvalds int voice, idx; 12491da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12501da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 12511da177e4SLinus Torvalds 12521da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12531da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 12541da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 12551da177e4SLinus Torvalds ucontrol->value.integer.value[(voice * num_efx) + idx] = 12561da177e4SLinus Torvalds mix->send_routing[voice][idx] & mask; 12571da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 12581da177e4SLinus Torvalds return 0; 12591da177e4SLinus Torvalds } 12601da177e4SLinus Torvalds 1261eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, 1262eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12631da177e4SLinus Torvalds { 12641da177e4SLinus Torvalds unsigned long flags; 1265eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1266eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1267eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12681da177e4SLinus Torvalds int change = 0, voice, idx, val; 12691da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12701da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 12711da177e4SLinus Torvalds 12721da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12731da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 12741da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 12751da177e4SLinus Torvalds val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; 12761da177e4SLinus Torvalds if (mix->send_routing[voice][idx] != val) { 12771da177e4SLinus Torvalds mix->send_routing[voice][idx] = val; 12781da177e4SLinus Torvalds change = 1; 12791da177e4SLinus Torvalds } 12801da177e4SLinus Torvalds } 12811da177e4SLinus Torvalds if (change && mix->epcm) { 12821da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 12831da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 12841da177e4SLinus Torvalds &mix->send_routing[1][0]); 12851da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, 12861da177e4SLinus Torvalds &mix->send_routing[2][0]); 12871da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 12881da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 12891da177e4SLinus Torvalds &mix->send_routing[0][0]); 12901da177e4SLinus Torvalds } 12911da177e4SLinus Torvalds } 12921da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 12931da177e4SLinus Torvalds return change; 12941da177e4SLinus Torvalds } 12951da177e4SLinus Torvalds 1296*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control = 12971da177e4SLinus Torvalds { 12981da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 129967ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 13001da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Routing", 13011da177e4SLinus Torvalds .count = 32, 13021da177e4SLinus Torvalds .info = snd_emu10k1_send_routing_info, 13031da177e4SLinus Torvalds .get = snd_emu10k1_send_routing_get, 13041da177e4SLinus Torvalds .put = snd_emu10k1_send_routing_put 13051da177e4SLinus Torvalds }; 13061da177e4SLinus Torvalds 1307eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13081da177e4SLinus Torvalds { 1309eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13101da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13111da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 13121da177e4SLinus Torvalds uinfo->value.integer.min = 0; 13131da177e4SLinus Torvalds uinfo->value.integer.max = 255; 13141da177e4SLinus Torvalds return 0; 13151da177e4SLinus Torvalds } 13161da177e4SLinus Torvalds 1317eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, 1318eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13191da177e4SLinus Torvalds { 13201da177e4SLinus Torvalds unsigned long flags; 1321eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1322eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1323eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13241da177e4SLinus Torvalds int idx; 13251da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13261da177e4SLinus Torvalds 13271da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13281da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) 13291da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; 13301da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13311da177e4SLinus Torvalds return 0; 13321da177e4SLinus Torvalds } 13331da177e4SLinus Torvalds 1334eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, 1335eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13361da177e4SLinus Torvalds { 13371da177e4SLinus Torvalds unsigned long flags; 1338eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1339eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1340eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13411da177e4SLinus Torvalds int change = 0, idx, val; 13421da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13431da177e4SLinus Torvalds 13441da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13451da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) { 13461da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 13471da177e4SLinus Torvalds if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { 13481da177e4SLinus Torvalds mix->send_volume[idx/num_efx][idx%num_efx] = val; 13491da177e4SLinus Torvalds change = 1; 13501da177e4SLinus Torvalds } 13511da177e4SLinus Torvalds } 13521da177e4SLinus Torvalds if (change && mix->epcm) { 13531da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 13541da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 13551da177e4SLinus Torvalds &mix->send_volume[1][0]); 13561da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, 13571da177e4SLinus Torvalds &mix->send_volume[2][0]); 13581da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 13591da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 13601da177e4SLinus Torvalds &mix->send_volume[0][0]); 13611da177e4SLinus Torvalds } 13621da177e4SLinus Torvalds } 13631da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13641da177e4SLinus Torvalds return change; 13651da177e4SLinus Torvalds } 13661da177e4SLinus Torvalds 1367*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control = 13681da177e4SLinus Torvalds { 13691da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 137067ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 13711da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Volume", 13721da177e4SLinus Torvalds .count = 32, 13731da177e4SLinus Torvalds .info = snd_emu10k1_send_volume_info, 13741da177e4SLinus Torvalds .get = snd_emu10k1_send_volume_get, 13751da177e4SLinus Torvalds .put = snd_emu10k1_send_volume_put 13761da177e4SLinus Torvalds }; 13771da177e4SLinus Torvalds 1378eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13791da177e4SLinus Torvalds { 13801da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13811da177e4SLinus Torvalds uinfo->count = 3; 13821da177e4SLinus Torvalds uinfo->value.integer.min = 0; 13831da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 13841da177e4SLinus Torvalds return 0; 13851da177e4SLinus Torvalds } 13861da177e4SLinus Torvalds 1387eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, 1388eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13891da177e4SLinus Torvalds { 1390eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1391eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1392eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13931da177e4SLinus Torvalds unsigned long flags; 13941da177e4SLinus Torvalds int idx; 13951da177e4SLinus Torvalds 13961da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13971da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) 13981da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->attn[idx]; 13991da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 14001da177e4SLinus Torvalds return 0; 14011da177e4SLinus Torvalds } 14021da177e4SLinus Torvalds 1403eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, 1404eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14051da177e4SLinus Torvalds { 14061da177e4SLinus Torvalds unsigned long flags; 1407eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1408eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1409eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14101da177e4SLinus Torvalds int change = 0, idx, val; 14111da177e4SLinus Torvalds 14121da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 14131da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) { 14141da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 0xffff; 14151da177e4SLinus Torvalds if (mix->attn[idx] != val) { 14161da177e4SLinus Torvalds mix->attn[idx] = val; 14171da177e4SLinus Torvalds change = 1; 14181da177e4SLinus Torvalds } 14191da177e4SLinus Torvalds } 14201da177e4SLinus Torvalds if (change && mix->epcm) { 14211da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 14221da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); 14231da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); 14241da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 14251da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); 14261da177e4SLinus Torvalds } 14271da177e4SLinus Torvalds } 14281da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 14291da177e4SLinus Torvalds return change; 14301da177e4SLinus Torvalds } 14311da177e4SLinus Torvalds 1432*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control = 14331da177e4SLinus Torvalds { 14341da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 143567ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14361da177e4SLinus Torvalds .name = "EMU10K1 PCM Volume", 14371da177e4SLinus Torvalds .count = 32, 14381da177e4SLinus Torvalds .info = snd_emu10k1_attn_info, 14391da177e4SLinus Torvalds .get = snd_emu10k1_attn_get, 14401da177e4SLinus Torvalds .put = snd_emu10k1_attn_put 14411da177e4SLinus Torvalds }; 14421da177e4SLinus Torvalds 14431da177e4SLinus Torvalds /* Mutichannel PCM stream controls */ 14441da177e4SLinus Torvalds 1445eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 14461da177e4SLinus Torvalds { 1447eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14481da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 14491da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 14501da177e4SLinus Torvalds uinfo->value.integer.min = 0; 14511da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 14521da177e4SLinus Torvalds return 0; 14531da177e4SLinus Torvalds } 14541da177e4SLinus Torvalds 1455eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, 1456eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14571da177e4SLinus Torvalds { 14581da177e4SLinus Torvalds unsigned long flags; 1459eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1460eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1461eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14621da177e4SLinus Torvalds int idx; 14631da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 14641da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 14651da177e4SLinus Torvalds 14661da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 14671da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 14681da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = 14691da177e4SLinus Torvalds mix->send_routing[0][idx] & mask; 14701da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 14711da177e4SLinus Torvalds return 0; 14721da177e4SLinus Torvalds } 14731da177e4SLinus Torvalds 1474eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, 1475eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14761da177e4SLinus Torvalds { 14771da177e4SLinus Torvalds unsigned long flags; 1478eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14791da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1480eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 14811da177e4SLinus Torvalds int change = 0, idx, val; 14821da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 14831da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 14841da177e4SLinus Torvalds 14851da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 14861da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 14871da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & mask; 14881da177e4SLinus Torvalds if (mix->send_routing[0][idx] != val) { 14891da177e4SLinus Torvalds mix->send_routing[0][idx] = val; 14901da177e4SLinus Torvalds change = 1; 14911da177e4SLinus Torvalds } 14921da177e4SLinus Torvalds } 14931da177e4SLinus Torvalds 14941da177e4SLinus Torvalds if (change && mix->epcm) { 14951da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 14961da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, 14971da177e4SLinus Torvalds &mix->send_routing[0][0]); 14981da177e4SLinus Torvalds } 14991da177e4SLinus Torvalds } 15001da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 15011da177e4SLinus Torvalds return change; 15021da177e4SLinus Torvalds } 15031da177e4SLinus Torvalds 1504*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = 15051da177e4SLinus Torvalds { 15061da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 15071da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 15081da177e4SLinus Torvalds .name = "Multichannel PCM Send Routing", 15091da177e4SLinus Torvalds .count = 16, 15101da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_routing_info, 15111da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_routing_get, 15121da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_routing_put 15131da177e4SLinus Torvalds }; 15141da177e4SLinus Torvalds 1515eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 15161da177e4SLinus Torvalds { 1517eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15181da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 15191da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 15201da177e4SLinus Torvalds uinfo->value.integer.min = 0; 15211da177e4SLinus Torvalds uinfo->value.integer.max = 255; 15221da177e4SLinus Torvalds return 0; 15231da177e4SLinus Torvalds } 15241da177e4SLinus Torvalds 1525eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, 1526eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15271da177e4SLinus Torvalds { 15281da177e4SLinus Torvalds unsigned long flags; 1529eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1530eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1531eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 15321da177e4SLinus Torvalds int idx; 15331da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 15341da177e4SLinus Torvalds 15351da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 15361da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 15371da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; 15381da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 15391da177e4SLinus Torvalds return 0; 15401da177e4SLinus Torvalds } 15411da177e4SLinus Torvalds 1542eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, 1543eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15441da177e4SLinus Torvalds { 15451da177e4SLinus Torvalds unsigned long flags; 1546eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15471da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1548eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 15491da177e4SLinus Torvalds int change = 0, idx, val; 15501da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 15511da177e4SLinus Torvalds 15521da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 15531da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 15541da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 15551da177e4SLinus Torvalds if (mix->send_volume[0][idx] != val) { 15561da177e4SLinus Torvalds mix->send_volume[0][idx] = val; 15571da177e4SLinus Torvalds change = 1; 15581da177e4SLinus Torvalds } 15591da177e4SLinus Torvalds } 15601da177e4SLinus Torvalds if (change && mix->epcm) { 15611da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 15621da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, 15631da177e4SLinus Torvalds &mix->send_volume[0][0]); 15641da177e4SLinus Torvalds } 15651da177e4SLinus Torvalds } 15661da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 15671da177e4SLinus Torvalds return change; 15681da177e4SLinus Torvalds } 15691da177e4SLinus Torvalds 15701da177e4SLinus Torvalds 1571*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = 15721da177e4SLinus Torvalds { 15731da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 15741da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 15751da177e4SLinus Torvalds .name = "Multichannel PCM Send Volume", 15761da177e4SLinus Torvalds .count = 16, 15771da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_volume_info, 15781da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_volume_get, 15791da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_volume_put 15801da177e4SLinus Torvalds }; 15811da177e4SLinus Torvalds 1582eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 15831da177e4SLinus Torvalds { 15841da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 15851da177e4SLinus Torvalds uinfo->count = 1; 15861da177e4SLinus Torvalds uinfo->value.integer.min = 0; 15871da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 15881da177e4SLinus Torvalds return 0; 15891da177e4SLinus Torvalds } 15901da177e4SLinus Torvalds 1591eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, 1592eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15931da177e4SLinus Torvalds { 1594eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1595eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1596eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 15971da177e4SLinus Torvalds unsigned long flags; 15981da177e4SLinus Torvalds 15991da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 16001da177e4SLinus Torvalds ucontrol->value.integer.value[0] = mix->attn[0]; 16011da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 16021da177e4SLinus Torvalds return 0; 16031da177e4SLinus Torvalds } 16041da177e4SLinus Torvalds 1605eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, 1606eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16071da177e4SLinus Torvalds { 16081da177e4SLinus Torvalds unsigned long flags; 1609eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 16101da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1611eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 16121da177e4SLinus Torvalds int change = 0, val; 16131da177e4SLinus Torvalds 16141da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 16151da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] & 0xffff; 16161da177e4SLinus Torvalds if (mix->attn[0] != val) { 16171da177e4SLinus Torvalds mix->attn[0] = val; 16181da177e4SLinus Torvalds change = 1; 16191da177e4SLinus Torvalds } 16201da177e4SLinus Torvalds if (change && mix->epcm) { 16211da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 16221da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); 16231da177e4SLinus Torvalds } 16241da177e4SLinus Torvalds } 16251da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 16261da177e4SLinus Torvalds return change; 16271da177e4SLinus Torvalds } 16281da177e4SLinus Torvalds 1629*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control = 16301da177e4SLinus Torvalds { 16311da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 16321da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 16331da177e4SLinus Torvalds .name = "Multichannel PCM Volume", 16341da177e4SLinus Torvalds .count = 16, 16351da177e4SLinus Torvalds .info = snd_emu10k1_efx_attn_info, 16361da177e4SLinus Torvalds .get = snd_emu10k1_efx_attn_get, 16371da177e4SLinus Torvalds .put = snd_emu10k1_efx_attn_put 16381da177e4SLinus Torvalds }; 16391da177e4SLinus Torvalds 1640a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info snd_ctl_boolean_mono_info 16411da177e4SLinus Torvalds 1642eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, 1643eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16441da177e4SLinus Torvalds { 1645eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 16461da177e4SLinus Torvalds 16471da177e4SLinus Torvalds if (emu->audigy) 16481da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; 16491da177e4SLinus Torvalds else 16501da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; 1651d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1652d2cd74b1STakashi Iwai ucontrol->value.integer.value[0] = 1653d2cd74b1STakashi Iwai !ucontrol->value.integer.value[0]; 1654d2cd74b1STakashi Iwai 16551da177e4SLinus Torvalds return 0; 16561da177e4SLinus Torvalds } 16571da177e4SLinus Torvalds 1658eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, 1659eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16601da177e4SLinus Torvalds { 16611da177e4SLinus Torvalds unsigned long flags; 1662eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1663d2cd74b1STakashi Iwai unsigned int reg, val, sw; 16641da177e4SLinus Torvalds int change = 0; 16651da177e4SLinus Torvalds 1666d2cd74b1STakashi Iwai sw = ucontrol->value.integer.value[0]; 1667d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1668d2cd74b1STakashi Iwai sw = !sw; 16691da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 1670184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 1671184c1e2cSJames Courtier-Dutton /* Do nothing for Audigy 2 ZS Notebook */ 1672184c1e2cSJames Courtier-Dutton } else if (emu->audigy) { 16731da177e4SLinus Torvalds reg = inl(emu->port + A_IOCFG); 1674d2cd74b1STakashi Iwai val = sw ? A_IOCFG_GPOUT0 : 0; 16751da177e4SLinus Torvalds change = (reg & A_IOCFG_GPOUT0) != val; 16761da177e4SLinus Torvalds if (change) { 16771da177e4SLinus Torvalds reg &= ~A_IOCFG_GPOUT0; 16781da177e4SLinus Torvalds reg |= val; 16791da177e4SLinus Torvalds outl(reg | val, emu->port + A_IOCFG); 16801da177e4SLinus Torvalds } 16811da177e4SLinus Torvalds } 16821da177e4SLinus Torvalds reg = inl(emu->port + HCFG); 1683d2cd74b1STakashi Iwai val = sw ? HCFG_GPOUT0 : 0; 16841da177e4SLinus Torvalds change |= (reg & HCFG_GPOUT0) != val; 16851da177e4SLinus Torvalds if (change) { 16861da177e4SLinus Torvalds reg &= ~HCFG_GPOUT0; 16871da177e4SLinus Torvalds reg |= val; 16881da177e4SLinus Torvalds outl(reg | val, emu->port + HCFG); 16891da177e4SLinus Torvalds } 16901da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 16911da177e4SLinus Torvalds return change; 16921da177e4SLinus Torvalds } 16931da177e4SLinus Torvalds 1694*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif = 16951da177e4SLinus Torvalds { 16961da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 16971da177e4SLinus Torvalds .name = "SB Live Analog/Digital Output Jack", 16981da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 16991da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 17001da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 17011da177e4SLinus Torvalds }; 17021da177e4SLinus Torvalds 1703*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif = 17041da177e4SLinus Torvalds { 17051da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 17061da177e4SLinus Torvalds .name = "Audigy Analog/Digital Output Jack", 17071da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 17081da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 17091da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 17101da177e4SLinus Torvalds }; 17111da177e4SLinus Torvalds 171216950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */ 171316950e09STakashi Iwai 171416950e09STakashi Iwai #define snd_audigy_capture_boost_info snd_ctl_boolean_mono_info 171516950e09STakashi Iwai 171616950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol, 171716950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 171816950e09STakashi Iwai { 171916950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 172016950e09STakashi Iwai unsigned int val; 172116950e09STakashi Iwai 172216950e09STakashi Iwai /* FIXME: better to use a cached version */ 172316950e09STakashi Iwai val = snd_ac97_read(emu->ac97, AC97_REC_GAIN); 172416950e09STakashi Iwai ucontrol->value.integer.value[0] = !!val; 172516950e09STakashi Iwai return 0; 172616950e09STakashi Iwai } 172716950e09STakashi Iwai 172816950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, 172916950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 173016950e09STakashi Iwai { 173116950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 173216950e09STakashi Iwai unsigned int val; 173316950e09STakashi Iwai 173416950e09STakashi Iwai if (ucontrol->value.integer.value[0]) 173516950e09STakashi Iwai val = 0x0f0f; 173616950e09STakashi Iwai else 173716950e09STakashi Iwai val = 0; 173816950e09STakashi Iwai return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); 173916950e09STakashi Iwai } 174016950e09STakashi Iwai 1741*f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost = 174216950e09STakashi Iwai { 174316950e09STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 17442a52feb1SMaciej S. Szmigiero .name = "Mic Extra Boost", 174516950e09STakashi Iwai .info = snd_audigy_capture_boost_info, 174616950e09STakashi Iwai .get = snd_audigy_capture_boost_get, 174716950e09STakashi Iwai .put = snd_audigy_capture_boost_put 174816950e09STakashi Iwai }; 174916950e09STakashi Iwai 175016950e09STakashi Iwai 17511da177e4SLinus Torvalds /* 17521da177e4SLinus Torvalds */ 1753eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) 17541da177e4SLinus Torvalds { 1755eb4698f3STakashi Iwai struct snd_emu10k1 *emu = ac97->private_data; 17561da177e4SLinus Torvalds emu->ac97 = NULL; 17571da177e4SLinus Torvalds } 17581da177e4SLinus Torvalds 17591da177e4SLinus Torvalds /* 17601da177e4SLinus Torvalds */ 1761eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name) 17621da177e4SLinus Torvalds { 1763eb4698f3STakashi Iwai struct snd_ctl_elem_id id; 17641da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 17651da177e4SLinus Torvalds strcpy(id.name, name); 17661da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 17671da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 17681da177e4SLinus Torvalds } 17691da177e4SLinus Torvalds 1770eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) 17711da177e4SLinus Torvalds { 1772eb4698f3STakashi Iwai struct snd_ctl_elem_id sid; 17731da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 17741da177e4SLinus Torvalds strcpy(sid.name, name); 17751da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 17761da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 17771da177e4SLinus Torvalds } 17781da177e4SLinus Torvalds 1779eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst) 17801da177e4SLinus Torvalds { 1781eb4698f3STakashi Iwai struct snd_kcontrol *kctl = ctl_find(card, src); 17821da177e4SLinus Torvalds if (kctl) { 17831da177e4SLinus Torvalds strcpy(kctl->id.name, dst); 17841da177e4SLinus Torvalds return 0; 17851da177e4SLinus Torvalds } 17861da177e4SLinus Torvalds return -ENOENT; 17871da177e4SLinus Torvalds } 17881da177e4SLinus Torvalds 1789e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu, 179067ed4161SClemens Ladisch int pcm_device, int multi_device) 17911da177e4SLinus Torvalds { 17921da177e4SLinus Torvalds int err, pcm; 1793eb4698f3STakashi Iwai struct snd_kcontrol *kctl; 1794eb4698f3STakashi Iwai struct snd_card *card = emu->card; 17951da177e4SLinus Torvalds char **c; 17961da177e4SLinus Torvalds static char *emu10k1_remove_ctls[] = { 17971da177e4SLinus Torvalds /* no AC97 mono, surround, center/lfe */ 17981da177e4SLinus Torvalds "Master Mono Playback Switch", 17991da177e4SLinus Torvalds "Master Mono Playback Volume", 18001da177e4SLinus Torvalds "PCM Out Path & Mute", 18011da177e4SLinus Torvalds "Mono Output Select", 18021da177e4SLinus Torvalds "Surround Playback Switch", 18031da177e4SLinus Torvalds "Surround Playback Volume", 18041da177e4SLinus Torvalds "Center Playback Switch", 18051da177e4SLinus Torvalds "Center Playback Volume", 18061da177e4SLinus Torvalds "LFE Playback Switch", 18071da177e4SLinus Torvalds "LFE Playback Volume", 18081da177e4SLinus Torvalds NULL 18091da177e4SLinus Torvalds }; 18101da177e4SLinus Torvalds static char *emu10k1_rename_ctls[] = { 18111da177e4SLinus Torvalds "Surround Digital Playback Volume", "Surround Playback Volume", 18121da177e4SLinus Torvalds "Center Digital Playback Volume", "Center Playback Volume", 18131da177e4SLinus Torvalds "LFE Digital Playback Volume", "LFE Playback Volume", 18141da177e4SLinus Torvalds NULL 18151da177e4SLinus Torvalds }; 18161da177e4SLinus Torvalds static char *audigy_remove_ctls[] = { 18171da177e4SLinus Torvalds /* Master/PCM controls on ac97 of Audigy has no effect */ 181821fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 181921fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 18201da177e4SLinus Torvalds "PCM Playback Switch", 18211da177e4SLinus Torvalds "PCM Playback Volume", 18221da177e4SLinus Torvalds "Master Playback Switch", 18231da177e4SLinus Torvalds "Master Playback Volume", 18241da177e4SLinus Torvalds "PCM Out Path & Mute", 18251da177e4SLinus Torvalds "Mono Output Select", 18261da177e4SLinus Torvalds /* remove unused AC97 capture controls */ 18271da177e4SLinus Torvalds "Capture Source", 18281da177e4SLinus Torvalds "Capture Switch", 18291da177e4SLinus Torvalds "Capture Volume", 18301da177e4SLinus Torvalds "Mic Select", 1831274b2000SMaciej S. Szmigiero "Headphone Playback Switch", 1832274b2000SMaciej S. Szmigiero "Headphone Playback Volume", 1833274b2000SMaciej S. Szmigiero "3D Control - Center", 1834274b2000SMaciej S. Szmigiero "3D Control - Depth", 1835274b2000SMaciej S. Szmigiero "3D Control - Switch", 18361da177e4SLinus Torvalds "Video Playback Switch", 18371da177e4SLinus Torvalds "Video Playback Volume", 18381da177e4SLinus Torvalds "Mic Playback Switch", 18391da177e4SLinus Torvalds "Mic Playback Volume", 1840274b2000SMaciej S. Szmigiero "External Amplifier", 18411da177e4SLinus Torvalds NULL 18421da177e4SLinus Torvalds }; 18431da177e4SLinus Torvalds static char *audigy_rename_ctls[] = { 18441da177e4SLinus Torvalds /* use conventional names */ 18451da177e4SLinus Torvalds "Wave Playback Volume", "PCM Playback Volume", 18461da177e4SLinus Torvalds /* "Wave Capture Volume", "PCM Capture Volume", */ 18471da177e4SLinus Torvalds "Wave Master Playback Volume", "Master Playback Volume", 18481da177e4SLinus Torvalds "AMic Playback Volume", "Mic Playback Volume", 184952051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 185052051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 18511da177e4SLinus Torvalds NULL 18521da177e4SLinus Torvalds }; 1853184c1e2cSJames Courtier-Dutton static char *audigy_rename_ctls_i2c_adc[] = { 1854184c1e2cSJames Courtier-Dutton //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", 1855184c1e2cSJames Courtier-Dutton "Line Capture Volume", "Analog Mix Capture Volume", 1856184c1e2cSJames Courtier-Dutton "Wave Playback Volume", "OLD PCM Playback Volume", 1857184c1e2cSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 1858184c1e2cSJames Courtier-Dutton "AMic Playback Volume", "Old Mic Playback Volume", 1859eb41dab6SJames Courtier-Dutton "CD Capture Volume", "IEC958 Optical Capture Volume", 1860184c1e2cSJames Courtier-Dutton NULL 1861184c1e2cSJames Courtier-Dutton }; 1862184c1e2cSJames Courtier-Dutton static char *audigy_remove_ctls_i2c_adc[] = { 1863184c1e2cSJames Courtier-Dutton /* On the Audigy2 ZS Notebook 1864184c1e2cSJames Courtier-Dutton * Capture via WM8775 */ 1865184c1e2cSJames Courtier-Dutton "Mic Capture Volume", 1866184c1e2cSJames Courtier-Dutton "Analog Mix Capture Volume", 1867184c1e2cSJames Courtier-Dutton "Aux Capture Volume", 1868eb41dab6SJames Courtier-Dutton "IEC958 Optical Capture Volume", 1869184c1e2cSJames Courtier-Dutton NULL 1870184c1e2cSJames Courtier-Dutton }; 187121fdddeaSJames Courtier-Dutton static char *audigy_remove_ctls_1361t_adc[] = { 187221fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 187321fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 187421fdddeaSJames Courtier-Dutton "PCM Playback Switch", 187521fdddeaSJames Courtier-Dutton "PCM Playback Volume", 187621fdddeaSJames Courtier-Dutton "Capture Source", 187721fdddeaSJames Courtier-Dutton "Capture Switch", 187821fdddeaSJames Courtier-Dutton "Capture Volume", 187921fdddeaSJames Courtier-Dutton "Mic Capture Volume", 188021fdddeaSJames Courtier-Dutton "Headphone Playback Switch", 188121fdddeaSJames Courtier-Dutton "Headphone Playback Volume", 188221fdddeaSJames Courtier-Dutton "3D Control - Center", 188321fdddeaSJames Courtier-Dutton "3D Control - Depth", 188421fdddeaSJames Courtier-Dutton "3D Control - Switch", 188521fdddeaSJames Courtier-Dutton "Line2 Playback Volume", 188621fdddeaSJames Courtier-Dutton "Line2 Capture Volume", 188721fdddeaSJames Courtier-Dutton NULL 188821fdddeaSJames Courtier-Dutton }; 188921fdddeaSJames Courtier-Dutton static char *audigy_rename_ctls_1361t_adc[] = { 189021fdddeaSJames Courtier-Dutton "Master Playback Switch", "Master Capture Switch", 189121fdddeaSJames Courtier-Dutton "Master Playback Volume", "Master Capture Volume", 189221fdddeaSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 1893d355c82aSJaroslav Kysela "Beep Playback Switch", "Beep Capture Switch", 1894d355c82aSJaroslav Kysela "Beep Playback Volume", "Beep Capture Volume", 189521fdddeaSJames Courtier-Dutton "Phone Playback Switch", "Phone Capture Switch", 189621fdddeaSJames Courtier-Dutton "Phone Playback Volume", "Phone Capture Volume", 189721fdddeaSJames Courtier-Dutton "Mic Playback Switch", "Mic Capture Switch", 189821fdddeaSJames Courtier-Dutton "Mic Playback Volume", "Mic Capture Volume", 189921fdddeaSJames Courtier-Dutton "Line Playback Switch", "Line Capture Switch", 190021fdddeaSJames Courtier-Dutton "Line Playback Volume", "Line Capture Volume", 190121fdddeaSJames Courtier-Dutton "CD Playback Switch", "CD Capture Switch", 190221fdddeaSJames Courtier-Dutton "CD Playback Volume", "CD Capture Volume", 190321fdddeaSJames Courtier-Dutton "Aux Playback Switch", "Aux Capture Switch", 190421fdddeaSJames Courtier-Dutton "Aux Playback Volume", "Aux Capture Volume", 190521fdddeaSJames Courtier-Dutton "Video Playback Switch", "Video Capture Switch", 190621fdddeaSJames Courtier-Dutton "Video Playback Volume", "Video Capture Volume", 190752051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 190852051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 190921fdddeaSJames Courtier-Dutton NULL 191021fdddeaSJames Courtier-Dutton }; 19111da177e4SLinus Torvalds 19122b637da5SLee Revell if (emu->card_capabilities->ac97_chip) { 1913eb4698f3STakashi Iwai struct snd_ac97_bus *pbus; 1914eb4698f3STakashi Iwai struct snd_ac97_template ac97; 1915eb4698f3STakashi Iwai static struct snd_ac97_bus_ops ops = { 19161da177e4SLinus Torvalds .write = snd_emu10k1_ac97_write, 19171da177e4SLinus Torvalds .read = snd_emu10k1_ac97_read, 19181da177e4SLinus Torvalds }; 19191da177e4SLinus Torvalds 1920b1508693STakashi Iwai if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0) 19211da177e4SLinus Torvalds return err; 19221da177e4SLinus Torvalds pbus->no_vra = 1; /* we don't need VRA */ 19231da177e4SLinus Torvalds 19241da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97)); 19251da177e4SLinus Torvalds ac97.private_data = emu; 19261da177e4SLinus Torvalds ac97.private_free = snd_emu10k1_mixer_free_ac97; 19271da177e4SLinus Torvalds ac97.scaps = AC97_SCAP_NO_SPDIF; 1928b1508693STakashi Iwai if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) { 1929b1508693STakashi Iwai if (emu->card_capabilities->ac97_chip == 1) 19301da177e4SLinus Torvalds return err; 19316f002b02STakashi Iwai dev_info(emu->card->dev, 19326f002b02STakashi Iwai "AC97 is optional on this board\n"); 19336f002b02STakashi Iwai dev_info(emu->card->dev, 19346f002b02STakashi Iwai "Proceeding without ac97 mixers...\n"); 1935b1508693STakashi Iwai snd_device_free(emu->card, pbus); 1936b1508693STakashi Iwai goto no_ac97; /* FIXME: get rid of ugly gotos.. */ 1937b1508693STakashi Iwai } 19381da177e4SLinus Torvalds if (emu->audigy) { 19391da177e4SLinus Torvalds /* set master volume to 0 dB */ 19404d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); 19411da177e4SLinus Torvalds /* set capture source to mic */ 19424d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); 194352051942SMaciej S. Szmigiero /* set mono output (TAD) to mic */ 194452051942SMaciej S. Szmigiero snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE, 194552051942SMaciej S. Szmigiero 0x0200, 0x0200); 194621fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 194721fdddeaSJames Courtier-Dutton c = audigy_remove_ctls_1361t_adc; 194821fdddeaSJames Courtier-Dutton else 19491da177e4SLinus Torvalds c = audigy_remove_ctls; 19501da177e4SLinus Torvalds } else { 19511da177e4SLinus Torvalds /* 19521da177e4SLinus Torvalds * Credits for cards based on STAC9758: 19531da177e4SLinus Torvalds * James Courtier-Dutton <James@superbug.demon.co.uk> 19541da177e4SLinus Torvalds * Voluspa <voluspa@comhem.se> 19551da177e4SLinus Torvalds */ 19561da177e4SLinus Torvalds if (emu->ac97->id == AC97_ID_STAC9758) { 19571da177e4SLinus Torvalds emu->rear_ac97 = 1; 19581da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); 19592594d960SRolf Stefan Wilke snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); 1960b6a48404SRaymond Yau remove_ctl(card,"Front Playback Volume"); 1961b6a48404SRaymond Yau remove_ctl(card,"Front Playback Switch"); 19621da177e4SLinus Torvalds } 19631da177e4SLinus Torvalds /* remove unused AC97 controls */ 19644d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); 19654d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); 19661da177e4SLinus Torvalds c = emu10k1_remove_ctls; 19671da177e4SLinus Torvalds } 19681da177e4SLinus Torvalds for (; *c; c++) 19691da177e4SLinus Torvalds remove_ctl(card, *c); 1970184c1e2cSJames Courtier-Dutton } else if (emu->card_capabilities->i2c_adc) { 1971184c1e2cSJames Courtier-Dutton c = audigy_remove_ctls_i2c_adc; 1972184c1e2cSJames Courtier-Dutton for (; *c; c++) 1973184c1e2cSJames Courtier-Dutton remove_ctl(card, *c); 19741da177e4SLinus Torvalds } else { 1975f12aa40cSTakashi Iwai no_ac97: 19762b637da5SLee Revell if (emu->card_capabilities->ecard) 19771da177e4SLinus Torvalds strcpy(emu->card->mixername, "EMU APS"); 19781da177e4SLinus Torvalds else if (emu->audigy) 19791da177e4SLinus Torvalds strcpy(emu->card->mixername, "SB Audigy"); 19801da177e4SLinus Torvalds else 19811da177e4SLinus Torvalds strcpy(emu->card->mixername, "Emu10k1"); 19821da177e4SLinus Torvalds } 19831da177e4SLinus Torvalds 19841da177e4SLinus Torvalds if (emu->audigy) 198521fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 198621fdddeaSJames Courtier-Dutton c = audigy_rename_ctls_1361t_adc; 1987184c1e2cSJames Courtier-Dutton else if (emu->card_capabilities->i2c_adc) 1988184c1e2cSJames Courtier-Dutton c = audigy_rename_ctls_i2c_adc; 198921fdddeaSJames Courtier-Dutton else 19901da177e4SLinus Torvalds c = audigy_rename_ctls; 19911da177e4SLinus Torvalds else 19921da177e4SLinus Torvalds c = emu10k1_rename_ctls; 19931da177e4SLinus Torvalds for (; *c; c += 2) 19941da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 199521fdddeaSJames Courtier-Dutton 1996e217b960SRaymond Yau if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */ 1997e217b960SRaymond Yau remove_ctl(card, "Center Playback Volume"); 1998e217b960SRaymond Yau remove_ctl(card, "LFE Playback Volume"); 1999e217b960SRaymond Yau remove_ctl(card, "Wave Center Playback Volume"); 2000e217b960SRaymond Yau remove_ctl(card, "Wave LFE Playback Volume"); 2001e217b960SRaymond Yau } 2002e3b9bc0eSJames Courtier-Dutton if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ 2003e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); 2004e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); 2005e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); 2006e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); 2007e3b9bc0eSJames Courtier-Dutton } 20081da177e4SLinus Torvalds if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) 20091da177e4SLinus Torvalds return -ENOMEM; 201067ed4161SClemens Ladisch kctl->id.device = pcm_device; 20111da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 20121da177e4SLinus Torvalds return err; 20131da177e4SLinus Torvalds if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL) 20141da177e4SLinus Torvalds return -ENOMEM; 201567ed4161SClemens Ladisch kctl->id.device = pcm_device; 20161da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 20171da177e4SLinus Torvalds return err; 20181da177e4SLinus Torvalds if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL) 20191da177e4SLinus Torvalds return -ENOMEM; 202067ed4161SClemens Ladisch kctl->id.device = pcm_device; 20211da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 20221da177e4SLinus Torvalds return err; 20231da177e4SLinus Torvalds 20241da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL) 20251da177e4SLinus Torvalds return -ENOMEM; 202667ed4161SClemens Ladisch kctl->id.device = multi_device; 20271da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 20281da177e4SLinus Torvalds return err; 20291da177e4SLinus Torvalds 20301da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL) 20311da177e4SLinus Torvalds return -ENOMEM; 203267ed4161SClemens Ladisch kctl->id.device = multi_device; 20331da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 20341da177e4SLinus Torvalds return err; 20351da177e4SLinus Torvalds 20361da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL) 20371da177e4SLinus Torvalds return -ENOMEM; 203867ed4161SClemens Ladisch kctl->id.device = multi_device; 20391da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 20401da177e4SLinus Torvalds return err; 20411da177e4SLinus Torvalds 20421da177e4SLinus Torvalds /* initialize the routing and volume table for each pcm playback stream */ 20431da177e4SLinus Torvalds for (pcm = 0; pcm < 32; pcm++) { 2044eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 20451da177e4SLinus Torvalds int v; 20461da177e4SLinus Torvalds 20471da177e4SLinus Torvalds mix = &emu->pcm_mixer[pcm]; 20481da177e4SLinus Torvalds mix->epcm = NULL; 20491da177e4SLinus Torvalds 20501da177e4SLinus Torvalds for (v = 0; v < 4; v++) 20511da177e4SLinus Torvalds mix->send_routing[0][v] = 20521da177e4SLinus Torvalds mix->send_routing[1][v] = 20531da177e4SLinus Torvalds mix->send_routing[2][v] = v; 20541da177e4SLinus Torvalds 20551da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 20561da177e4SLinus Torvalds mix->send_volume[0][0] = mix->send_volume[0][1] = 20571da177e4SLinus Torvalds mix->send_volume[1][0] = mix->send_volume[2][1] = 255; 20581da177e4SLinus Torvalds 20591da177e4SLinus Torvalds mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; 20601da177e4SLinus Torvalds } 20611da177e4SLinus Torvalds 20621da177e4SLinus Torvalds /* initialize the routing and volume table for the multichannel playback stream */ 20631da177e4SLinus Torvalds for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) { 2064eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 20651da177e4SLinus Torvalds int v; 20661da177e4SLinus Torvalds 20671da177e4SLinus Torvalds mix = &emu->efx_pcm_mixer[pcm]; 20681da177e4SLinus Torvalds mix->epcm = NULL; 20691da177e4SLinus Torvalds 20701da177e4SLinus Torvalds mix->send_routing[0][0] = pcm; 20711da177e4SLinus Torvalds mix->send_routing[0][1] = (pcm == 0) ? 1 : 0; 20721da177e4SLinus Torvalds for (v = 0; v < 2; v++) 20731da177e4SLinus Torvalds mix->send_routing[0][2+v] = 13+v; 20741da177e4SLinus Torvalds if (emu->audigy) 20751da177e4SLinus Torvalds for (v = 0; v < 4; v++) 20761da177e4SLinus Torvalds mix->send_routing[0][4+v] = 60+v; 20771da177e4SLinus Torvalds 20781da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 20791da177e4SLinus Torvalds mix->send_volume[0][0] = 255; 20801da177e4SLinus Torvalds 20811da177e4SLinus Torvalds mix->attn[0] = 0xffff; 20821da177e4SLinus Torvalds } 20831da177e4SLinus Torvalds 20842b637da5SLee Revell if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */ 20851da177e4SLinus Torvalds /* sb live! and audigy */ 20861da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) 20871da177e4SLinus Torvalds return -ENOMEM; 20885549d549SClemens Ladisch if (!emu->audigy) 20895549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 20901da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 20911da177e4SLinus Torvalds return err; 20921da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) 20931da177e4SLinus Torvalds return -ENOMEM; 20945549d549SClemens Ladisch if (!emu->audigy) 20955549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 20961da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 20971da177e4SLinus Torvalds return err; 20981da177e4SLinus Torvalds } 20991da177e4SLinus Torvalds 2100190d2c46SJames Courtier-Dutton if (emu->card_capabilities->emu_model) { 210119b99fbaSJames Courtier-Dutton ; /* Disable the snd_audigy_spdif_shared_spdif */ 210219b99fbaSJames Courtier-Dutton } else if (emu->audigy) { 21031da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) 21041da177e4SLinus Torvalds return -ENOMEM; 21051da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 21061da177e4SLinus Torvalds return err; 2107001f7589SJames Courtier-Dutton #if 0 21081da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) 21091da177e4SLinus Torvalds return -ENOMEM; 21101da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 21111da177e4SLinus Torvalds return err; 2112001f7589SJames Courtier-Dutton #endif 21132b637da5SLee Revell } else if (! emu->card_capabilities->ecard) { 21141da177e4SLinus Torvalds /* sb live! */ 21151da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) 21161da177e4SLinus Torvalds return -ENOMEM; 21171da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 21181da177e4SLinus Torvalds return err; 21191da177e4SLinus Torvalds } 21202b637da5SLee Revell if (emu->card_capabilities->ca0151_chip) { /* P16V */ 21211da177e4SLinus Torvalds if ((err = snd_p16v_mixer(emu))) 21221da177e4SLinus Torvalds return err; 21231da177e4SLinus Torvalds } 21241da177e4SLinus Torvalds 21253839e4f1STakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { 21261c02e366SCtirad Fertr /* 1616(m) cardbus */ 21279f4bd5ddSJames Courtier-Dutton int i; 21289f4bd5ddSJames Courtier-Dutton 21291c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) { 21301c02e366SCtirad Fertr err = snd_ctl_add(card, 21311c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1616_output_enum_ctls[i], 21321c02e366SCtirad Fertr emu)); 21339f4bd5ddSJames Courtier-Dutton if (err < 0) 21349f4bd5ddSJames Courtier-Dutton return err; 21359f4bd5ddSJames Courtier-Dutton } 21369f4bd5ddSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { 21371c02e366SCtirad Fertr err = snd_ctl_add(card, 21381c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], 21391c02e366SCtirad Fertr emu)); 21401c02e366SCtirad Fertr if (err < 0) 21411c02e366SCtirad Fertr return err; 21421c02e366SCtirad Fertr } 21431c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) { 21441c02e366SCtirad Fertr err = snd_ctl_add(card, 21451c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); 21461c02e366SCtirad Fertr if (err < 0) 21471c02e366SCtirad Fertr return err; 21481c02e366SCtirad Fertr } 21491c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) { 21501c02e366SCtirad Fertr err = snd_ctl_add(card, 21511c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); 21521c02e366SCtirad Fertr if (err < 0) 21531c02e366SCtirad Fertr return err; 21541c02e366SCtirad Fertr } 21551c02e366SCtirad Fertr err = snd_ctl_add(card, 21561c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 21571c02e366SCtirad Fertr if (err < 0) 21581c02e366SCtirad Fertr return err; 215999dcab46SMichael Gernoth err = snd_ctl_add(card, 216099dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_out, emu)); 216199dcab46SMichael Gernoth if (err < 0) 216299dcab46SMichael Gernoth return err; 216399dcab46SMichael Gernoth err = snd_ctl_add(card, 216499dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_in, emu)); 216599dcab46SMichael Gernoth if (err < 0) 216699dcab46SMichael Gernoth return err; 21671c02e366SCtirad Fertr 216888aa1390STakashi Iwai } else if (emu->card_capabilities->emu_model) { 21691c02e366SCtirad Fertr /* all other e-mu cards for now */ 21701c02e366SCtirad Fertr int i; 21711c02e366SCtirad Fertr 21721c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { 21731c02e366SCtirad Fertr err = snd_ctl_add(card, 21741c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], 21751c02e366SCtirad Fertr emu)); 21761c02e366SCtirad Fertr if (err < 0) 21771c02e366SCtirad Fertr return err; 21781c02e366SCtirad Fertr } 21791c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { 21801c02e366SCtirad Fertr err = snd_ctl_add(card, 21811c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], 21821c02e366SCtirad Fertr emu)); 21839f4bd5ddSJames Courtier-Dutton if (err < 0) 21849f4bd5ddSJames Courtier-Dutton return err; 21859f4bd5ddSJames Courtier-Dutton } 21869148cc50SJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { 21871c02e366SCtirad Fertr err = snd_ctl_add(card, 21881c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); 21899148cc50SJames Courtier-Dutton if (err < 0) 21909148cc50SJames Courtier-Dutton return err; 21919148cc50SJames Courtier-Dutton } 21929148cc50SJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { 21931c02e366SCtirad Fertr err = snd_ctl_add(card, 21941c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); 21959148cc50SJames Courtier-Dutton if (err < 0) 21969148cc50SJames Courtier-Dutton return err; 21979148cc50SJames Courtier-Dutton } 21981c02e366SCtirad Fertr err = snd_ctl_add(card, 21991c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 2200b0dbdaeaSJames Courtier-Dutton if (err < 0) 2201b0dbdaeaSJames Courtier-Dutton return err; 220299dcab46SMichael Gernoth err = snd_ctl_add(card, 220399dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_out, emu)); 220499dcab46SMichael Gernoth if (err < 0) 220599dcab46SMichael Gernoth return err; 220699dcab46SMichael Gernoth err = snd_ctl_add(card, 220799dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_in, emu)); 220899dcab46SMichael Gernoth if (err < 0) 220999dcab46SMichael Gernoth return err; 22109f4bd5ddSJames Courtier-Dutton } 22119f4bd5ddSJames Courtier-Dutton 2212184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 2213184c1e2cSJames Courtier-Dutton int i; 2214184c1e2cSJames Courtier-Dutton 2215184c1e2cSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); 2216184c1e2cSJames Courtier-Dutton if (err < 0) 2217184c1e2cSJames Courtier-Dutton return err; 2218184c1e2cSJames Courtier-Dutton 2219184c1e2cSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { 2220184c1e2cSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); 2221184c1e2cSJames Courtier-Dutton if (err < 0) 2222184c1e2cSJames Courtier-Dutton return err; 2223184c1e2cSJames Courtier-Dutton } 2224184c1e2cSJames Courtier-Dutton } 2225184c1e2cSJames Courtier-Dutton 222616950e09STakashi Iwai if (emu->card_capabilities->ac97_chip && emu->audigy) { 222716950e09STakashi Iwai err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost, 222816950e09STakashi Iwai emu)); 222916950e09STakashi Iwai if (err < 0) 223016950e09STakashi Iwai return err; 223116950e09STakashi Iwai } 223216950e09STakashi Iwai 22331da177e4SLinus Torvalds return 0; 22341da177e4SLinus Torvalds } 2235