11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 3c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, 41da177e4SLinus Torvalds * Takashi Iwai <tiwai@suse.de> 51da177e4SLinus Torvalds * Creative Labs, Inc. 61da177e4SLinus Torvalds * Routines for control of EMU10K1 chips / mixer routines 71da177e4SLinus Torvalds * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> 81da177e4SLinus Torvalds * 99f4bd5ddSJames Courtier-Dutton * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> 109f4bd5ddSJames Courtier-Dutton * Added EMU 1010 support. 119f4bd5ddSJames Courtier-Dutton * 121da177e4SLinus Torvalds * BUGS: 131da177e4SLinus Torvalds * -- 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * TODO: 161da177e4SLinus Torvalds * -- 171da177e4SLinus Torvalds */ 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds #include <linux/time.h> 201da177e4SLinus Torvalds #include <linux/init.h> 211da177e4SLinus Torvalds #include <sound/core.h> 221da177e4SLinus Torvalds #include <sound/emu10k1.h> 23b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h> 24184c1e2cSJames Courtier-Dutton #include <sound/tlv.h> 25184c1e2cSJames Courtier-Dutton 26184c1e2cSJames Courtier-Dutton #include "p17v.h" 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #define AC97_ID_STAC9758 0x83847658 291da177e4SLinus Torvalds 300cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ 31184c1e2cSJames Courtier-Dutton 32eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 331da177e4SLinus Torvalds { 341da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 351da177e4SLinus Torvalds uinfo->count = 1; 361da177e4SLinus Torvalds return 0; 371da177e4SLinus Torvalds } 381da177e4SLinus Torvalds 39eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol, 40eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 411da177e4SLinus Torvalds { 42eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 431da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 441da177e4SLinus Torvalds unsigned long flags; 451da177e4SLinus Torvalds 4674415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 4774415a36SJames Courtier-Dutton if (idx >= 3) 4874415a36SJames Courtier-Dutton return -EINVAL; 491da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 501da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 511da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 521da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 531da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 541da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 551da177e4SLinus Torvalds return 0; 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 58eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, 59eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 601da177e4SLinus Torvalds { 611da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = 0xff; 621da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = 0xff; 631da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = 0xff; 641da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = 0xff; 651da177e4SLinus Torvalds return 0; 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 6813d45709SPavel Hofman /* 6913d45709SPavel Hofman * Items labels in enum mixer controls assigning source data to 7013d45709SPavel Hofman * each destination 7113d45709SPavel Hofman */ 721541c66dSTakashi Iwai static const char * const emu1010_src_texts[] = { 739f4bd5ddSJames Courtier-Dutton "Silence", 749f4bd5ddSJames Courtier-Dutton "Dock Mic A", 759f4bd5ddSJames Courtier-Dutton "Dock Mic B", 769f4bd5ddSJames Courtier-Dutton "Dock ADC1 Left", 779f4bd5ddSJames Courtier-Dutton "Dock ADC1 Right", 789f4bd5ddSJames Courtier-Dutton "Dock ADC2 Left", 799f4bd5ddSJames Courtier-Dutton "Dock ADC2 Right", 809f4bd5ddSJames Courtier-Dutton "Dock ADC3 Left", 819f4bd5ddSJames Courtier-Dutton "Dock ADC3 Right", 829f4bd5ddSJames Courtier-Dutton "0202 ADC Left", 839f4bd5ddSJames Courtier-Dutton "0202 ADC Right", 849f4bd5ddSJames Courtier-Dutton "0202 SPDIF Left", 859f4bd5ddSJames Courtier-Dutton "0202 SPDIF Right", 869f4bd5ddSJames Courtier-Dutton "ADAT 0", 879f4bd5ddSJames Courtier-Dutton "ADAT 1", 889f4bd5ddSJames Courtier-Dutton "ADAT 2", 899f4bd5ddSJames Courtier-Dutton "ADAT 3", 909f4bd5ddSJames Courtier-Dutton "ADAT 4", 919f4bd5ddSJames Courtier-Dutton "ADAT 5", 929f4bd5ddSJames Courtier-Dutton "ADAT 6", 939f4bd5ddSJames Courtier-Dutton "ADAT 7", 949f4bd5ddSJames Courtier-Dutton "DSP 0", 959f4bd5ddSJames Courtier-Dutton "DSP 1", 969f4bd5ddSJames Courtier-Dutton "DSP 2", 979f4bd5ddSJames Courtier-Dutton "DSP 3", 989f4bd5ddSJames Courtier-Dutton "DSP 4", 999f4bd5ddSJames Courtier-Dutton "DSP 5", 1009f4bd5ddSJames Courtier-Dutton "DSP 6", 1019f4bd5ddSJames Courtier-Dutton "DSP 7", 1029f4bd5ddSJames Courtier-Dutton "DSP 8", 1039f4bd5ddSJames Courtier-Dutton "DSP 9", 1049f4bd5ddSJames Courtier-Dutton "DSP 10", 1059f4bd5ddSJames Courtier-Dutton "DSP 11", 1069f4bd5ddSJames Courtier-Dutton "DSP 12", 1079f4bd5ddSJames Courtier-Dutton "DSP 13", 1089f4bd5ddSJames Courtier-Dutton "DSP 14", 1099f4bd5ddSJames Courtier-Dutton "DSP 15", 1109f4bd5ddSJames Courtier-Dutton "DSP 16", 1119f4bd5ddSJames Courtier-Dutton "DSP 17", 1129f4bd5ddSJames Courtier-Dutton "DSP 18", 1139f4bd5ddSJames Courtier-Dutton "DSP 19", 1149f4bd5ddSJames Courtier-Dutton "DSP 20", 1159f4bd5ddSJames Courtier-Dutton "DSP 21", 1169f4bd5ddSJames Courtier-Dutton "DSP 22", 1179f4bd5ddSJames Courtier-Dutton "DSP 23", 1189f4bd5ddSJames Courtier-Dutton "DSP 24", 1199f4bd5ddSJames Courtier-Dutton "DSP 25", 1209f4bd5ddSJames Courtier-Dutton "DSP 26", 1219f4bd5ddSJames Courtier-Dutton "DSP 27", 1229f4bd5ddSJames Courtier-Dutton "DSP 28", 1239f4bd5ddSJames Courtier-Dutton "DSP 29", 1249f4bd5ddSJames Courtier-Dutton "DSP 30", 1259f4bd5ddSJames Courtier-Dutton "DSP 31", 1269f4bd5ddSJames Courtier-Dutton }; 1279f4bd5ddSJames Courtier-Dutton 1281c02e366SCtirad Fertr /* 1616(m) cardbus */ 1291c02e366SCtirad Fertr 1301541c66dSTakashi Iwai static const char * const emu1616_src_texts[] = { 1311c02e366SCtirad Fertr "Silence", 1321c02e366SCtirad Fertr "Dock Mic A", 1331c02e366SCtirad Fertr "Dock Mic B", 1341c02e366SCtirad Fertr "Dock ADC1 Left", 1351c02e366SCtirad Fertr "Dock ADC1 Right", 1361c02e366SCtirad Fertr "Dock ADC2 Left", 1371c02e366SCtirad Fertr "Dock ADC2 Right", 1381c02e366SCtirad Fertr "Dock SPDIF Left", 1391c02e366SCtirad Fertr "Dock SPDIF Right", 1401c02e366SCtirad Fertr "ADAT 0", 1411c02e366SCtirad Fertr "ADAT 1", 1421c02e366SCtirad Fertr "ADAT 2", 1431c02e366SCtirad Fertr "ADAT 3", 1441c02e366SCtirad Fertr "ADAT 4", 1451c02e366SCtirad Fertr "ADAT 5", 1461c02e366SCtirad Fertr "ADAT 6", 1471c02e366SCtirad Fertr "ADAT 7", 1481c02e366SCtirad Fertr "DSP 0", 1491c02e366SCtirad Fertr "DSP 1", 1501c02e366SCtirad Fertr "DSP 2", 1511c02e366SCtirad Fertr "DSP 3", 1521c02e366SCtirad Fertr "DSP 4", 1531c02e366SCtirad Fertr "DSP 5", 1541c02e366SCtirad Fertr "DSP 6", 1551c02e366SCtirad Fertr "DSP 7", 1561c02e366SCtirad Fertr "DSP 8", 1571c02e366SCtirad Fertr "DSP 9", 1581c02e366SCtirad Fertr "DSP 10", 1591c02e366SCtirad Fertr "DSP 11", 1601c02e366SCtirad Fertr "DSP 12", 1611c02e366SCtirad Fertr "DSP 13", 1621c02e366SCtirad Fertr "DSP 14", 1631c02e366SCtirad Fertr "DSP 15", 1641c02e366SCtirad Fertr "DSP 16", 1651c02e366SCtirad Fertr "DSP 17", 1661c02e366SCtirad Fertr "DSP 18", 1671c02e366SCtirad Fertr "DSP 19", 1681c02e366SCtirad Fertr "DSP 20", 1691c02e366SCtirad Fertr "DSP 21", 1701c02e366SCtirad Fertr "DSP 22", 1711c02e366SCtirad Fertr "DSP 23", 1721c02e366SCtirad Fertr "DSP 24", 1731c02e366SCtirad Fertr "DSP 25", 1741c02e366SCtirad Fertr "DSP 26", 1751c02e366SCtirad Fertr "DSP 27", 1761c02e366SCtirad Fertr "DSP 28", 1771c02e366SCtirad Fertr "DSP 29", 1781c02e366SCtirad Fertr "DSP 30", 1791c02e366SCtirad Fertr "DSP 31", 1801c02e366SCtirad Fertr }; 1811c02e366SCtirad Fertr 1821c02e366SCtirad Fertr 18313d45709SPavel Hofman /* 18413d45709SPavel Hofman * List of data sources available for each destination 18513d45709SPavel Hofman */ 1866fddce26STakashi Iwai static const unsigned int emu1010_src_regs[] = { 1879f4bd5ddSJames Courtier-Dutton EMU_SRC_SILENCE,/* 0 */ 1889f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_MIC_A1, /* 1 */ 1899f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_MIC_B1, /* 2 */ 1909f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */ 1919f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */ 1929f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */ 1939f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */ 1949f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */ 1959f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */ 1969f4bd5ddSJames Courtier-Dutton EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */ 1979f4bd5ddSJames Courtier-Dutton EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */ 1989f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */ 1999f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */ 2009f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT, /* 13 */ 2019f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+1, /* 14 */ 2029f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+2, /* 15 */ 2039f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+3, /* 16 */ 2049f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+4, /* 17 */ 2059f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+5, /* 18 */ 2069f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+6, /* 19 */ 2079f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+7, /* 20 */ 2089f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A, /* 21 */ 2099f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+1, /* 22 */ 2109f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+2, /* 23 */ 2119f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+3, /* 24 */ 2129f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+4, /* 25 */ 2139f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+5, /* 26 */ 2149f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+6, /* 27 */ 2159f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+7, /* 28 */ 2169f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+8, /* 29 */ 2179f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+9, /* 30 */ 2189f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xa, /* 31 */ 2199f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xb, /* 32 */ 2209f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xc, /* 33 */ 2219f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xd, /* 34 */ 2229f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xe, /* 35 */ 2239f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xf, /* 36 */ 2249f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B, /* 37 */ 2259f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+1, /* 38 */ 2269f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+2, /* 39 */ 2279f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+3, /* 40 */ 2289f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+4, /* 41 */ 2299f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+5, /* 42 */ 2309f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+6, /* 43 */ 2319f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+7, /* 44 */ 2329f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+8, /* 45 */ 2339f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+9, /* 46 */ 2349f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xa, /* 47 */ 2359f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xb, /* 48 */ 2369f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xc, /* 49 */ 2379f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xd, /* 50 */ 2389f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xe, /* 51 */ 2399f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ 2409f4bd5ddSJames Courtier-Dutton }; 2419f4bd5ddSJames Courtier-Dutton 2421c02e366SCtirad Fertr /* 1616(m) cardbus */ 2436fddce26STakashi Iwai static const unsigned int emu1616_src_regs[] = { 2441c02e366SCtirad Fertr EMU_SRC_SILENCE, 2451c02e366SCtirad Fertr EMU_SRC_DOCK_MIC_A1, 2461c02e366SCtirad Fertr EMU_SRC_DOCK_MIC_B1, 2471c02e366SCtirad Fertr EMU_SRC_DOCK_ADC1_LEFT1, 2481c02e366SCtirad Fertr EMU_SRC_DOCK_ADC1_RIGHT1, 2491c02e366SCtirad Fertr EMU_SRC_DOCK_ADC2_LEFT1, 2501c02e366SCtirad Fertr EMU_SRC_DOCK_ADC2_RIGHT1, 2511c02e366SCtirad Fertr EMU_SRC_MDOCK_SPDIF_LEFT1, 2521c02e366SCtirad Fertr EMU_SRC_MDOCK_SPDIF_RIGHT1, 2531c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT, 2541c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+1, 2551c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+2, 2561c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+3, 2571c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+4, 2581c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+5, 2591c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+6, 2601c02e366SCtirad Fertr EMU_SRC_MDOCK_ADAT+7, 2611c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A, 2621c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+1, 2631c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+2, 2641c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+3, 2651c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+4, 2661c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+5, 2671c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+6, 2681c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+7, 2691c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+8, 2701c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+9, 2711c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xa, 2721c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xb, 2731c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xc, 2741c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xd, 2751c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xe, 2761c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32A+0xf, 2771c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B, 2781c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+1, 2791c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+2, 2801c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+3, 2811c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+4, 2821c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+5, 2831c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+6, 2841c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+7, 2851c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+8, 2861c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+9, 2871c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xa, 2881c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xb, 2891c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xc, 2901c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xd, 2911c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xe, 2921c02e366SCtirad Fertr EMU_SRC_ALICE_EMU32B+0xf, 2931c02e366SCtirad Fertr }; 2941c02e366SCtirad Fertr 29513d45709SPavel Hofman /* 29613d45709SPavel Hofman * Data destinations - physical EMU outputs. 29713d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 29813d45709SPavel Hofman */ 2996fddce26STakashi Iwai static const unsigned int emu1010_output_dst[] = { 3009f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ 3019f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ 3029f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ 3039f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ 3049f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ 3059f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ 3069f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ 3079f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ 3089f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ 3099f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ 3109f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ 3119f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ 3129f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ 3139f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ 3149f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ 3159f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ 3169f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT, /* 16 */ 3179f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+1, /* 17 */ 3189f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+2, /* 18 */ 3199f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+3, /* 19 */ 3209f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+4, /* 20 */ 3219f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+5, /* 21 */ 3229f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+6, /* 22 */ 3239f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+7, /* 23 */ 3249f4bd5ddSJames Courtier-Dutton }; 3259f4bd5ddSJames Courtier-Dutton 3261c02e366SCtirad Fertr /* 1616(m) cardbus */ 3276fddce26STakashi Iwai static const unsigned int emu1616_output_dst[] = { 3281c02e366SCtirad Fertr EMU_DST_DOCK_DAC1_LEFT1, 3291c02e366SCtirad Fertr EMU_DST_DOCK_DAC1_RIGHT1, 3301c02e366SCtirad Fertr EMU_DST_DOCK_DAC2_LEFT1, 3311c02e366SCtirad Fertr EMU_DST_DOCK_DAC2_RIGHT1, 3321c02e366SCtirad Fertr EMU_DST_DOCK_DAC3_LEFT1, 3331c02e366SCtirad Fertr EMU_DST_DOCK_DAC3_RIGHT1, 3341c02e366SCtirad Fertr EMU_DST_MDOCK_SPDIF_LEFT1, 3351c02e366SCtirad Fertr EMU_DST_MDOCK_SPDIF_RIGHT1, 3361c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT, 3371c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+1, 3381c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+2, 3391c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+3, 3401c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+4, 3411c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+5, 3421c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+6, 3431c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+7, 3441c02e366SCtirad Fertr EMU_DST_MANA_DAC_LEFT, 3451c02e366SCtirad Fertr EMU_DST_MANA_DAC_RIGHT, 3461c02e366SCtirad Fertr }; 3471c02e366SCtirad Fertr 34813d45709SPavel Hofman /* 34913d45709SPavel Hofman * Data destinations - HANA outputs going to Alice2 (audigy) for 35013d45709SPavel Hofman * capture (EMU32 + I2S links) 35113d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 35213d45709SPavel Hofman */ 3536fddce26STakashi Iwai static const unsigned int emu1010_input_dst[] = { 3549f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_0, 3559f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_1, 3569f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_2, 3579f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_3, 3589f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_4, 3599f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_5, 3609f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_6, 3619f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_7, 3629f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_8, 3639f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_9, 3649f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_A, 3659f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_B, 3669f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_C, 3679f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_D, 3689f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_E, 3699f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_F, 3709f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_LEFT, 3719f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_RIGHT, 3729f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_LEFT, 3739f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_RIGHT, 3749f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_LEFT, 3759f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_RIGHT, 3769f4bd5ddSJames Courtier-Dutton }; 3779f4bd5ddSJames Courtier-Dutton 3781c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, 3791c02e366SCtirad Fertr struct snd_ctl_elem_info *uinfo) 3809f4bd5ddSJames Courtier-Dutton { 3811c02e366SCtirad Fertr struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 3821c02e366SCtirad Fertr 3831541c66dSTakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 3841541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts); 3851541c66dSTakashi Iwai else 3861541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts); 3879f4bd5ddSJames Courtier-Dutton } 3889f4bd5ddSJames Courtier-Dutton 3899f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, 3909f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 3919f4bd5ddSJames Courtier-Dutton { 3929f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 39374415a36SJames Courtier-Dutton unsigned int channel; 3949f4bd5ddSJames Courtier-Dutton 3959f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 39674415a36SJames Courtier-Dutton /* Limit: emu1010_output_dst, emu->emu1010.output_source */ 3971c02e366SCtirad Fertr if (channel >= 24 || 3983839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 3993839e4f1STakashi Iwai channel >= 18)) 40074415a36SJames Courtier-Dutton return -EINVAL; 4019f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; 4029f4bd5ddSJames Courtier-Dutton return 0; 4039f4bd5ddSJames Courtier-Dutton } 4049f4bd5ddSJames Courtier-Dutton 4059f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, 4069f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4079f4bd5ddSJames Courtier-Dutton { 4089f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4099f4bd5ddSJames Courtier-Dutton unsigned int val; 41074415a36SJames Courtier-Dutton unsigned int channel; 4119f4bd5ddSJames Courtier-Dutton 412aa299d01STakashi Iwai val = ucontrol->value.enumerated.item[0]; 4131c02e366SCtirad Fertr if (val >= 53 || 4143839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 4153839e4f1STakashi Iwai val >= 49)) 416aa299d01STakashi Iwai return -EINVAL; 4179f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 41874415a36SJames Courtier-Dutton /* Limit: emu1010_output_dst, emu->emu1010.output_source */ 4191c02e366SCtirad Fertr if (channel >= 24 || 4203839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 4213839e4f1STakashi Iwai channel >= 18)) 42274415a36SJames Courtier-Dutton return -EINVAL; 4231c02e366SCtirad Fertr if (emu->emu1010.output_source[channel] == val) 4241c02e366SCtirad Fertr return 0; 425aa299d01STakashi Iwai emu->emu1010.output_source[channel] = val; 4263839e4f1STakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 4271c02e366SCtirad Fertr snd_emu1010_fpga_link_dst_src_write(emu, 4281c02e366SCtirad Fertr emu1616_output_dst[channel], emu1616_src_regs[val]); 4291c02e366SCtirad Fertr else 4309f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 4319f4bd5ddSJames Courtier-Dutton emu1010_output_dst[channel], emu1010_src_regs[val]); 4321c02e366SCtirad Fertr return 1; 4339f4bd5ddSJames Courtier-Dutton } 4349f4bd5ddSJames Courtier-Dutton 4359f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, 4369f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4379f4bd5ddSJames Courtier-Dutton { 4389f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 43974415a36SJames Courtier-Dutton unsigned int channel; 4409f4bd5ddSJames Courtier-Dutton 4419f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 44274415a36SJames Courtier-Dutton /* Limit: emu1010_input_dst, emu->emu1010.input_source */ 44374415a36SJames Courtier-Dutton if (channel >= 22) 44474415a36SJames Courtier-Dutton return -EINVAL; 4459f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; 4469f4bd5ddSJames Courtier-Dutton return 0; 4479f4bd5ddSJames Courtier-Dutton } 4489f4bd5ddSJames Courtier-Dutton 4499f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(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); 4539f4bd5ddSJames Courtier-Dutton unsigned int val; 45474415a36SJames Courtier-Dutton unsigned int channel; 4559f4bd5ddSJames Courtier-Dutton 456aa299d01STakashi Iwai val = ucontrol->value.enumerated.item[0]; 4571c02e366SCtirad Fertr if (val >= 53 || 4583839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 4593839e4f1STakashi Iwai val >= 49)) 460aa299d01STakashi Iwai return -EINVAL; 4619f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 46274415a36SJames Courtier-Dutton /* Limit: emu1010_input_dst, emu->emu1010.input_source */ 46374415a36SJames Courtier-Dutton if (channel >= 22) 46474415a36SJames Courtier-Dutton return -EINVAL; 4651c02e366SCtirad Fertr if (emu->emu1010.input_source[channel] == val) 4661c02e366SCtirad Fertr return 0; 467aa299d01STakashi Iwai emu->emu1010.input_source[channel] = val; 4683839e4f1STakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 4691c02e366SCtirad Fertr snd_emu1010_fpga_link_dst_src_write(emu, 4701c02e366SCtirad Fertr emu1010_input_dst[channel], emu1616_src_regs[val]); 4711c02e366SCtirad Fertr else 4729f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 4739f4bd5ddSJames Courtier-Dutton emu1010_input_dst[channel], emu1010_src_regs[val]); 4741c02e366SCtirad Fertr return 1; 4759f4bd5ddSJames Courtier-Dutton } 4769f4bd5ddSJames Courtier-Dutton 4779f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \ 4789f4bd5ddSJames Courtier-Dutton { \ 4799f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 4809f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 4819f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 4829f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_output_source_get, \ 4839f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_output_source_put, \ 4849f4bd5ddSJames Courtier-Dutton .private_value = chid \ 4859f4bd5ddSJames Courtier-Dutton } 4869f4bd5ddSJames Courtier-Dutton 487b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = { 4884c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), 4894c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), 4904c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), 4914c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), 4924c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), 4934c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), 4944c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6), 4954c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7), 4964c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8), 4974c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9), 4984c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa), 4994c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb), 5004c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc), 5014c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd), 5024c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe), 5034c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf), 5044c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10), 5054c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11), 5064c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12), 5074c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13), 5084c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14), 5094c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15), 5104c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16), 5114c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), 5129f4bd5ddSJames Courtier-Dutton }; 5139f4bd5ddSJames Courtier-Dutton 5141c02e366SCtirad Fertr 5151c02e366SCtirad Fertr /* 1616(m) cardbus */ 516b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = { 5171c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), 5181c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), 5191c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), 5201c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), 5211c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), 5221c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), 5231c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6), 5241c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7), 5251c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8), 5261c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9), 5271c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa), 5281c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb), 5291c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc), 5301c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd), 5311c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe), 5321c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf), 5331c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10), 5341c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11), 5351c02e366SCtirad Fertr }; 5361c02e366SCtirad Fertr 5371c02e366SCtirad Fertr 5389f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \ 5399f4bd5ddSJames Courtier-Dutton { \ 5409f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 5419f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 5429f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 5439f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_input_source_get, \ 5449f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_input_source_put, \ 5459f4bd5ddSJames Courtier-Dutton .private_value = chid \ 5469f4bd5ddSJames Courtier-Dutton } 5479f4bd5ddSJames Courtier-Dutton 548b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = { 5494c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), 5504c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), 5514c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), 5524c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3), 5534c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4), 5544c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5), 5554c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6), 5564c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7), 5574c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8), 5584c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9), 5594c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa), 5604c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb), 5614c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc), 5624c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd), 5634c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe), 5644c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf), 5654c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10), 5664c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11), 5674c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12), 5684c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13), 5694c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14), 5704c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15), 5719148cc50SJames Courtier-Dutton }; 5729148cc50SJames Courtier-Dutton 5739148cc50SJames Courtier-Dutton 5749148cc50SJames Courtier-Dutton 575a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info 5769148cc50SJames Courtier-Dutton 5779148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5789148cc50SJames Courtier-Dutton { 5799148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 5809148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 5819148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; 5829148cc50SJames Courtier-Dutton return 0; 5839148cc50SJames Courtier-Dutton } 5849148cc50SJames Courtier-Dutton 5859148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5869148cc50SJames Courtier-Dutton { 5879148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 5889148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 5899148cc50SJames Courtier-Dutton unsigned int val, cache; 5909148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 5919148cc50SJames Courtier-Dutton cache = emu->emu1010.adc_pads; 5929148cc50SJames Courtier-Dutton if (val == 1) 5939148cc50SJames Courtier-Dutton cache = cache | mask; 5949148cc50SJames Courtier-Dutton else 5959148cc50SJames Courtier-Dutton cache = cache & ~mask; 5969148cc50SJames Courtier-Dutton if (cache != emu->emu1010.adc_pads) { 5979148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); 5989148cc50SJames Courtier-Dutton emu->emu1010.adc_pads = cache; 5999148cc50SJames Courtier-Dutton } 6009148cc50SJames Courtier-Dutton 6019148cc50SJames Courtier-Dutton return 0; 6029148cc50SJames Courtier-Dutton } 6039148cc50SJames Courtier-Dutton 6049148cc50SJames Courtier-Dutton 6059148cc50SJames Courtier-Dutton 6069148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \ 6079148cc50SJames Courtier-Dutton { \ 6089148cc50SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 6099148cc50SJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 6109148cc50SJames Courtier-Dutton .info = snd_emu1010_adc_pads_info, \ 6119148cc50SJames Courtier-Dutton .get = snd_emu1010_adc_pads_get, \ 6129148cc50SJames Courtier-Dutton .put = snd_emu1010_adc_pads_put, \ 6139148cc50SJames Courtier-Dutton .private_value = chid \ 6149148cc50SJames Courtier-Dutton } 6159148cc50SJames Courtier-Dutton 616b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_adc_pads[] = { 6179148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), 6189148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), 6199148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), 6209148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), 6219148cc50SJames Courtier-Dutton }; 6229148cc50SJames Courtier-Dutton 623a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info 6249148cc50SJames Courtier-Dutton 6259148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6269148cc50SJames Courtier-Dutton { 6279148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6289148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 6299148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; 6309148cc50SJames Courtier-Dutton return 0; 6319148cc50SJames Courtier-Dutton } 6329148cc50SJames Courtier-Dutton 6339148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6349148cc50SJames Courtier-Dutton { 6359148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6369148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 6379148cc50SJames Courtier-Dutton unsigned int val, cache; 6389148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 6399148cc50SJames Courtier-Dutton cache = emu->emu1010.dac_pads; 6409148cc50SJames Courtier-Dutton if (val == 1) 6419148cc50SJames Courtier-Dutton cache = cache | mask; 6429148cc50SJames Courtier-Dutton else 6439148cc50SJames Courtier-Dutton cache = cache & ~mask; 6449148cc50SJames Courtier-Dutton if (cache != emu->emu1010.dac_pads) { 6459148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); 6469148cc50SJames Courtier-Dutton emu->emu1010.dac_pads = cache; 6479148cc50SJames Courtier-Dutton } 6489148cc50SJames Courtier-Dutton 6499148cc50SJames Courtier-Dutton return 0; 6509148cc50SJames Courtier-Dutton } 6519148cc50SJames Courtier-Dutton 6529148cc50SJames Courtier-Dutton 6539148cc50SJames Courtier-Dutton 6549148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \ 6559148cc50SJames Courtier-Dutton { \ 6569148cc50SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 6579148cc50SJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 6589148cc50SJames Courtier-Dutton .info = snd_emu1010_dac_pads_info, \ 6599148cc50SJames Courtier-Dutton .get = snd_emu1010_dac_pads_get, \ 6609148cc50SJames Courtier-Dutton .put = snd_emu1010_dac_pads_put, \ 6619148cc50SJames Courtier-Dutton .private_value = chid \ 6629148cc50SJames Courtier-Dutton } 6639148cc50SJames Courtier-Dutton 664b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_dac_pads[] = { 6659148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), 6669148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), 6679148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), 6689148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4), 6699148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), 6709f4bd5ddSJames Courtier-Dutton }; 6719f4bd5ddSJames Courtier-Dutton 672b0dbdaeaSJames Courtier-Dutton 673b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, 674b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 675b0dbdaeaSJames Courtier-Dutton { 6761541c66dSTakashi Iwai static const char * const texts[4] = { 677edec7bbbSJames Courtier-Dutton "44100", "48000", "SPDIF", "ADAT" 678b0dbdaeaSJames Courtier-Dutton }; 679b0dbdaeaSJames Courtier-Dutton 6801541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 4, texts); 681b0dbdaeaSJames Courtier-Dutton } 682b0dbdaeaSJames Courtier-Dutton 683b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, 684b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 685b0dbdaeaSJames Courtier-Dutton { 686b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 687b0dbdaeaSJames Courtier-Dutton 688b0dbdaeaSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; 689b0dbdaeaSJames Courtier-Dutton return 0; 690b0dbdaeaSJames Courtier-Dutton } 691b0dbdaeaSJames Courtier-Dutton 692b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, 693b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 694b0dbdaeaSJames Courtier-Dutton { 695b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 696b0dbdaeaSJames Courtier-Dutton unsigned int val; 697b0dbdaeaSJames Courtier-Dutton int change = 0; 698b0dbdaeaSJames Courtier-Dutton 699b0dbdaeaSJames Courtier-Dutton val = ucontrol->value.enumerated.item[0] ; 70074415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 4; */ 70174415a36SJames Courtier-Dutton if (val >= 4) 70274415a36SJames Courtier-Dutton return -EINVAL; 703b0dbdaeaSJames Courtier-Dutton change = (emu->emu1010.internal_clock != val); 704b0dbdaeaSJames Courtier-Dutton if (change) { 705b0dbdaeaSJames Courtier-Dutton emu->emu1010.internal_clock = val; 706b0dbdaeaSJames Courtier-Dutton switch (val) { 707b0dbdaeaSJames Courtier-Dutton case 0: 708b0dbdaeaSJames Courtier-Dutton /* 44100 */ 709b0dbdaeaSJames Courtier-Dutton /* Mute all */ 710b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 711b0dbdaeaSJames Courtier-Dutton /* Default fallback clock 48kHz */ 712b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); 713b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 44.1kHz x1 */ 714b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 715b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); 716b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 717b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 718b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); 719b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 720e40a0b2eSJames Courtier-Dutton msleep(10); 721b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 722b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 723b0dbdaeaSJames Courtier-Dutton break; 724b0dbdaeaSJames Courtier-Dutton case 1: 725b0dbdaeaSJames Courtier-Dutton /* 48000 */ 726b0dbdaeaSJames Courtier-Dutton /* Mute all */ 727b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 728b0dbdaeaSJames Courtier-Dutton /* Default fallback clock 48kHz */ 729b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 730b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 48kHz x1 */ 731b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 732b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); 733b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 734b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 735b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); 736b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 737e40a0b2eSJames Courtier-Dutton msleep(10); 738b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 739b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 740b0dbdaeaSJames Courtier-Dutton break; 741edec7bbbSJames Courtier-Dutton 742edec7bbbSJames Courtier-Dutton case 2: /* Take clock from S/PDIF IN */ 743edec7bbbSJames Courtier-Dutton /* Mute all */ 744edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 745edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 746edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 747edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to S/PDIF input */ 748edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 749edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); 750edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 751edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 752edec7bbbSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 753edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 754edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 755edec7bbbSJames Courtier-Dutton msleep(10); 756edec7bbbSJames Courtier-Dutton /* Unmute all */ 757edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 758edec7bbbSJames Courtier-Dutton break; 759edec7bbbSJames Courtier-Dutton 760edec7bbbSJames Courtier-Dutton case 3: 761edec7bbbSJames Courtier-Dutton /* Take clock from ADAT IN */ 762edec7bbbSJames Courtier-Dutton /* Mute all */ 763edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 764edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 765edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 766edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to ADAT input */ 767edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 768edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); 769edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 770edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 771edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 772edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 773edec7bbbSJames Courtier-Dutton msleep(10); 774edec7bbbSJames Courtier-Dutton /* Unmute all */ 775edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 776edec7bbbSJames Courtier-Dutton 777edec7bbbSJames Courtier-Dutton 778edec7bbbSJames Courtier-Dutton break; 779b0dbdaeaSJames Courtier-Dutton } 780b0dbdaeaSJames Courtier-Dutton } 781b0dbdaeaSJames Courtier-Dutton return change; 782b0dbdaeaSJames Courtier-Dutton } 783b0dbdaeaSJames Courtier-Dutton 784f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock = 785b0dbdaeaSJames Courtier-Dutton { 786b0dbdaeaSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 787b0dbdaeaSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 788b0dbdaeaSJames Courtier-Dutton .name = "Clock Internal Rate", 789b0dbdaeaSJames Courtier-Dutton .count = 1, 790b0dbdaeaSJames Courtier-Dutton .info = snd_emu1010_internal_clock_info, 791b0dbdaeaSJames Courtier-Dutton .get = snd_emu1010_internal_clock_get, 792b0dbdaeaSJames Courtier-Dutton .put = snd_emu1010_internal_clock_put 793b0dbdaeaSJames Courtier-Dutton }; 794b0dbdaeaSJames Courtier-Dutton 79599dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol, 79699dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 79799dcab46SMichael Gernoth { 79899dcab46SMichael Gernoth static const char * const texts[2] = { 79999dcab46SMichael Gernoth "SPDIF", "ADAT" 80099dcab46SMichael Gernoth }; 80199dcab46SMichael Gernoth 80299dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 80399dcab46SMichael Gernoth } 80499dcab46SMichael Gernoth 80599dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol, 80699dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 80799dcab46SMichael Gernoth { 80899dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 80999dcab46SMichael Gernoth 81099dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out; 81199dcab46SMichael Gernoth return 0; 81299dcab46SMichael Gernoth } 81399dcab46SMichael Gernoth 81499dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol, 81599dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 81699dcab46SMichael Gernoth { 81799dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 81899dcab46SMichael Gernoth unsigned int val; 81999dcab46SMichael Gernoth u32 tmp; 82099dcab46SMichael Gernoth int change = 0; 82199dcab46SMichael Gernoth 82299dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 82399dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 82499dcab46SMichael Gernoth if (val >= 2) 82599dcab46SMichael Gernoth return -EINVAL; 82699dcab46SMichael Gernoth change = (emu->emu1010.optical_out != val); 82799dcab46SMichael Gernoth if (change) { 82899dcab46SMichael Gernoth emu->emu1010.optical_out = val; 82999dcab46SMichael Gernoth tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | 83099dcab46SMichael Gernoth (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); 83199dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 83299dcab46SMichael Gernoth } 83399dcab46SMichael Gernoth return change; 83499dcab46SMichael Gernoth } 83599dcab46SMichael Gernoth 836f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = { 83799dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 83899dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 83999dcab46SMichael Gernoth .name = "Optical Output Mode", 84099dcab46SMichael Gernoth .count = 1, 84199dcab46SMichael Gernoth .info = snd_emu1010_optical_out_info, 84299dcab46SMichael Gernoth .get = snd_emu1010_optical_out_get, 84399dcab46SMichael Gernoth .put = snd_emu1010_optical_out_put 84499dcab46SMichael Gernoth }; 84599dcab46SMichael Gernoth 84699dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol, 84799dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 84899dcab46SMichael Gernoth { 84999dcab46SMichael Gernoth static const char * const texts[2] = { 85099dcab46SMichael Gernoth "SPDIF", "ADAT" 85199dcab46SMichael Gernoth }; 85299dcab46SMichael Gernoth 85399dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 85499dcab46SMichael Gernoth } 85599dcab46SMichael Gernoth 85699dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol, 85799dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 85899dcab46SMichael Gernoth { 85999dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 86099dcab46SMichael Gernoth 86199dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in; 86299dcab46SMichael Gernoth return 0; 86399dcab46SMichael Gernoth } 86499dcab46SMichael Gernoth 86599dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol, 86699dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 86799dcab46SMichael Gernoth { 86899dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 86999dcab46SMichael Gernoth unsigned int val; 87099dcab46SMichael Gernoth u32 tmp; 87199dcab46SMichael Gernoth int change = 0; 87299dcab46SMichael Gernoth 87399dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 87499dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 87599dcab46SMichael Gernoth if (val >= 2) 87699dcab46SMichael Gernoth return -EINVAL; 87799dcab46SMichael Gernoth change = (emu->emu1010.optical_in != val); 87899dcab46SMichael Gernoth if (change) { 87999dcab46SMichael Gernoth emu->emu1010.optical_in = val; 88099dcab46SMichael Gernoth tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | 88199dcab46SMichael Gernoth (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); 88299dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 88399dcab46SMichael Gernoth } 88499dcab46SMichael Gernoth return change; 88599dcab46SMichael Gernoth } 88699dcab46SMichael Gernoth 887f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = { 88899dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 88999dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 89099dcab46SMichael Gernoth .name = "Optical Input Mode", 89199dcab46SMichael Gernoth .count = 1, 89299dcab46SMichael Gernoth .info = snd_emu1010_optical_in_info, 89399dcab46SMichael Gernoth .get = snd_emu1010_optical_in_get, 89499dcab46SMichael Gernoth .put = snd_emu1010_optical_in_put 89599dcab46SMichael Gernoth }; 89699dcab46SMichael Gernoth 897184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, 898184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 899184c1e2cSJames Courtier-Dutton { 900184c1e2cSJames Courtier-Dutton #if 0 9011541c66dSTakashi Iwai static const char * const texts[4] = { 902184c1e2cSJames Courtier-Dutton "Unknown1", "Unknown2", "Mic", "Line" 903184c1e2cSJames Courtier-Dutton }; 904184c1e2cSJames Courtier-Dutton #endif 9051541c66dSTakashi Iwai static const char * const texts[2] = { 906184c1e2cSJames Courtier-Dutton "Mic", "Line" 907184c1e2cSJames Courtier-Dutton }; 908184c1e2cSJames Courtier-Dutton 9091541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 2, texts); 910184c1e2cSJames Courtier-Dutton } 911184c1e2cSJames Courtier-Dutton 912184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, 913184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 914184c1e2cSJames Courtier-Dutton { 915184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 916184c1e2cSJames Courtier-Dutton 917184c1e2cSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; 918184c1e2cSJames Courtier-Dutton return 0; 919184c1e2cSJames Courtier-Dutton } 920184c1e2cSJames Courtier-Dutton 921184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, 922184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 923184c1e2cSJames Courtier-Dutton { 924184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 925184c1e2cSJames Courtier-Dutton unsigned int source_id; 926184c1e2cSJames Courtier-Dutton unsigned int ngain, ogain; 927184c1e2cSJames Courtier-Dutton u32 gpio; 928184c1e2cSJames Courtier-Dutton int change = 0; 929184c1e2cSJames Courtier-Dutton unsigned long flags; 930184c1e2cSJames Courtier-Dutton u32 source; 931184c1e2cSJames Courtier-Dutton /* If the capture source has changed, 932184c1e2cSJames Courtier-Dutton * update the capture volume from the cached value 933184c1e2cSJames Courtier-Dutton * for the particular source. 934184c1e2cSJames Courtier-Dutton */ 93574415a36SJames Courtier-Dutton source_id = ucontrol->value.enumerated.item[0]; 93674415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 2; */ 93774415a36SJames Courtier-Dutton /* emu->i2c_capture_volume */ 93874415a36SJames Courtier-Dutton if (source_id >= 2) 93974415a36SJames Courtier-Dutton return -EINVAL; 940184c1e2cSJames Courtier-Dutton change = (emu->i2c_capture_source != source_id); 941184c1e2cSJames Courtier-Dutton if (change) { 942184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 943184c1e2cSJames Courtier-Dutton spin_lock_irqsave(&emu->emu_lock, flags); 944184c1e2cSJames Courtier-Dutton gpio = inl(emu->port + A_IOCFG); 945184c1e2cSJames Courtier-Dutton if (source_id==0) 946184c1e2cSJames Courtier-Dutton outl(gpio | 0x4, emu->port + A_IOCFG); 947184c1e2cSJames Courtier-Dutton else 948184c1e2cSJames Courtier-Dutton outl(gpio & ~0x4, emu->port + A_IOCFG); 949184c1e2cSJames Courtier-Dutton spin_unlock_irqrestore(&emu->emu_lock, flags); 950184c1e2cSJames Courtier-Dutton 951184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ 952184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ 953184c1e2cSJames Courtier-Dutton if (ngain != ogain) 954184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); 955184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ 956184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ 957184c1e2cSJames Courtier-Dutton if (ngain != ogain) 958184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 959184c1e2cSJames Courtier-Dutton 960184c1e2cSJames Courtier-Dutton source = 1 << (source_id + 2); 961184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ 962184c1e2cSJames Courtier-Dutton emu->i2c_capture_source = source_id; 963184c1e2cSJames Courtier-Dutton } 964184c1e2cSJames Courtier-Dutton return change; 965184c1e2cSJames Courtier-Dutton } 966184c1e2cSJames Courtier-Dutton 967f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source = 968184c1e2cSJames Courtier-Dutton { 969184c1e2cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 970184c1e2cSJames Courtier-Dutton .name = "Capture Source", 971184c1e2cSJames Courtier-Dutton .info = snd_audigy_i2c_capture_source_info, 972184c1e2cSJames Courtier-Dutton .get = snd_audigy_i2c_capture_source_get, 973184c1e2cSJames Courtier-Dutton .put = snd_audigy_i2c_capture_source_put 974184c1e2cSJames Courtier-Dutton }; 975184c1e2cSJames Courtier-Dutton 976184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, 977184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 978184c1e2cSJames Courtier-Dutton { 979184c1e2cSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 980184c1e2cSJames Courtier-Dutton uinfo->count = 2; 981184c1e2cSJames Courtier-Dutton uinfo->value.integer.min = 0; 982184c1e2cSJames Courtier-Dutton uinfo->value.integer.max = 255; 983184c1e2cSJames Courtier-Dutton return 0; 984184c1e2cSJames Courtier-Dutton } 985184c1e2cSJames Courtier-Dutton 986184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, 987184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 988184c1e2cSJames Courtier-Dutton { 989184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 99074415a36SJames Courtier-Dutton unsigned int source_id; 991184c1e2cSJames Courtier-Dutton 992184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 99374415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 99474415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 99574415a36SJames Courtier-Dutton if (source_id >= 2) 99674415a36SJames Courtier-Dutton return -EINVAL; 997184c1e2cSJames Courtier-Dutton 998184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; 999184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; 1000184c1e2cSJames Courtier-Dutton return 0; 1001184c1e2cSJames Courtier-Dutton } 1002184c1e2cSJames Courtier-Dutton 1003184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, 1004184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 1005184c1e2cSJames Courtier-Dutton { 1006184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1007184c1e2cSJames Courtier-Dutton unsigned int ogain; 1008184c1e2cSJames Courtier-Dutton unsigned int ngain; 100974415a36SJames Courtier-Dutton unsigned int source_id; 1010184c1e2cSJames Courtier-Dutton int change = 0; 1011184c1e2cSJames Courtier-Dutton 1012184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 101374415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 101474415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 101574415a36SJames Courtier-Dutton if (source_id >= 2) 101674415a36SJames Courtier-Dutton return -EINVAL; 1017184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ 1018184c1e2cSJames Courtier-Dutton ngain = ucontrol->value.integer.value[0]; 1019184c1e2cSJames Courtier-Dutton if (ngain > 0xff) 1020184c1e2cSJames Courtier-Dutton return 0; 1021184c1e2cSJames Courtier-Dutton if (ogain != ngain) { 1022184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 1023184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); 102474415a36SJames Courtier-Dutton emu->i2c_capture_volume[source_id][0] = ngain; 1025184c1e2cSJames Courtier-Dutton change = 1; 1026184c1e2cSJames Courtier-Dutton } 1027184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ 1028184c1e2cSJames Courtier-Dutton ngain = ucontrol->value.integer.value[1]; 1029184c1e2cSJames Courtier-Dutton if (ngain > 0xff) 1030184c1e2cSJames Courtier-Dutton return 0; 1031184c1e2cSJames Courtier-Dutton if (ogain != ngain) { 1032184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 1033184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 103474415a36SJames Courtier-Dutton emu->i2c_capture_volume[source_id][1] = ngain; 1035184c1e2cSJames Courtier-Dutton change = 1; 1036184c1e2cSJames Courtier-Dutton } 1037184c1e2cSJames Courtier-Dutton 1038184c1e2cSJames Courtier-Dutton return change; 1039184c1e2cSJames Courtier-Dutton } 1040184c1e2cSJames Courtier-Dutton 1041184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \ 1042184c1e2cSJames Courtier-Dutton { \ 1043184c1e2cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 1044184c1e2cSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 1045184c1e2cSJames Courtier-Dutton SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 1046184c1e2cSJames Courtier-Dutton .info = snd_audigy_i2c_volume_info, \ 1047184c1e2cSJames Courtier-Dutton .get = snd_audigy_i2c_volume_get, \ 1048184c1e2cSJames Courtier-Dutton .put = snd_audigy_i2c_volume_put, \ 1049184c1e2cSJames Courtier-Dutton .tlv = { .p = snd_audigy_db_scale2 }, \ 1050184c1e2cSJames Courtier-Dutton .private_value = chid \ 1051184c1e2cSJames Courtier-Dutton } 1052184c1e2cSJames Courtier-Dutton 1053184c1e2cSJames Courtier-Dutton 1054b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = { 1055184c1e2cSJames Courtier-Dutton I2C_VOLUME("Mic Capture Volume", 0), 1056184c1e2cSJames Courtier-Dutton I2C_VOLUME("Line Capture Volume", 0) 1057184c1e2cSJames Courtier-Dutton }; 1058184c1e2cSJames Courtier-Dutton 10590af68e5eSTakashi Iwai #if 0 1060eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 10611da177e4SLinus Torvalds { 10621541c66dSTakashi Iwai static const char * const texts[] = {"44100", "48000", "96000"}; 10631da177e4SLinus Torvalds 10641541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 3, texts); 10651da177e4SLinus Torvalds } 10661da177e4SLinus Torvalds 1067eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, 1068eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10691da177e4SLinus Torvalds { 1070eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10711da177e4SLinus Torvalds unsigned int tmp; 10721da177e4SLinus Torvalds unsigned long flags; 10731da177e4SLinus Torvalds 10741da177e4SLinus Torvalds 10751da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 10761da177e4SLinus Torvalds tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 10771da177e4SLinus Torvalds switch (tmp & A_SPDIF_RATE_MASK) { 10781da177e4SLinus Torvalds case A_SPDIF_44100: 10791da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 10801da177e4SLinus Torvalds break; 10811da177e4SLinus Torvalds case A_SPDIF_48000: 10821da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 10831da177e4SLinus Torvalds break; 10841da177e4SLinus Torvalds case A_SPDIF_96000: 10851da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 10861da177e4SLinus Torvalds break; 10871da177e4SLinus Torvalds default: 10881da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 10891da177e4SLinus Torvalds } 10901da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 10911da177e4SLinus Torvalds return 0; 10921da177e4SLinus Torvalds } 10931da177e4SLinus Torvalds 1094eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, 1095eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10961da177e4SLinus Torvalds { 1097eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10981da177e4SLinus Torvalds int change; 10991da177e4SLinus Torvalds unsigned int reg, val, tmp; 11001da177e4SLinus Torvalds unsigned long flags; 11011da177e4SLinus Torvalds 11021da177e4SLinus Torvalds switch(ucontrol->value.enumerated.item[0]) { 11031da177e4SLinus Torvalds case 0: 11041da177e4SLinus Torvalds val = A_SPDIF_44100; 11051da177e4SLinus Torvalds break; 11061da177e4SLinus Torvalds case 1: 11071da177e4SLinus Torvalds val = A_SPDIF_48000; 11081da177e4SLinus Torvalds break; 11091da177e4SLinus Torvalds case 2: 11101da177e4SLinus Torvalds val = A_SPDIF_96000; 11111da177e4SLinus Torvalds break; 11121da177e4SLinus Torvalds default: 11131da177e4SLinus Torvalds val = A_SPDIF_48000; 11141da177e4SLinus Torvalds break; 11151da177e4SLinus Torvalds } 11161da177e4SLinus Torvalds 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11191da177e4SLinus Torvalds reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 11201da177e4SLinus Torvalds tmp = reg & ~A_SPDIF_RATE_MASK; 11211da177e4SLinus Torvalds tmp |= val; 112212bda107STakashi Iwai change = (tmp != reg); 112312bda107STakashi Iwai if (change) 11241da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); 11251da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11261da177e4SLinus Torvalds return change; 11271da177e4SLinus Torvalds } 11281da177e4SLinus Torvalds 1129b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate = 11301da177e4SLinus Torvalds { 11311da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 11321da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 11331da177e4SLinus Torvalds .name = "Audigy SPDIF Output Sample Rate", 11341da177e4SLinus Torvalds .count = 1, 11351da177e4SLinus Torvalds .info = snd_audigy_spdif_output_rate_info, 11361da177e4SLinus Torvalds .get = snd_audigy_spdif_output_rate_get, 11371da177e4SLinus Torvalds .put = snd_audigy_spdif_output_rate_put 11381da177e4SLinus Torvalds }; 11390af68e5eSTakashi Iwai #endif 11401da177e4SLinus Torvalds 1141eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, 1142eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11431da177e4SLinus Torvalds { 1144eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11451da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 11461da177e4SLinus Torvalds int change; 11471da177e4SLinus Torvalds unsigned int val; 11481da177e4SLinus Torvalds unsigned long flags; 11491da177e4SLinus Torvalds 115074415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 115174415a36SJames Courtier-Dutton if (idx >= 3) 115274415a36SJames Courtier-Dutton return -EINVAL; 11531da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 11541da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 11551da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 11561da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 11571da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11581da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 11591da177e4SLinus Torvalds if (change) { 11601da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); 11611da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 11621da177e4SLinus Torvalds } 11631da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11641da177e4SLinus Torvalds return change; 11651da177e4SLinus Torvalds } 11661da177e4SLinus Torvalds 1167f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = 11681da177e4SLinus Torvalds { 11691da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 11705549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 11711da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 11727583cb51STakashi Iwai .count = 3, 11731da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 11741da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get_mask 11751da177e4SLinus Torvalds }; 11761da177e4SLinus Torvalds 1177f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control = 11781da177e4SLinus Torvalds { 11795549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 11801da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 11817583cb51STakashi Iwai .count = 3, 11821da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 11831da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get, 11841da177e4SLinus Torvalds .put = snd_emu10k1_spdif_put 11851da177e4SLinus Torvalds }; 11861da177e4SLinus Torvalds 11871da177e4SLinus Torvalds 1188eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route) 11891da177e4SLinus Torvalds { 11901da177e4SLinus Torvalds if (emu->audigy) { 11911da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT1, voice, 11921da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt1(route)); 11931da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 11941da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt2(route)); 11951da177e4SLinus Torvalds } else { 11961da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXRT, voice, 11971da177e4SLinus Torvalds snd_emu10k1_compose_send_routing(route)); 11981da177e4SLinus Torvalds } 11991da177e4SLinus Torvalds } 12001da177e4SLinus Torvalds 1201eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume) 12021da177e4SLinus Torvalds { 12031da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); 12041da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); 12051da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); 12061da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); 12071da177e4SLinus Torvalds if (emu->audigy) { 12081da177e4SLinus Torvalds unsigned int val = ((unsigned int)volume[4] << 24) | 12091da177e4SLinus Torvalds ((unsigned int)volume[5] << 16) | 12101da177e4SLinus Torvalds ((unsigned int)volume[6] << 8) | 12111da177e4SLinus Torvalds (unsigned int)volume[7]; 12121da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val); 12131da177e4SLinus Torvalds } 12141da177e4SLinus Torvalds } 12151da177e4SLinus Torvalds 12161da177e4SLinus Torvalds /* PCM stream controls */ 12171da177e4SLinus Torvalds 1218eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 12191da177e4SLinus Torvalds { 1220eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 12211da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 12221da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 12231da177e4SLinus Torvalds uinfo->value.integer.min = 0; 12241da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 12251da177e4SLinus Torvalds return 0; 12261da177e4SLinus Torvalds } 12271da177e4SLinus Torvalds 1228eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, 1229eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12301da177e4SLinus Torvalds { 12311da177e4SLinus Torvalds unsigned long flags; 1232eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1233eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1234eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12351da177e4SLinus Torvalds int voice, idx; 12361da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12371da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 12381da177e4SLinus Torvalds 12391da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12401da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 12411da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 12421da177e4SLinus Torvalds ucontrol->value.integer.value[(voice * num_efx) + idx] = 12431da177e4SLinus Torvalds mix->send_routing[voice][idx] & mask; 12441da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 12451da177e4SLinus Torvalds return 0; 12461da177e4SLinus Torvalds } 12471da177e4SLinus Torvalds 1248eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, 1249eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12501da177e4SLinus Torvalds { 12511da177e4SLinus Torvalds unsigned long flags; 1252eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1253eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1254eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12551da177e4SLinus Torvalds int change = 0, voice, idx, val; 12561da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12571da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 12581da177e4SLinus Torvalds 12591da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12601da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 12611da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 12621da177e4SLinus Torvalds val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; 12631da177e4SLinus Torvalds if (mix->send_routing[voice][idx] != val) { 12641da177e4SLinus Torvalds mix->send_routing[voice][idx] = val; 12651da177e4SLinus Torvalds change = 1; 12661da177e4SLinus Torvalds } 12671da177e4SLinus Torvalds } 12681da177e4SLinus Torvalds if (change && mix->epcm) { 12691da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 12701da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 12711da177e4SLinus Torvalds &mix->send_routing[1][0]); 12721da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, 12731da177e4SLinus Torvalds &mix->send_routing[2][0]); 12741da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 12751da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 12761da177e4SLinus Torvalds &mix->send_routing[0][0]); 12771da177e4SLinus Torvalds } 12781da177e4SLinus Torvalds } 12791da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 12801da177e4SLinus Torvalds return change; 12811da177e4SLinus Torvalds } 12821da177e4SLinus Torvalds 1283f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control = 12841da177e4SLinus Torvalds { 12851da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 128667ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 12871da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Routing", 12881da177e4SLinus Torvalds .count = 32, 12891da177e4SLinus Torvalds .info = snd_emu10k1_send_routing_info, 12901da177e4SLinus Torvalds .get = snd_emu10k1_send_routing_get, 12911da177e4SLinus Torvalds .put = snd_emu10k1_send_routing_put 12921da177e4SLinus Torvalds }; 12931da177e4SLinus Torvalds 1294eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 12951da177e4SLinus Torvalds { 1296eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 12971da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 12981da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 12991da177e4SLinus Torvalds uinfo->value.integer.min = 0; 13001da177e4SLinus Torvalds uinfo->value.integer.max = 255; 13011da177e4SLinus Torvalds return 0; 13021da177e4SLinus Torvalds } 13031da177e4SLinus Torvalds 1304eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, 1305eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13061da177e4SLinus Torvalds { 13071da177e4SLinus Torvalds unsigned long flags; 1308eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1309eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1310eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13111da177e4SLinus Torvalds int idx; 13121da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13131da177e4SLinus Torvalds 13141da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13151da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) 13161da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; 13171da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13181da177e4SLinus Torvalds return 0; 13191da177e4SLinus Torvalds } 13201da177e4SLinus Torvalds 1321eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, 1322eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13231da177e4SLinus Torvalds { 13241da177e4SLinus Torvalds unsigned long flags; 1325eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1326eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1327eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13281da177e4SLinus Torvalds int change = 0, idx, val; 13291da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13301da177e4SLinus Torvalds 13311da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13321da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) { 13331da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 13341da177e4SLinus Torvalds if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { 13351da177e4SLinus Torvalds mix->send_volume[idx/num_efx][idx%num_efx] = val; 13361da177e4SLinus Torvalds change = 1; 13371da177e4SLinus Torvalds } 13381da177e4SLinus Torvalds } 13391da177e4SLinus Torvalds if (change && mix->epcm) { 13401da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 13411da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 13421da177e4SLinus Torvalds &mix->send_volume[1][0]); 13431da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, 13441da177e4SLinus Torvalds &mix->send_volume[2][0]); 13451da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 13461da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 13471da177e4SLinus Torvalds &mix->send_volume[0][0]); 13481da177e4SLinus Torvalds } 13491da177e4SLinus Torvalds } 13501da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13511da177e4SLinus Torvalds return change; 13521da177e4SLinus Torvalds } 13531da177e4SLinus Torvalds 1354f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control = 13551da177e4SLinus Torvalds { 13561da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 135767ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 13581da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Volume", 13591da177e4SLinus Torvalds .count = 32, 13601da177e4SLinus Torvalds .info = snd_emu10k1_send_volume_info, 13611da177e4SLinus Torvalds .get = snd_emu10k1_send_volume_get, 13621da177e4SLinus Torvalds .put = snd_emu10k1_send_volume_put 13631da177e4SLinus Torvalds }; 13641da177e4SLinus Torvalds 1365eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13661da177e4SLinus Torvalds { 13671da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13681da177e4SLinus Torvalds uinfo->count = 3; 13691da177e4SLinus Torvalds uinfo->value.integer.min = 0; 13701da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 13711da177e4SLinus Torvalds return 0; 13721da177e4SLinus Torvalds } 13731da177e4SLinus Torvalds 1374eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, 1375eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13761da177e4SLinus Torvalds { 1377eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1378eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1379eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13801da177e4SLinus Torvalds unsigned long flags; 13811da177e4SLinus Torvalds int idx; 13821da177e4SLinus Torvalds 13831da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13841da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) 13851da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->attn[idx]; 13861da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13871da177e4SLinus Torvalds return 0; 13881da177e4SLinus Torvalds } 13891da177e4SLinus Torvalds 1390eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, 1391eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13921da177e4SLinus Torvalds { 13931da177e4SLinus Torvalds unsigned long flags; 1394eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1395eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1396eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13971da177e4SLinus Torvalds int change = 0, idx, val; 13981da177e4SLinus Torvalds 13991da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 14001da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) { 14011da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 0xffff; 14021da177e4SLinus Torvalds if (mix->attn[idx] != val) { 14031da177e4SLinus Torvalds mix->attn[idx] = val; 14041da177e4SLinus Torvalds change = 1; 14051da177e4SLinus Torvalds } 14061da177e4SLinus Torvalds } 14071da177e4SLinus Torvalds if (change && mix->epcm) { 14081da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 14091da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); 14101da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); 14111da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 14121da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); 14131da177e4SLinus Torvalds } 14141da177e4SLinus Torvalds } 14151da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 14161da177e4SLinus Torvalds return change; 14171da177e4SLinus Torvalds } 14181da177e4SLinus Torvalds 1419f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control = 14201da177e4SLinus Torvalds { 14211da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 142267ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14231da177e4SLinus Torvalds .name = "EMU10K1 PCM Volume", 14241da177e4SLinus Torvalds .count = 32, 14251da177e4SLinus Torvalds .info = snd_emu10k1_attn_info, 14261da177e4SLinus Torvalds .get = snd_emu10k1_attn_get, 14271da177e4SLinus Torvalds .put = snd_emu10k1_attn_put 14281da177e4SLinus Torvalds }; 14291da177e4SLinus Torvalds 14301da177e4SLinus Torvalds /* Mutichannel PCM stream controls */ 14311da177e4SLinus Torvalds 1432eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 14331da177e4SLinus Torvalds { 1434eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14351da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 14361da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 14371da177e4SLinus Torvalds uinfo->value.integer.min = 0; 14381da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 14391da177e4SLinus Torvalds return 0; 14401da177e4SLinus Torvalds } 14411da177e4SLinus Torvalds 1442eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, 1443eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14441da177e4SLinus Torvalds { 14451da177e4SLinus Torvalds unsigned long flags; 1446eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1447eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1448eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14491da177e4SLinus Torvalds int idx; 14501da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 14511da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 14521da177e4SLinus Torvalds 14531da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 14541da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 14551da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = 14561da177e4SLinus Torvalds mix->send_routing[0][idx] & mask; 14571da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 14581da177e4SLinus Torvalds return 0; 14591da177e4SLinus Torvalds } 14601da177e4SLinus Torvalds 1461eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, 1462eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14631da177e4SLinus Torvalds { 14641da177e4SLinus Torvalds unsigned long flags; 1465eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14661da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1467eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 14681da177e4SLinus Torvalds int change = 0, idx, val; 14691da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 14701da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 14711da177e4SLinus Torvalds 14721da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 14731da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 14741da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & mask; 14751da177e4SLinus Torvalds if (mix->send_routing[0][idx] != val) { 14761da177e4SLinus Torvalds mix->send_routing[0][idx] = val; 14771da177e4SLinus Torvalds change = 1; 14781da177e4SLinus Torvalds } 14791da177e4SLinus Torvalds } 14801da177e4SLinus Torvalds 14811da177e4SLinus Torvalds if (change && mix->epcm) { 14821da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 14831da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, 14841da177e4SLinus Torvalds &mix->send_routing[0][0]); 14851da177e4SLinus Torvalds } 14861da177e4SLinus Torvalds } 14871da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 14881da177e4SLinus Torvalds return change; 14891da177e4SLinus Torvalds } 14901da177e4SLinus Torvalds 1491f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = 14921da177e4SLinus Torvalds { 14931da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 14941da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14951da177e4SLinus Torvalds .name = "Multichannel PCM Send Routing", 14961da177e4SLinus Torvalds .count = 16, 14971da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_routing_info, 14981da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_routing_get, 14991da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_routing_put 15001da177e4SLinus Torvalds }; 15011da177e4SLinus Torvalds 1502eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 15031da177e4SLinus Torvalds { 1504eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15051da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 15061da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 15071da177e4SLinus Torvalds uinfo->value.integer.min = 0; 15081da177e4SLinus Torvalds uinfo->value.integer.max = 255; 15091da177e4SLinus Torvalds return 0; 15101da177e4SLinus Torvalds } 15111da177e4SLinus Torvalds 1512eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, 1513eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15141da177e4SLinus Torvalds { 15151da177e4SLinus Torvalds unsigned long flags; 1516eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1517eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1518eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 15191da177e4SLinus Torvalds int idx; 15201da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 15211da177e4SLinus Torvalds 15221da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 15231da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 15241da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; 15251da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 15261da177e4SLinus Torvalds return 0; 15271da177e4SLinus Torvalds } 15281da177e4SLinus Torvalds 1529eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, 1530eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15311da177e4SLinus Torvalds { 15321da177e4SLinus Torvalds unsigned long flags; 1533eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15341da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1535eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 15361da177e4SLinus Torvalds int change = 0, idx, val; 15371da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 15381da177e4SLinus Torvalds 15391da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 15401da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 15411da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 15421da177e4SLinus Torvalds if (mix->send_volume[0][idx] != val) { 15431da177e4SLinus Torvalds mix->send_volume[0][idx] = val; 15441da177e4SLinus Torvalds change = 1; 15451da177e4SLinus Torvalds } 15461da177e4SLinus Torvalds } 15471da177e4SLinus Torvalds if (change && mix->epcm) { 15481da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 15491da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, 15501da177e4SLinus Torvalds &mix->send_volume[0][0]); 15511da177e4SLinus Torvalds } 15521da177e4SLinus Torvalds } 15531da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 15541da177e4SLinus Torvalds return change; 15551da177e4SLinus Torvalds } 15561da177e4SLinus Torvalds 15571da177e4SLinus Torvalds 1558f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = 15591da177e4SLinus Torvalds { 15601da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 15611da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 15621da177e4SLinus Torvalds .name = "Multichannel PCM Send Volume", 15631da177e4SLinus Torvalds .count = 16, 15641da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_volume_info, 15651da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_volume_get, 15661da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_volume_put 15671da177e4SLinus Torvalds }; 15681da177e4SLinus Torvalds 1569eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 15701da177e4SLinus Torvalds { 15711da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 15721da177e4SLinus Torvalds uinfo->count = 1; 15731da177e4SLinus Torvalds uinfo->value.integer.min = 0; 15741da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 15751da177e4SLinus Torvalds return 0; 15761da177e4SLinus Torvalds } 15771da177e4SLinus Torvalds 1578eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, 1579eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15801da177e4SLinus Torvalds { 1581eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1582eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1583eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 15841da177e4SLinus Torvalds unsigned long flags; 15851da177e4SLinus Torvalds 15861da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 15871da177e4SLinus Torvalds ucontrol->value.integer.value[0] = mix->attn[0]; 15881da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 15891da177e4SLinus Torvalds return 0; 15901da177e4SLinus Torvalds } 15911da177e4SLinus Torvalds 1592eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, 1593eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15941da177e4SLinus Torvalds { 15951da177e4SLinus Torvalds unsigned long flags; 1596eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15971da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1598eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 15991da177e4SLinus Torvalds int change = 0, val; 16001da177e4SLinus Torvalds 16011da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 16021da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] & 0xffff; 16031da177e4SLinus Torvalds if (mix->attn[0] != val) { 16041da177e4SLinus Torvalds mix->attn[0] = val; 16051da177e4SLinus Torvalds change = 1; 16061da177e4SLinus Torvalds } 16071da177e4SLinus Torvalds if (change && mix->epcm) { 16081da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 16091da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); 16101da177e4SLinus Torvalds } 16111da177e4SLinus Torvalds } 16121da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 16131da177e4SLinus Torvalds return change; 16141da177e4SLinus Torvalds } 16151da177e4SLinus Torvalds 1616f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control = 16171da177e4SLinus Torvalds { 16181da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 16191da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 16201da177e4SLinus Torvalds .name = "Multichannel PCM Volume", 16211da177e4SLinus Torvalds .count = 16, 16221da177e4SLinus Torvalds .info = snd_emu10k1_efx_attn_info, 16231da177e4SLinus Torvalds .get = snd_emu10k1_efx_attn_get, 16241da177e4SLinus Torvalds .put = snd_emu10k1_efx_attn_put 16251da177e4SLinus Torvalds }; 16261da177e4SLinus Torvalds 1627a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info snd_ctl_boolean_mono_info 16281da177e4SLinus Torvalds 1629eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, 1630eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16311da177e4SLinus Torvalds { 1632eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 16331da177e4SLinus Torvalds 16341da177e4SLinus Torvalds if (emu->audigy) 16351da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; 16361da177e4SLinus Torvalds else 16371da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; 1638d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1639d2cd74b1STakashi Iwai ucontrol->value.integer.value[0] = 1640d2cd74b1STakashi Iwai !ucontrol->value.integer.value[0]; 1641d2cd74b1STakashi Iwai 16421da177e4SLinus Torvalds return 0; 16431da177e4SLinus Torvalds } 16441da177e4SLinus Torvalds 1645eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, 1646eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16471da177e4SLinus Torvalds { 16481da177e4SLinus Torvalds unsigned long flags; 1649eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1650d2cd74b1STakashi Iwai unsigned int reg, val, sw; 16511da177e4SLinus Torvalds int change = 0; 16521da177e4SLinus Torvalds 1653d2cd74b1STakashi Iwai sw = ucontrol->value.integer.value[0]; 1654d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1655d2cd74b1STakashi Iwai sw = !sw; 16561da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 1657184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 1658184c1e2cSJames Courtier-Dutton /* Do nothing for Audigy 2 ZS Notebook */ 1659184c1e2cSJames Courtier-Dutton } else if (emu->audigy) { 16601da177e4SLinus Torvalds reg = inl(emu->port + A_IOCFG); 1661d2cd74b1STakashi Iwai val = sw ? A_IOCFG_GPOUT0 : 0; 16621da177e4SLinus Torvalds change = (reg & A_IOCFG_GPOUT0) != val; 16631da177e4SLinus Torvalds if (change) { 16641da177e4SLinus Torvalds reg &= ~A_IOCFG_GPOUT0; 16651da177e4SLinus Torvalds reg |= val; 16661da177e4SLinus Torvalds outl(reg | val, emu->port + A_IOCFG); 16671da177e4SLinus Torvalds } 16681da177e4SLinus Torvalds } 16691da177e4SLinus Torvalds reg = inl(emu->port + HCFG); 1670d2cd74b1STakashi Iwai val = sw ? HCFG_GPOUT0 : 0; 16711da177e4SLinus Torvalds change |= (reg & HCFG_GPOUT0) != val; 16721da177e4SLinus Torvalds if (change) { 16731da177e4SLinus Torvalds reg &= ~HCFG_GPOUT0; 16741da177e4SLinus Torvalds reg |= val; 16751da177e4SLinus Torvalds outl(reg | val, emu->port + HCFG); 16761da177e4SLinus Torvalds } 16771da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 16781da177e4SLinus Torvalds return change; 16791da177e4SLinus Torvalds } 16801da177e4SLinus Torvalds 1681f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif = 16821da177e4SLinus Torvalds { 16831da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 16841da177e4SLinus Torvalds .name = "SB Live Analog/Digital Output Jack", 16851da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 16861da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 16871da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 16881da177e4SLinus Torvalds }; 16891da177e4SLinus Torvalds 1690f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif = 16911da177e4SLinus Torvalds { 16921da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 16931da177e4SLinus Torvalds .name = "Audigy Analog/Digital Output Jack", 16941da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 16951da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 16961da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 16971da177e4SLinus Torvalds }; 16981da177e4SLinus Torvalds 169916950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */ 170016950e09STakashi Iwai 170116950e09STakashi Iwai #define snd_audigy_capture_boost_info snd_ctl_boolean_mono_info 170216950e09STakashi Iwai 170316950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol, 170416950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 170516950e09STakashi Iwai { 170616950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 170716950e09STakashi Iwai unsigned int val; 170816950e09STakashi Iwai 170916950e09STakashi Iwai /* FIXME: better to use a cached version */ 171016950e09STakashi Iwai val = snd_ac97_read(emu->ac97, AC97_REC_GAIN); 171116950e09STakashi Iwai ucontrol->value.integer.value[0] = !!val; 171216950e09STakashi Iwai return 0; 171316950e09STakashi Iwai } 171416950e09STakashi Iwai 171516950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, 171616950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 171716950e09STakashi Iwai { 171816950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 171916950e09STakashi Iwai unsigned int val; 172016950e09STakashi Iwai 172116950e09STakashi Iwai if (ucontrol->value.integer.value[0]) 172216950e09STakashi Iwai val = 0x0f0f; 172316950e09STakashi Iwai else 172416950e09STakashi Iwai val = 0; 172516950e09STakashi Iwai return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); 172616950e09STakashi Iwai } 172716950e09STakashi Iwai 1728f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost = 172916950e09STakashi Iwai { 173016950e09STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 17312a52feb1SMaciej S. Szmigiero .name = "Mic Extra Boost", 173216950e09STakashi Iwai .info = snd_audigy_capture_boost_info, 173316950e09STakashi Iwai .get = snd_audigy_capture_boost_get, 173416950e09STakashi Iwai .put = snd_audigy_capture_boost_put 173516950e09STakashi Iwai }; 173616950e09STakashi Iwai 173716950e09STakashi Iwai 17381da177e4SLinus Torvalds /* 17391da177e4SLinus Torvalds */ 1740eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) 17411da177e4SLinus Torvalds { 1742eb4698f3STakashi Iwai struct snd_emu10k1 *emu = ac97->private_data; 17431da177e4SLinus Torvalds emu->ac97 = NULL; 17441da177e4SLinus Torvalds } 17451da177e4SLinus Torvalds 17461da177e4SLinus Torvalds /* 17471da177e4SLinus Torvalds */ 1748eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name) 17491da177e4SLinus Torvalds { 1750eb4698f3STakashi Iwai struct snd_ctl_elem_id id; 17511da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 17521da177e4SLinus Torvalds strcpy(id.name, name); 17531da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 17541da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 17551da177e4SLinus Torvalds } 17561da177e4SLinus Torvalds 1757eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) 17581da177e4SLinus Torvalds { 1759eb4698f3STakashi Iwai struct snd_ctl_elem_id sid; 17601da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 17611da177e4SLinus Torvalds strcpy(sid.name, name); 17621da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 17631da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 17641da177e4SLinus Torvalds } 17651da177e4SLinus Torvalds 1766eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst) 17671da177e4SLinus Torvalds { 1768eb4698f3STakashi Iwai struct snd_kcontrol *kctl = ctl_find(card, src); 17691da177e4SLinus Torvalds if (kctl) { 1770*36476b81SMaciej S. Szmigiero snd_ctl_rename(card, kctl, dst); 17711da177e4SLinus Torvalds return 0; 17721da177e4SLinus Torvalds } 17731da177e4SLinus Torvalds return -ENOENT; 17741da177e4SLinus Torvalds } 17751da177e4SLinus Torvalds 1776e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu, 177767ed4161SClemens Ladisch int pcm_device, int multi_device) 17781da177e4SLinus Torvalds { 17791da177e4SLinus Torvalds int err, pcm; 1780eb4698f3STakashi Iwai struct snd_kcontrol *kctl; 1781eb4698f3STakashi Iwai struct snd_card *card = emu->card; 17826fddce26STakashi Iwai const char * const *c; 17836fddce26STakashi Iwai static const char * const emu10k1_remove_ctls[] = { 17841da177e4SLinus Torvalds /* no AC97 mono, surround, center/lfe */ 17851da177e4SLinus Torvalds "Master Mono Playback Switch", 17861da177e4SLinus Torvalds "Master Mono Playback Volume", 17871da177e4SLinus Torvalds "PCM Out Path & Mute", 17881da177e4SLinus Torvalds "Mono Output Select", 17891da177e4SLinus Torvalds "Surround Playback Switch", 17901da177e4SLinus Torvalds "Surround Playback Volume", 17911da177e4SLinus Torvalds "Center Playback Switch", 17921da177e4SLinus Torvalds "Center Playback Volume", 17931da177e4SLinus Torvalds "LFE Playback Switch", 17941da177e4SLinus Torvalds "LFE Playback Volume", 17951da177e4SLinus Torvalds NULL 17961da177e4SLinus Torvalds }; 17976fddce26STakashi Iwai static const char * const emu10k1_rename_ctls[] = { 17981da177e4SLinus Torvalds "Surround Digital Playback Volume", "Surround Playback Volume", 17991da177e4SLinus Torvalds "Center Digital Playback Volume", "Center Playback Volume", 18001da177e4SLinus Torvalds "LFE Digital Playback Volume", "LFE Playback Volume", 18011da177e4SLinus Torvalds NULL 18021da177e4SLinus Torvalds }; 18036fddce26STakashi Iwai static const char * const audigy_remove_ctls[] = { 18041da177e4SLinus Torvalds /* Master/PCM controls on ac97 of Audigy has no effect */ 180521fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 180621fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 18071da177e4SLinus Torvalds "PCM Playback Switch", 18081da177e4SLinus Torvalds "PCM Playback Volume", 18091da177e4SLinus Torvalds "Master Playback Switch", 18101da177e4SLinus Torvalds "Master Playback Volume", 18111da177e4SLinus Torvalds "PCM Out Path & Mute", 18121da177e4SLinus Torvalds "Mono Output Select", 18131da177e4SLinus Torvalds /* remove unused AC97 capture controls */ 18141da177e4SLinus Torvalds "Capture Source", 18151da177e4SLinus Torvalds "Capture Switch", 18161da177e4SLinus Torvalds "Capture Volume", 18171da177e4SLinus Torvalds "Mic Select", 1818274b2000SMaciej S. Szmigiero "Headphone Playback Switch", 1819274b2000SMaciej S. Szmigiero "Headphone Playback Volume", 1820274b2000SMaciej S. Szmigiero "3D Control - Center", 1821274b2000SMaciej S. Szmigiero "3D Control - Depth", 1822274b2000SMaciej S. Szmigiero "3D Control - Switch", 18231da177e4SLinus Torvalds "Video Playback Switch", 18241da177e4SLinus Torvalds "Video Playback Volume", 18251da177e4SLinus Torvalds "Mic Playback Switch", 18261da177e4SLinus Torvalds "Mic Playback Volume", 1827274b2000SMaciej S. Szmigiero "External Amplifier", 18281da177e4SLinus Torvalds NULL 18291da177e4SLinus Torvalds }; 18306fddce26STakashi Iwai static const char * const audigy_rename_ctls[] = { 18311da177e4SLinus Torvalds /* use conventional names */ 18321da177e4SLinus Torvalds "Wave Playback Volume", "PCM Playback Volume", 18331da177e4SLinus Torvalds /* "Wave Capture Volume", "PCM Capture Volume", */ 18341da177e4SLinus Torvalds "Wave Master Playback Volume", "Master Playback Volume", 18351da177e4SLinus Torvalds "AMic Playback Volume", "Mic Playback Volume", 183652051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 183752051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 18381da177e4SLinus Torvalds NULL 18391da177e4SLinus Torvalds }; 18406fddce26STakashi Iwai static const char * const audigy_rename_ctls_i2c_adc[] = { 1841184c1e2cSJames Courtier-Dutton //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", 1842184c1e2cSJames Courtier-Dutton "Line Capture Volume", "Analog Mix Capture Volume", 1843184c1e2cSJames Courtier-Dutton "Wave Playback Volume", "OLD PCM Playback Volume", 1844184c1e2cSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 1845184c1e2cSJames Courtier-Dutton "AMic Playback Volume", "Old Mic Playback Volume", 1846eb41dab6SJames Courtier-Dutton "CD Capture Volume", "IEC958 Optical Capture Volume", 1847184c1e2cSJames Courtier-Dutton NULL 1848184c1e2cSJames Courtier-Dutton }; 18496fddce26STakashi Iwai static const char * const audigy_remove_ctls_i2c_adc[] = { 1850184c1e2cSJames Courtier-Dutton /* On the Audigy2 ZS Notebook 1851184c1e2cSJames Courtier-Dutton * Capture via WM8775 */ 1852184c1e2cSJames Courtier-Dutton "Mic Capture Volume", 1853184c1e2cSJames Courtier-Dutton "Analog Mix Capture Volume", 1854184c1e2cSJames Courtier-Dutton "Aux Capture Volume", 1855eb41dab6SJames Courtier-Dutton "IEC958 Optical Capture Volume", 1856184c1e2cSJames Courtier-Dutton NULL 1857184c1e2cSJames Courtier-Dutton }; 18586fddce26STakashi Iwai static const char * const audigy_remove_ctls_1361t_adc[] = { 185921fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 186021fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 186121fdddeaSJames Courtier-Dutton "PCM Playback Switch", 186221fdddeaSJames Courtier-Dutton "PCM Playback Volume", 186321fdddeaSJames Courtier-Dutton "Capture Source", 186421fdddeaSJames Courtier-Dutton "Capture Switch", 186521fdddeaSJames Courtier-Dutton "Capture Volume", 186621fdddeaSJames Courtier-Dutton "Mic Capture Volume", 186721fdddeaSJames Courtier-Dutton "Headphone Playback Switch", 186821fdddeaSJames Courtier-Dutton "Headphone Playback Volume", 186921fdddeaSJames Courtier-Dutton "3D Control - Center", 187021fdddeaSJames Courtier-Dutton "3D Control - Depth", 187121fdddeaSJames Courtier-Dutton "3D Control - Switch", 187221fdddeaSJames Courtier-Dutton "Line2 Playback Volume", 187321fdddeaSJames Courtier-Dutton "Line2 Capture Volume", 187421fdddeaSJames Courtier-Dutton NULL 187521fdddeaSJames Courtier-Dutton }; 18766fddce26STakashi Iwai static const char * const audigy_rename_ctls_1361t_adc[] = { 187721fdddeaSJames Courtier-Dutton "Master Playback Switch", "Master Capture Switch", 187821fdddeaSJames Courtier-Dutton "Master Playback Volume", "Master Capture Volume", 187921fdddeaSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 1880d355c82aSJaroslav Kysela "Beep Playback Switch", "Beep Capture Switch", 1881d355c82aSJaroslav Kysela "Beep Playback Volume", "Beep Capture Volume", 188221fdddeaSJames Courtier-Dutton "Phone Playback Switch", "Phone Capture Switch", 188321fdddeaSJames Courtier-Dutton "Phone Playback Volume", "Phone Capture Volume", 188421fdddeaSJames Courtier-Dutton "Mic Playback Switch", "Mic Capture Switch", 188521fdddeaSJames Courtier-Dutton "Mic Playback Volume", "Mic Capture Volume", 188621fdddeaSJames Courtier-Dutton "Line Playback Switch", "Line Capture Switch", 188721fdddeaSJames Courtier-Dutton "Line Playback Volume", "Line Capture Volume", 188821fdddeaSJames Courtier-Dutton "CD Playback Switch", "CD Capture Switch", 188921fdddeaSJames Courtier-Dutton "CD Playback Volume", "CD Capture Volume", 189021fdddeaSJames Courtier-Dutton "Aux Playback Switch", "Aux Capture Switch", 189121fdddeaSJames Courtier-Dutton "Aux Playback Volume", "Aux Capture Volume", 189221fdddeaSJames Courtier-Dutton "Video Playback Switch", "Video Capture Switch", 189321fdddeaSJames Courtier-Dutton "Video Playback Volume", "Video Capture Volume", 189452051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 189552051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 189621fdddeaSJames Courtier-Dutton NULL 189721fdddeaSJames Courtier-Dutton }; 18981da177e4SLinus Torvalds 18992b637da5SLee Revell if (emu->card_capabilities->ac97_chip) { 1900eb4698f3STakashi Iwai struct snd_ac97_bus *pbus; 1901eb4698f3STakashi Iwai struct snd_ac97_template ac97; 190251055da5STakashi Iwai static const struct snd_ac97_bus_ops ops = { 19031da177e4SLinus Torvalds .write = snd_emu10k1_ac97_write, 19041da177e4SLinus Torvalds .read = snd_emu10k1_ac97_read, 19051da177e4SLinus Torvalds }; 19061da177e4SLinus Torvalds 190712bda107STakashi Iwai err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus); 190812bda107STakashi Iwai if (err < 0) 19091da177e4SLinus Torvalds return err; 19101da177e4SLinus Torvalds pbus->no_vra = 1; /* we don't need VRA */ 19111da177e4SLinus Torvalds 19121da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97)); 19131da177e4SLinus Torvalds ac97.private_data = emu; 19141da177e4SLinus Torvalds ac97.private_free = snd_emu10k1_mixer_free_ac97; 19151da177e4SLinus Torvalds ac97.scaps = AC97_SCAP_NO_SPDIF; 191612bda107STakashi Iwai err = snd_ac97_mixer(pbus, &ac97, &emu->ac97); 191712bda107STakashi Iwai if (err < 0) { 1918b1508693STakashi Iwai if (emu->card_capabilities->ac97_chip == 1) 19191da177e4SLinus Torvalds return err; 19206f002b02STakashi Iwai dev_info(emu->card->dev, 19216f002b02STakashi Iwai "AC97 is optional on this board\n"); 19226f002b02STakashi Iwai dev_info(emu->card->dev, 19236f002b02STakashi Iwai "Proceeding without ac97 mixers...\n"); 1924b1508693STakashi Iwai snd_device_free(emu->card, pbus); 1925b1508693STakashi Iwai goto no_ac97; /* FIXME: get rid of ugly gotos.. */ 1926b1508693STakashi Iwai } 19271da177e4SLinus Torvalds if (emu->audigy) { 19281da177e4SLinus Torvalds /* set master volume to 0 dB */ 19294d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); 19301da177e4SLinus Torvalds /* set capture source to mic */ 19314d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); 193252051942SMaciej S. Szmigiero /* set mono output (TAD) to mic */ 193352051942SMaciej S. Szmigiero snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE, 193452051942SMaciej S. Szmigiero 0x0200, 0x0200); 193521fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 193621fdddeaSJames Courtier-Dutton c = audigy_remove_ctls_1361t_adc; 193721fdddeaSJames Courtier-Dutton else 19381da177e4SLinus Torvalds c = audigy_remove_ctls; 19391da177e4SLinus Torvalds } else { 19401da177e4SLinus Torvalds /* 19411da177e4SLinus Torvalds * Credits for cards based on STAC9758: 19421da177e4SLinus Torvalds * James Courtier-Dutton <James@superbug.demon.co.uk> 19431da177e4SLinus Torvalds * Voluspa <voluspa@comhem.se> 19441da177e4SLinus Torvalds */ 19451da177e4SLinus Torvalds if (emu->ac97->id == AC97_ID_STAC9758) { 19461da177e4SLinus Torvalds emu->rear_ac97 = 1; 19471da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); 19482594d960SRolf Stefan Wilke snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); 1949b6a48404SRaymond Yau remove_ctl(card,"Front Playback Volume"); 1950b6a48404SRaymond Yau remove_ctl(card,"Front Playback Switch"); 19511da177e4SLinus Torvalds } 19521da177e4SLinus Torvalds /* remove unused AC97 controls */ 19534d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); 19544d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); 19551da177e4SLinus Torvalds c = emu10k1_remove_ctls; 19561da177e4SLinus Torvalds } 19571da177e4SLinus Torvalds for (; *c; c++) 19581da177e4SLinus Torvalds remove_ctl(card, *c); 1959184c1e2cSJames Courtier-Dutton } else if (emu->card_capabilities->i2c_adc) { 1960184c1e2cSJames Courtier-Dutton c = audigy_remove_ctls_i2c_adc; 1961184c1e2cSJames Courtier-Dutton for (; *c; c++) 1962184c1e2cSJames Courtier-Dutton remove_ctl(card, *c); 19631da177e4SLinus Torvalds } else { 1964f12aa40cSTakashi Iwai no_ac97: 19652b637da5SLee Revell if (emu->card_capabilities->ecard) 19661da177e4SLinus Torvalds strcpy(emu->card->mixername, "EMU APS"); 19671da177e4SLinus Torvalds else if (emu->audigy) 19681da177e4SLinus Torvalds strcpy(emu->card->mixername, "SB Audigy"); 19691da177e4SLinus Torvalds else 19701da177e4SLinus Torvalds strcpy(emu->card->mixername, "Emu10k1"); 19711da177e4SLinus Torvalds } 19721da177e4SLinus Torvalds 19731da177e4SLinus Torvalds if (emu->audigy) 197421fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 197521fdddeaSJames Courtier-Dutton c = audigy_rename_ctls_1361t_adc; 1976184c1e2cSJames Courtier-Dutton else if (emu->card_capabilities->i2c_adc) 1977184c1e2cSJames Courtier-Dutton c = audigy_rename_ctls_i2c_adc; 197821fdddeaSJames Courtier-Dutton else 19791da177e4SLinus Torvalds c = audigy_rename_ctls; 19801da177e4SLinus Torvalds else 19811da177e4SLinus Torvalds c = emu10k1_rename_ctls; 19821da177e4SLinus Torvalds for (; *c; c += 2) 19831da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 198421fdddeaSJames Courtier-Dutton 1985e217b960SRaymond Yau if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */ 1986e217b960SRaymond Yau remove_ctl(card, "Center Playback Volume"); 1987e217b960SRaymond Yau remove_ctl(card, "LFE Playback Volume"); 1988e217b960SRaymond Yau remove_ctl(card, "Wave Center Playback Volume"); 1989e217b960SRaymond Yau remove_ctl(card, "Wave LFE Playback Volume"); 1990e217b960SRaymond Yau } 1991e3b9bc0eSJames Courtier-Dutton if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ 1992e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); 1993e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); 1994e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); 1995e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); 1996e3b9bc0eSJames Courtier-Dutton } 199712bda107STakashi Iwai kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu); 199812bda107STakashi Iwai if (!kctl) 19991da177e4SLinus Torvalds return -ENOMEM; 200067ed4161SClemens Ladisch kctl->id.device = pcm_device; 200112bda107STakashi Iwai err = snd_ctl_add(card, kctl); 200212bda107STakashi Iwai if (err) 20031da177e4SLinus Torvalds return err; 200412bda107STakashi Iwai kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu); 200512bda107STakashi Iwai if (!kctl) 20061da177e4SLinus Torvalds return -ENOMEM; 200767ed4161SClemens Ladisch kctl->id.device = pcm_device; 200812bda107STakashi Iwai err = snd_ctl_add(card, kctl); 200912bda107STakashi Iwai if (err) 20101da177e4SLinus Torvalds return err; 201112bda107STakashi Iwai kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu); 201212bda107STakashi Iwai if (!kctl) 20131da177e4SLinus Torvalds return -ENOMEM; 201467ed4161SClemens Ladisch kctl->id.device = pcm_device; 201512bda107STakashi Iwai err = snd_ctl_add(card, kctl); 201612bda107STakashi Iwai if (err) 20171da177e4SLinus Torvalds return err; 20181da177e4SLinus Torvalds 201912bda107STakashi Iwai kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu); 202012bda107STakashi Iwai if (!kctl) 20211da177e4SLinus Torvalds return -ENOMEM; 202267ed4161SClemens Ladisch kctl->id.device = multi_device; 202312bda107STakashi Iwai err = snd_ctl_add(card, kctl); 202412bda107STakashi Iwai if (err) 20251da177e4SLinus Torvalds return err; 20261da177e4SLinus Torvalds 202712bda107STakashi Iwai kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu); 202812bda107STakashi Iwai if (!kctl) 20291da177e4SLinus Torvalds return -ENOMEM; 203067ed4161SClemens Ladisch kctl->id.device = multi_device; 203112bda107STakashi Iwai err = snd_ctl_add(card, kctl); 203212bda107STakashi Iwai if (err) 20331da177e4SLinus Torvalds return err; 20341da177e4SLinus Torvalds 203512bda107STakashi Iwai kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu); 203612bda107STakashi Iwai if (!kctl) 20371da177e4SLinus Torvalds return -ENOMEM; 203867ed4161SClemens Ladisch kctl->id.device = multi_device; 203912bda107STakashi Iwai err = snd_ctl_add(card, kctl); 204012bda107STakashi Iwai if (err) 20411da177e4SLinus Torvalds return err; 20421da177e4SLinus Torvalds 20431da177e4SLinus Torvalds /* initialize the routing and volume table for each pcm playback stream */ 20441da177e4SLinus Torvalds for (pcm = 0; pcm < 32; pcm++) { 2045eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 20461da177e4SLinus Torvalds int v; 20471da177e4SLinus Torvalds 20481da177e4SLinus Torvalds mix = &emu->pcm_mixer[pcm]; 20491da177e4SLinus Torvalds mix->epcm = NULL; 20501da177e4SLinus Torvalds 20511da177e4SLinus Torvalds for (v = 0; v < 4; v++) 20521da177e4SLinus Torvalds mix->send_routing[0][v] = 20531da177e4SLinus Torvalds mix->send_routing[1][v] = 20541da177e4SLinus Torvalds mix->send_routing[2][v] = v; 20551da177e4SLinus Torvalds 20561da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 20571da177e4SLinus Torvalds mix->send_volume[0][0] = mix->send_volume[0][1] = 20581da177e4SLinus Torvalds mix->send_volume[1][0] = mix->send_volume[2][1] = 255; 20591da177e4SLinus Torvalds 20601da177e4SLinus Torvalds mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; 20611da177e4SLinus Torvalds } 20621da177e4SLinus Torvalds 20631da177e4SLinus Torvalds /* initialize the routing and volume table for the multichannel playback stream */ 20641da177e4SLinus Torvalds for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) { 2065eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 20661da177e4SLinus Torvalds int v; 20671da177e4SLinus Torvalds 20681da177e4SLinus Torvalds mix = &emu->efx_pcm_mixer[pcm]; 20691da177e4SLinus Torvalds mix->epcm = NULL; 20701da177e4SLinus Torvalds 20711da177e4SLinus Torvalds mix->send_routing[0][0] = pcm; 20721da177e4SLinus Torvalds mix->send_routing[0][1] = (pcm == 0) ? 1 : 0; 20731da177e4SLinus Torvalds for (v = 0; v < 2; v++) 20741da177e4SLinus Torvalds mix->send_routing[0][2+v] = 13+v; 20751da177e4SLinus Torvalds if (emu->audigy) 20761da177e4SLinus Torvalds for (v = 0; v < 4; v++) 20771da177e4SLinus Torvalds mix->send_routing[0][4+v] = 60+v; 20781da177e4SLinus Torvalds 20791da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 20801da177e4SLinus Torvalds mix->send_volume[0][0] = 255; 20811da177e4SLinus Torvalds 20821da177e4SLinus Torvalds mix->attn[0] = 0xffff; 20831da177e4SLinus Torvalds } 20841da177e4SLinus Torvalds 20852b637da5SLee Revell if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */ 20861da177e4SLinus Torvalds /* sb live! and audigy */ 208712bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu); 208812bda107STakashi Iwai if (!kctl) 20891da177e4SLinus Torvalds return -ENOMEM; 20905549d549SClemens Ladisch if (!emu->audigy) 20915549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 209212bda107STakashi Iwai err = snd_ctl_add(card, kctl); 209312bda107STakashi Iwai if (err) 20941da177e4SLinus Torvalds return err; 209512bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu); 209612bda107STakashi Iwai if (!kctl) 20971da177e4SLinus Torvalds return -ENOMEM; 20985549d549SClemens Ladisch if (!emu->audigy) 20995549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 210012bda107STakashi Iwai err = snd_ctl_add(card, kctl); 210112bda107STakashi Iwai if (err) 21021da177e4SLinus Torvalds return err; 21031da177e4SLinus Torvalds } 21041da177e4SLinus Torvalds 2105190d2c46SJames Courtier-Dutton if (emu->card_capabilities->emu_model) { 210619b99fbaSJames Courtier-Dutton ; /* Disable the snd_audigy_spdif_shared_spdif */ 210719b99fbaSJames Courtier-Dutton } else if (emu->audigy) { 210812bda107STakashi Iwai kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu); 210912bda107STakashi Iwai if (!kctl) 21101da177e4SLinus Torvalds return -ENOMEM; 211112bda107STakashi Iwai err = snd_ctl_add(card, kctl); 211212bda107STakashi Iwai if (err) 21131da177e4SLinus Torvalds return err; 2114001f7589SJames Courtier-Dutton #if 0 211512bda107STakashi Iwai kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu); 211612bda107STakashi Iwai if (!kctl) 21171da177e4SLinus Torvalds return -ENOMEM; 211812bda107STakashi Iwai err = snd_ctl_add(card, kctl); 211912bda107STakashi Iwai if (err) 21201da177e4SLinus Torvalds return err; 2121001f7589SJames Courtier-Dutton #endif 21222b637da5SLee Revell } else if (! emu->card_capabilities->ecard) { 21231da177e4SLinus Torvalds /* sb live! */ 212412bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu); 212512bda107STakashi Iwai if (!kctl) 21261da177e4SLinus Torvalds return -ENOMEM; 212712bda107STakashi Iwai err = snd_ctl_add(card, kctl); 212812bda107STakashi Iwai if (err) 21291da177e4SLinus Torvalds return err; 21301da177e4SLinus Torvalds } 21312b637da5SLee Revell if (emu->card_capabilities->ca0151_chip) { /* P16V */ 213212bda107STakashi Iwai err = snd_p16v_mixer(emu); 213312bda107STakashi Iwai if (err) 21341da177e4SLinus Torvalds return err; 21351da177e4SLinus Torvalds } 21361da177e4SLinus Torvalds 21373839e4f1STakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { 21381c02e366SCtirad Fertr /* 1616(m) cardbus */ 21399f4bd5ddSJames Courtier-Dutton int i; 21409f4bd5ddSJames Courtier-Dutton 21411c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) { 21421c02e366SCtirad Fertr err = snd_ctl_add(card, 21431c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1616_output_enum_ctls[i], 21441c02e366SCtirad Fertr emu)); 21459f4bd5ddSJames Courtier-Dutton if (err < 0) 21469f4bd5ddSJames Courtier-Dutton return err; 21479f4bd5ddSJames Courtier-Dutton } 21489f4bd5ddSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { 21491c02e366SCtirad Fertr err = snd_ctl_add(card, 21501c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], 21511c02e366SCtirad Fertr emu)); 21521c02e366SCtirad Fertr if (err < 0) 21531c02e366SCtirad Fertr return err; 21541c02e366SCtirad Fertr } 21551c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) { 21561c02e366SCtirad Fertr err = snd_ctl_add(card, 21571c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); 21581c02e366SCtirad Fertr if (err < 0) 21591c02e366SCtirad Fertr return err; 21601c02e366SCtirad Fertr } 21611c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) { 21621c02e366SCtirad Fertr err = snd_ctl_add(card, 21631c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); 21641c02e366SCtirad Fertr if (err < 0) 21651c02e366SCtirad Fertr return err; 21661c02e366SCtirad Fertr } 21671c02e366SCtirad Fertr err = snd_ctl_add(card, 21681c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 21691c02e366SCtirad Fertr if (err < 0) 21701c02e366SCtirad Fertr return err; 217199dcab46SMichael Gernoth err = snd_ctl_add(card, 217299dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_out, emu)); 217399dcab46SMichael Gernoth if (err < 0) 217499dcab46SMichael Gernoth return err; 217599dcab46SMichael Gernoth err = snd_ctl_add(card, 217699dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_in, emu)); 217799dcab46SMichael Gernoth if (err < 0) 217899dcab46SMichael Gernoth return err; 21791c02e366SCtirad Fertr 218088aa1390STakashi Iwai } else if (emu->card_capabilities->emu_model) { 21811c02e366SCtirad Fertr /* all other e-mu cards for now */ 21821c02e366SCtirad Fertr int i; 21831c02e366SCtirad Fertr 21841c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { 21851c02e366SCtirad Fertr err = snd_ctl_add(card, 21861c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], 21871c02e366SCtirad Fertr emu)); 21881c02e366SCtirad Fertr if (err < 0) 21891c02e366SCtirad Fertr return err; 21901c02e366SCtirad Fertr } 21911c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { 21921c02e366SCtirad Fertr err = snd_ctl_add(card, 21931c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], 21941c02e366SCtirad Fertr emu)); 21959f4bd5ddSJames Courtier-Dutton if (err < 0) 21969f4bd5ddSJames Courtier-Dutton return err; 21979f4bd5ddSJames Courtier-Dutton } 21989148cc50SJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { 21991c02e366SCtirad Fertr err = snd_ctl_add(card, 22001c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); 22019148cc50SJames Courtier-Dutton if (err < 0) 22029148cc50SJames Courtier-Dutton return err; 22039148cc50SJames Courtier-Dutton } 22049148cc50SJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { 22051c02e366SCtirad Fertr err = snd_ctl_add(card, 22061c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); 22079148cc50SJames Courtier-Dutton if (err < 0) 22089148cc50SJames Courtier-Dutton return err; 22099148cc50SJames Courtier-Dutton } 22101c02e366SCtirad Fertr err = snd_ctl_add(card, 22111c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 2212b0dbdaeaSJames Courtier-Dutton if (err < 0) 2213b0dbdaeaSJames Courtier-Dutton return err; 221499dcab46SMichael Gernoth err = snd_ctl_add(card, 221599dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_out, emu)); 221699dcab46SMichael Gernoth if (err < 0) 221799dcab46SMichael Gernoth return err; 221899dcab46SMichael Gernoth err = snd_ctl_add(card, 221999dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_in, emu)); 222099dcab46SMichael Gernoth if (err < 0) 222199dcab46SMichael Gernoth return err; 22229f4bd5ddSJames Courtier-Dutton } 22239f4bd5ddSJames Courtier-Dutton 2224184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 2225184c1e2cSJames Courtier-Dutton int i; 2226184c1e2cSJames Courtier-Dutton 2227184c1e2cSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); 2228184c1e2cSJames Courtier-Dutton if (err < 0) 2229184c1e2cSJames Courtier-Dutton return err; 2230184c1e2cSJames Courtier-Dutton 2231184c1e2cSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { 2232184c1e2cSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); 2233184c1e2cSJames Courtier-Dutton if (err < 0) 2234184c1e2cSJames Courtier-Dutton return err; 2235184c1e2cSJames Courtier-Dutton } 2236184c1e2cSJames Courtier-Dutton } 2237184c1e2cSJames Courtier-Dutton 223816950e09STakashi Iwai if (emu->card_capabilities->ac97_chip && emu->audigy) { 223916950e09STakashi Iwai err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost, 224016950e09STakashi Iwai emu)); 224116950e09STakashi Iwai if (err < 0) 224216950e09STakashi Iwai return err; 224316950e09STakashi Iwai } 224416950e09STakashi Iwai 22451da177e4SLinus Torvalds return 0; 22461da177e4SLinus Torvalds } 2247