11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (c) by Jaroslav Kysela <perex@suse.cz>, 31da177e4SLinus Torvalds * Takashi Iwai <tiwai@suse.de> 41da177e4SLinus Torvalds * Creative Labs, Inc. 51da177e4SLinus Torvalds * Routines for control of EMU10K1 chips / mixer routines 61da177e4SLinus Torvalds * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> 71da177e4SLinus Torvalds * 8*9f4bd5ddSJames Courtier-Dutton * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> 9*9f4bd5ddSJames Courtier-Dutton * Added EMU 1010 support. 10*9f4bd5ddSJames Courtier-Dutton * 111da177e4SLinus Torvalds * BUGS: 121da177e4SLinus Torvalds * -- 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * TODO: 151da177e4SLinus Torvalds * -- 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 181da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 191da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 201da177e4SLinus Torvalds * (at your option) any later version. 211da177e4SLinus Torvalds * 221da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 231da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 241da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 251da177e4SLinus Torvalds * GNU General Public License for more details. 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 281da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 291da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds */ 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds #include <sound/driver.h> 341da177e4SLinus Torvalds #include <linux/time.h> 351da177e4SLinus Torvalds #include <linux/init.h> 361da177e4SLinus Torvalds #include <sound/core.h> 371da177e4SLinus Torvalds #include <sound/emu10k1.h> 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds #define AC97_ID_STAC9758 0x83847658 401da177e4SLinus Torvalds 41eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 421da177e4SLinus Torvalds { 431da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 441da177e4SLinus Torvalds uinfo->count = 1; 451da177e4SLinus Torvalds return 0; 461da177e4SLinus Torvalds } 471da177e4SLinus Torvalds 48eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol, 49eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 501da177e4SLinus Torvalds { 51eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 521da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 531da177e4SLinus Torvalds unsigned long flags; 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 561da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 571da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 581da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 591da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 601da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 611da177e4SLinus Torvalds return 0; 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds 64eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, 65eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 661da177e4SLinus Torvalds { 671da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = 0xff; 681da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = 0xff; 691da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = 0xff; 701da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = 0xff; 711da177e4SLinus Torvalds return 0; 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds 74*9f4bd5ddSJames Courtier-Dutton static char *emu1010_src_texts[] = { 75*9f4bd5ddSJames Courtier-Dutton "Silence", 76*9f4bd5ddSJames Courtier-Dutton "Dock Mic A", 77*9f4bd5ddSJames Courtier-Dutton "Dock Mic B", 78*9f4bd5ddSJames Courtier-Dutton "Dock ADC1 Left", 79*9f4bd5ddSJames Courtier-Dutton "Dock ADC1 Right", 80*9f4bd5ddSJames Courtier-Dutton "Dock ADC2 Left", 81*9f4bd5ddSJames Courtier-Dutton "Dock ADC2 Right", 82*9f4bd5ddSJames Courtier-Dutton "Dock ADC3 Left", 83*9f4bd5ddSJames Courtier-Dutton "Dock ADC3 Right", 84*9f4bd5ddSJames Courtier-Dutton "0202 ADC Left", 85*9f4bd5ddSJames Courtier-Dutton "0202 ADC Right", 86*9f4bd5ddSJames Courtier-Dutton "0202 SPDIF Left", 87*9f4bd5ddSJames Courtier-Dutton "0202 SPDIF Right", 88*9f4bd5ddSJames Courtier-Dutton "ADAT 0", 89*9f4bd5ddSJames Courtier-Dutton "ADAT 1", 90*9f4bd5ddSJames Courtier-Dutton "ADAT 2", 91*9f4bd5ddSJames Courtier-Dutton "ADAT 3", 92*9f4bd5ddSJames Courtier-Dutton "ADAT 4", 93*9f4bd5ddSJames Courtier-Dutton "ADAT 5", 94*9f4bd5ddSJames Courtier-Dutton "ADAT 6", 95*9f4bd5ddSJames Courtier-Dutton "ADAT 7", 96*9f4bd5ddSJames Courtier-Dutton "DSP 0", 97*9f4bd5ddSJames Courtier-Dutton "DSP 1", 98*9f4bd5ddSJames Courtier-Dutton "DSP 2", 99*9f4bd5ddSJames Courtier-Dutton "DSP 3", 100*9f4bd5ddSJames Courtier-Dutton "DSP 4", 101*9f4bd5ddSJames Courtier-Dutton "DSP 5", 102*9f4bd5ddSJames Courtier-Dutton "DSP 6", 103*9f4bd5ddSJames Courtier-Dutton "DSP 7", 104*9f4bd5ddSJames Courtier-Dutton "DSP 8", 105*9f4bd5ddSJames Courtier-Dutton "DSP 9", 106*9f4bd5ddSJames Courtier-Dutton "DSP 10", 107*9f4bd5ddSJames Courtier-Dutton "DSP 11", 108*9f4bd5ddSJames Courtier-Dutton "DSP 12", 109*9f4bd5ddSJames Courtier-Dutton "DSP 13", 110*9f4bd5ddSJames Courtier-Dutton "DSP 14", 111*9f4bd5ddSJames Courtier-Dutton "DSP 15", 112*9f4bd5ddSJames Courtier-Dutton "DSP 16", 113*9f4bd5ddSJames Courtier-Dutton "DSP 17", 114*9f4bd5ddSJames Courtier-Dutton "DSP 18", 115*9f4bd5ddSJames Courtier-Dutton "DSP 19", 116*9f4bd5ddSJames Courtier-Dutton "DSP 20", 117*9f4bd5ddSJames Courtier-Dutton "DSP 21", 118*9f4bd5ddSJames Courtier-Dutton "DSP 22", 119*9f4bd5ddSJames Courtier-Dutton "DSP 23", 120*9f4bd5ddSJames Courtier-Dutton "DSP 24", 121*9f4bd5ddSJames Courtier-Dutton "DSP 25", 122*9f4bd5ddSJames Courtier-Dutton "DSP 26", 123*9f4bd5ddSJames Courtier-Dutton "DSP 27", 124*9f4bd5ddSJames Courtier-Dutton "DSP 28", 125*9f4bd5ddSJames Courtier-Dutton "DSP 29", 126*9f4bd5ddSJames Courtier-Dutton "DSP 30", 127*9f4bd5ddSJames Courtier-Dutton "DSP 31", 128*9f4bd5ddSJames Courtier-Dutton }; 129*9f4bd5ddSJames Courtier-Dutton 130*9f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_src_regs[] = { 131*9f4bd5ddSJames Courtier-Dutton EMU_SRC_SILENCE,/* 0 */ 132*9f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_MIC_A1, /* 1 */ 133*9f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_MIC_B1, /* 2 */ 134*9f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */ 135*9f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */ 136*9f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */ 137*9f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */ 138*9f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */ 139*9f4bd5ddSJames Courtier-Dutton EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */ 140*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */ 141*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */ 142*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */ 143*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */ 144*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT, /* 13 */ 145*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+1, /* 14 */ 146*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+2, /* 15 */ 147*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+3, /* 16 */ 148*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+4, /* 17 */ 149*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+5, /* 18 */ 150*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+6, /* 19 */ 151*9f4bd5ddSJames Courtier-Dutton EMU_SRC_HANA_ADAT+7, /* 20 */ 152*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A, /* 21 */ 153*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+1, /* 22 */ 154*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+2, /* 23 */ 155*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+3, /* 24 */ 156*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+4, /* 25 */ 157*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+5, /* 26 */ 158*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+6, /* 27 */ 159*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+7, /* 28 */ 160*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+8, /* 29 */ 161*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+9, /* 30 */ 162*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xa, /* 31 */ 163*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xb, /* 32 */ 164*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xc, /* 33 */ 165*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xd, /* 34 */ 166*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xe, /* 35 */ 167*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32A+0xf, /* 36 */ 168*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B, /* 37 */ 169*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+1, /* 38 */ 170*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+2, /* 39 */ 171*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+3, /* 40 */ 172*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+4, /* 41 */ 173*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+5, /* 42 */ 174*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+6, /* 43 */ 175*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+7, /* 44 */ 176*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+8, /* 45 */ 177*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+9, /* 46 */ 178*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xa, /* 47 */ 179*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xb, /* 48 */ 180*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xc, /* 49 */ 181*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xd, /* 50 */ 182*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xe, /* 51 */ 183*9f4bd5ddSJames Courtier-Dutton EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ 184*9f4bd5ddSJames Courtier-Dutton }; 185*9f4bd5ddSJames Courtier-Dutton 186*9f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_output_dst[] = { 187*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ 188*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ 189*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ 190*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ 191*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ 192*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ 193*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ 194*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ 195*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ 196*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ 197*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ 198*9f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ 199*9f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ 200*9f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ 201*9f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ 202*9f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ 203*9f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT, /* 16 */ 204*9f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+1, /* 17 */ 205*9f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+2, /* 18 */ 206*9f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+3, /* 19 */ 207*9f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+4, /* 20 */ 208*9f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+5, /* 21 */ 209*9f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+6, /* 22 */ 210*9f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+7, /* 23 */ 211*9f4bd5ddSJames Courtier-Dutton }; 212*9f4bd5ddSJames Courtier-Dutton 213*9f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_input_dst[] = { 214*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_0, 215*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_1, 216*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_2, 217*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_3, 218*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_4, 219*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_5, 220*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_6, 221*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_7, 222*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_8, 223*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_9, 224*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_A, 225*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_B, 226*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_C, 227*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_D, 228*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_E, 229*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_F, 230*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_LEFT, 231*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_RIGHT, 232*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_LEFT, 233*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_RIGHT, 234*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_LEFT, 235*9f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_RIGHT, 236*9f4bd5ddSJames Courtier-Dutton }; 237*9f4bd5ddSJames Courtier-Dutton 238*9f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 239*9f4bd5ddSJames Courtier-Dutton { 240*9f4bd5ddSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 241*9f4bd5ddSJames Courtier-Dutton uinfo->count = 1; 242*9f4bd5ddSJames Courtier-Dutton uinfo->value.enumerated.items = 53; 243*9f4bd5ddSJames Courtier-Dutton if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 244*9f4bd5ddSJames Courtier-Dutton uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 245*9f4bd5ddSJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]); 246*9f4bd5ddSJames Courtier-Dutton return 0; 247*9f4bd5ddSJames Courtier-Dutton } 248*9f4bd5ddSJames Courtier-Dutton 249*9f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, 250*9f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 251*9f4bd5ddSJames Courtier-Dutton { 252*9f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 253*9f4bd5ddSJames Courtier-Dutton int channel; 254*9f4bd5ddSJames Courtier-Dutton 255*9f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 256*9f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; 257*9f4bd5ddSJames Courtier-Dutton return 0; 258*9f4bd5ddSJames Courtier-Dutton } 259*9f4bd5ddSJames Courtier-Dutton 260*9f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, 261*9f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 262*9f4bd5ddSJames Courtier-Dutton { 263*9f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 264*9f4bd5ddSJames Courtier-Dutton int change = 0; 265*9f4bd5ddSJames Courtier-Dutton unsigned int val; 266*9f4bd5ddSJames Courtier-Dutton int channel; 267*9f4bd5ddSJames Courtier-Dutton 268*9f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 269*9f4bd5ddSJames Courtier-Dutton if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) { 270*9f4bd5ddSJames Courtier-Dutton val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0]; 271*9f4bd5ddSJames Courtier-Dutton change = 1; 272*9f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 273*9f4bd5ddSJames Courtier-Dutton emu1010_output_dst[channel], emu1010_src_regs[val]); 274*9f4bd5ddSJames Courtier-Dutton } 275*9f4bd5ddSJames Courtier-Dutton return change; 276*9f4bd5ddSJames Courtier-Dutton } 277*9f4bd5ddSJames Courtier-Dutton 278*9f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, 279*9f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 280*9f4bd5ddSJames Courtier-Dutton { 281*9f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 282*9f4bd5ddSJames Courtier-Dutton int channel; 283*9f4bd5ddSJames Courtier-Dutton 284*9f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 285*9f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; 286*9f4bd5ddSJames Courtier-Dutton return 0; 287*9f4bd5ddSJames Courtier-Dutton } 288*9f4bd5ddSJames Courtier-Dutton 289*9f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, 290*9f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 291*9f4bd5ddSJames Courtier-Dutton { 292*9f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 293*9f4bd5ddSJames Courtier-Dutton int change = 0; 294*9f4bd5ddSJames Courtier-Dutton unsigned int val; 295*9f4bd5ddSJames Courtier-Dutton int channel; 296*9f4bd5ddSJames Courtier-Dutton 297*9f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 298*9f4bd5ddSJames Courtier-Dutton if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) { 299*9f4bd5ddSJames Courtier-Dutton val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0]; 300*9f4bd5ddSJames Courtier-Dutton change = 1; 301*9f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 302*9f4bd5ddSJames Courtier-Dutton emu1010_input_dst[channel], emu1010_src_regs[val]); 303*9f4bd5ddSJames Courtier-Dutton } 304*9f4bd5ddSJames Courtier-Dutton return change; 305*9f4bd5ddSJames Courtier-Dutton } 306*9f4bd5ddSJames Courtier-Dutton 307*9f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \ 308*9f4bd5ddSJames Courtier-Dutton { \ 309*9f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 310*9f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 311*9f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 312*9f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_output_source_get, \ 313*9f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_output_source_put, \ 314*9f4bd5ddSJames Courtier-Dutton .private_value = chid \ 315*9f4bd5ddSJames Courtier-Dutton } 316*9f4bd5ddSJames Courtier-Dutton 317*9f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { 318*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock DAC1 Left", 0), 319*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock DAC1 Right", 1), 320*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock DAC2 Left", 2), 321*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock DAC2 Right", 3), 322*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock DAC3 Left", 4), 323*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock DAC3 Right", 5), 324*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock DAC4 Left", 6), 325*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock DAC4 Right", 7), 326*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock Phones Left", 8), 327*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock Phones Right", 9), 328*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock SPDIF Left", 0xa), 329*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback Dock SPDIF Right", 0xb), 330*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 1010 SPDIF Left", 0xc), 331*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 1010 SPDIF Right", 0xd), 332*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 0202 DAC Left", 0xe), 333*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 0202 DAC Right", 0xf), 334*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 0", 0x10), 335*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 1", 0x11), 336*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 2", 0x12), 337*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 3", 0x13), 338*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 4", 0x14), 339*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 5", 0x15), 340*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 6", 0x16), 341*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 7", 0x17), 342*9f4bd5ddSJames Courtier-Dutton }; 343*9f4bd5ddSJames Courtier-Dutton 344*9f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \ 345*9f4bd5ddSJames Courtier-Dutton { \ 346*9f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 347*9f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 348*9f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 349*9f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_input_source_get, \ 350*9f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_input_source_put, \ 351*9f4bd5ddSJames Courtier-Dutton .private_value = chid \ 352*9f4bd5ddSJames Courtier-Dutton } 353*9f4bd5ddSJames Courtier-Dutton 354*9f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { 355*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 0 CAPTURE ENUM", 0), 356*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 1 CAPTURE ENUM", 1), 357*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 2 CAPTURE ENUM", 2), 358*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 3 CAPTURE ENUM", 3), 359*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 4 CAPTURE ENUM", 4), 360*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 5 CAPTURE ENUM", 5), 361*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 6 CAPTURE ENUM", 6), 362*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 7 CAPTURE ENUM", 7), 363*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 8 CAPTURE ENUM", 8), 364*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 9 CAPTURE ENUM", 9), 365*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP A CAPTURE ENUM", 0xa), 366*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP B CAPTURE ENUM", 0xb), 367*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP C CAPTURE ENUM", 0xc), 368*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP D CAPTURE ENUM", 0xd), 369*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP E CAPTURE ENUM", 0xe), 370*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP F CAPTURE ENUM", 0xf), 371*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 10 CAPTURE ENUM", 0x10), 372*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 11 CAPTURE ENUM", 0x11), 373*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 12 CAPTURE ENUM", 0x12), 374*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 13 CAPTURE ENUM", 0x13), 375*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 14 CAPTURE ENUM", 0x14), 376*9f4bd5ddSJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 15 CAPTURE ENUM", 0x15), 377*9f4bd5ddSJames Courtier-Dutton }; 378*9f4bd5ddSJames Courtier-Dutton 3790af68e5eSTakashi Iwai #if 0 380eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 3811da177e4SLinus Torvalds { 3821da177e4SLinus Torvalds static char *texts[] = {"44100", "48000", "96000"}; 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 3851da177e4SLinus Torvalds uinfo->count = 1; 3861da177e4SLinus Torvalds uinfo->value.enumerated.items = 3; 3871da177e4SLinus Torvalds if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 3881da177e4SLinus Torvalds uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 3891da177e4SLinus Torvalds strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 3901da177e4SLinus Torvalds return 0; 3911da177e4SLinus Torvalds } 3921da177e4SLinus Torvalds 393eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, 394eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3951da177e4SLinus Torvalds { 396eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 3971da177e4SLinus Torvalds unsigned int tmp; 3981da177e4SLinus Torvalds unsigned long flags; 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 4021da177e4SLinus Torvalds tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 4031da177e4SLinus Torvalds switch (tmp & A_SPDIF_RATE_MASK) { 4041da177e4SLinus Torvalds case A_SPDIF_44100: 4051da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 4061da177e4SLinus Torvalds break; 4071da177e4SLinus Torvalds case A_SPDIF_48000: 4081da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 4091da177e4SLinus Torvalds break; 4101da177e4SLinus Torvalds case A_SPDIF_96000: 4111da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 4121da177e4SLinus Torvalds break; 4131da177e4SLinus Torvalds default: 4141da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 4171da177e4SLinus Torvalds return 0; 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 420eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, 421eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 4221da177e4SLinus Torvalds { 423eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4241da177e4SLinus Torvalds int change; 4251da177e4SLinus Torvalds unsigned int reg, val, tmp; 4261da177e4SLinus Torvalds unsigned long flags; 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds switch(ucontrol->value.enumerated.item[0]) { 4291da177e4SLinus Torvalds case 0: 4301da177e4SLinus Torvalds val = A_SPDIF_44100; 4311da177e4SLinus Torvalds break; 4321da177e4SLinus Torvalds case 1: 4331da177e4SLinus Torvalds val = A_SPDIF_48000; 4341da177e4SLinus Torvalds break; 4351da177e4SLinus Torvalds case 2: 4361da177e4SLinus Torvalds val = A_SPDIF_96000; 4371da177e4SLinus Torvalds break; 4381da177e4SLinus Torvalds default: 4391da177e4SLinus Torvalds val = A_SPDIF_48000; 4401da177e4SLinus Torvalds break; 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 4451da177e4SLinus Torvalds reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 4461da177e4SLinus Torvalds tmp = reg & ~A_SPDIF_RATE_MASK; 4471da177e4SLinus Torvalds tmp |= val; 4481da177e4SLinus Torvalds if ((change = (tmp != reg))) 4491da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); 4501da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 4511da177e4SLinus Torvalds return change; 4521da177e4SLinus Torvalds } 4531da177e4SLinus Torvalds 454eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_spdif_output_rate = 4551da177e4SLinus Torvalds { 4561da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 4571da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4581da177e4SLinus Torvalds .name = "Audigy SPDIF Output Sample Rate", 4591da177e4SLinus Torvalds .count = 1, 4601da177e4SLinus Torvalds .info = snd_audigy_spdif_output_rate_info, 4611da177e4SLinus Torvalds .get = snd_audigy_spdif_output_rate_get, 4621da177e4SLinus Torvalds .put = snd_audigy_spdif_output_rate_put 4631da177e4SLinus Torvalds }; 4640af68e5eSTakashi Iwai #endif 4651da177e4SLinus Torvalds 466eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, 467eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 4681da177e4SLinus Torvalds { 469eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4701da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 4711da177e4SLinus Torvalds int change; 4721da177e4SLinus Torvalds unsigned int val; 4731da177e4SLinus Torvalds unsigned long flags; 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 4761da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 4771da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 4781da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 4791da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 4801da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 4811da177e4SLinus Torvalds if (change) { 4821da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); 4831da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 4841da177e4SLinus Torvalds } 4851da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 4861da177e4SLinus Torvalds return change; 4871da177e4SLinus Torvalds } 4881da177e4SLinus Torvalds 489eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = 4901da177e4SLinus Torvalds { 4911da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 4925549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4931da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 4941da177e4SLinus Torvalds .count = 4, 4951da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 4961da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get_mask 4971da177e4SLinus Torvalds }; 4981da177e4SLinus Torvalds 499eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_control = 5001da177e4SLinus Torvalds { 5015549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 5021da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 5031da177e4SLinus Torvalds .count = 4, 5041da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 5051da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get, 5061da177e4SLinus Torvalds .put = snd_emu10k1_spdif_put 5071da177e4SLinus Torvalds }; 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds 510eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route) 5111da177e4SLinus Torvalds { 5121da177e4SLinus Torvalds if (emu->audigy) { 5131da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT1, voice, 5141da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt1(route)); 5151da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 5161da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt2(route)); 5171da177e4SLinus Torvalds } else { 5181da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXRT, voice, 5191da177e4SLinus Torvalds snd_emu10k1_compose_send_routing(route)); 5201da177e4SLinus Torvalds } 5211da177e4SLinus Torvalds } 5221da177e4SLinus Torvalds 523eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume) 5241da177e4SLinus Torvalds { 5251da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); 5261da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); 5271da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); 5281da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); 5291da177e4SLinus Torvalds if (emu->audigy) { 5301da177e4SLinus Torvalds unsigned int val = ((unsigned int)volume[4] << 24) | 5311da177e4SLinus Torvalds ((unsigned int)volume[5] << 16) | 5321da177e4SLinus Torvalds ((unsigned int)volume[6] << 8) | 5331da177e4SLinus Torvalds (unsigned int)volume[7]; 5341da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val); 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds } 5371da177e4SLinus Torvalds 5381da177e4SLinus Torvalds /* PCM stream controls */ 5391da177e4SLinus Torvalds 540eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 5411da177e4SLinus Torvalds { 542eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 5431da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 5441da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 5451da177e4SLinus Torvalds uinfo->value.integer.min = 0; 5461da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 5471da177e4SLinus Torvalds return 0; 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds 550eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, 551eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 5521da177e4SLinus Torvalds { 5531da177e4SLinus Torvalds unsigned long flags; 554eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 555eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 556eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 5571da177e4SLinus Torvalds int voice, idx; 5581da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 5591da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 5621da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 5631da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 5641da177e4SLinus Torvalds ucontrol->value.integer.value[(voice * num_efx) + idx] = 5651da177e4SLinus Torvalds mix->send_routing[voice][idx] & mask; 5661da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 5671da177e4SLinus Torvalds return 0; 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds 570eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, 571eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 5721da177e4SLinus Torvalds { 5731da177e4SLinus Torvalds unsigned long flags; 574eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 575eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 576eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 5771da177e4SLinus Torvalds int change = 0, voice, idx, val; 5781da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 5791da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 5821da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 5831da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 5841da177e4SLinus Torvalds val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; 5851da177e4SLinus Torvalds if (mix->send_routing[voice][idx] != val) { 5861da177e4SLinus Torvalds mix->send_routing[voice][idx] = val; 5871da177e4SLinus Torvalds change = 1; 5881da177e4SLinus Torvalds } 5891da177e4SLinus Torvalds } 5901da177e4SLinus Torvalds if (change && mix->epcm) { 5911da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 5921da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 5931da177e4SLinus Torvalds &mix->send_routing[1][0]); 5941da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, 5951da177e4SLinus Torvalds &mix->send_routing[2][0]); 5961da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 5971da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 5981da177e4SLinus Torvalds &mix->send_routing[0][0]); 5991da177e4SLinus Torvalds } 6001da177e4SLinus Torvalds } 6011da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 6021da177e4SLinus Torvalds return change; 6031da177e4SLinus Torvalds } 6041da177e4SLinus Torvalds 605eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_routing_control = 6061da177e4SLinus Torvalds { 6071da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 60867ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 6091da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Routing", 6101da177e4SLinus Torvalds .count = 32, 6111da177e4SLinus Torvalds .info = snd_emu10k1_send_routing_info, 6121da177e4SLinus Torvalds .get = snd_emu10k1_send_routing_get, 6131da177e4SLinus Torvalds .put = snd_emu10k1_send_routing_put 6141da177e4SLinus Torvalds }; 6151da177e4SLinus Torvalds 616eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 6171da177e4SLinus Torvalds { 618eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6191da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 6201da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 6211da177e4SLinus Torvalds uinfo->value.integer.min = 0; 6221da177e4SLinus Torvalds uinfo->value.integer.max = 255; 6231da177e4SLinus Torvalds return 0; 6241da177e4SLinus Torvalds } 6251da177e4SLinus Torvalds 626eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, 627eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 6281da177e4SLinus Torvalds { 6291da177e4SLinus Torvalds unsigned long flags; 630eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 631eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 632eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 6331da177e4SLinus Torvalds int idx; 6341da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 6371da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) 6381da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; 6391da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 6401da177e4SLinus Torvalds return 0; 6411da177e4SLinus Torvalds } 6421da177e4SLinus Torvalds 643eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, 644eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 6451da177e4SLinus Torvalds { 6461da177e4SLinus Torvalds unsigned long flags; 647eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 648eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 649eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 6501da177e4SLinus Torvalds int change = 0, idx, val; 6511da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 6521da177e4SLinus Torvalds 6531da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 6541da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) { 6551da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 6561da177e4SLinus Torvalds if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { 6571da177e4SLinus Torvalds mix->send_volume[idx/num_efx][idx%num_efx] = val; 6581da177e4SLinus Torvalds change = 1; 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds } 6611da177e4SLinus Torvalds if (change && mix->epcm) { 6621da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 6631da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 6641da177e4SLinus Torvalds &mix->send_volume[1][0]); 6651da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, 6661da177e4SLinus Torvalds &mix->send_volume[2][0]); 6671da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 6681da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 6691da177e4SLinus Torvalds &mix->send_volume[0][0]); 6701da177e4SLinus Torvalds } 6711da177e4SLinus Torvalds } 6721da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 6731da177e4SLinus Torvalds return change; 6741da177e4SLinus Torvalds } 6751da177e4SLinus Torvalds 676eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_volume_control = 6771da177e4SLinus Torvalds { 6781da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 67967ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 6801da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Volume", 6811da177e4SLinus Torvalds .count = 32, 6821da177e4SLinus Torvalds .info = snd_emu10k1_send_volume_info, 6831da177e4SLinus Torvalds .get = snd_emu10k1_send_volume_get, 6841da177e4SLinus Torvalds .put = snd_emu10k1_send_volume_put 6851da177e4SLinus Torvalds }; 6861da177e4SLinus Torvalds 687eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 6881da177e4SLinus Torvalds { 6891da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 6901da177e4SLinus Torvalds uinfo->count = 3; 6911da177e4SLinus Torvalds uinfo->value.integer.min = 0; 6921da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 6931da177e4SLinus Torvalds return 0; 6941da177e4SLinus Torvalds } 6951da177e4SLinus Torvalds 696eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, 697eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 6981da177e4SLinus Torvalds { 699eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 700eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 701eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 7021da177e4SLinus Torvalds unsigned long flags; 7031da177e4SLinus Torvalds int idx; 7041da177e4SLinus Torvalds 7051da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 7061da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) 7071da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->attn[idx]; 7081da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 7091da177e4SLinus Torvalds return 0; 7101da177e4SLinus Torvalds } 7111da177e4SLinus Torvalds 712eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, 713eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 7141da177e4SLinus Torvalds { 7151da177e4SLinus Torvalds unsigned long flags; 716eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 717eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 718eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 7191da177e4SLinus Torvalds int change = 0, idx, val; 7201da177e4SLinus Torvalds 7211da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 7221da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) { 7231da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 0xffff; 7241da177e4SLinus Torvalds if (mix->attn[idx] != val) { 7251da177e4SLinus Torvalds mix->attn[idx] = val; 7261da177e4SLinus Torvalds change = 1; 7271da177e4SLinus Torvalds } 7281da177e4SLinus Torvalds } 7291da177e4SLinus Torvalds if (change && mix->epcm) { 7301da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 7311da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); 7321da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); 7331da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 7341da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); 7351da177e4SLinus Torvalds } 7361da177e4SLinus Torvalds } 7371da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 7381da177e4SLinus Torvalds return change; 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds 741eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_attn_control = 7421da177e4SLinus Torvalds { 7431da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 74467ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 7451da177e4SLinus Torvalds .name = "EMU10K1 PCM Volume", 7461da177e4SLinus Torvalds .count = 32, 7471da177e4SLinus Torvalds .info = snd_emu10k1_attn_info, 7481da177e4SLinus Torvalds .get = snd_emu10k1_attn_get, 7491da177e4SLinus Torvalds .put = snd_emu10k1_attn_put 7501da177e4SLinus Torvalds }; 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds /* Mutichannel PCM stream controls */ 7531da177e4SLinus Torvalds 754eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 7551da177e4SLinus Torvalds { 756eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 7571da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 7581da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 7591da177e4SLinus Torvalds uinfo->value.integer.min = 0; 7601da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 7611da177e4SLinus Torvalds return 0; 7621da177e4SLinus Torvalds } 7631da177e4SLinus Torvalds 764eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, 765eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 7661da177e4SLinus Torvalds { 7671da177e4SLinus Torvalds unsigned long flags; 768eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 769eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 770eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 7711da177e4SLinus Torvalds int idx; 7721da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 7731da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 7741da177e4SLinus Torvalds 7751da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 7761da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 7771da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = 7781da177e4SLinus Torvalds mix->send_routing[0][idx] & mask; 7791da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 7801da177e4SLinus Torvalds return 0; 7811da177e4SLinus Torvalds } 7821da177e4SLinus Torvalds 783eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, 784eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 7851da177e4SLinus Torvalds { 7861da177e4SLinus Torvalds unsigned long flags; 787eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 7881da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 789eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 7901da177e4SLinus Torvalds int change = 0, idx, val; 7911da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 7921da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 7951da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 7961da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & mask; 7971da177e4SLinus Torvalds if (mix->send_routing[0][idx] != val) { 7981da177e4SLinus Torvalds mix->send_routing[0][idx] = val; 7991da177e4SLinus Torvalds change = 1; 8001da177e4SLinus Torvalds } 8011da177e4SLinus Torvalds } 8021da177e4SLinus Torvalds 8031da177e4SLinus Torvalds if (change && mix->epcm) { 8041da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 8051da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, 8061da177e4SLinus Torvalds &mix->send_routing[0][0]); 8071da177e4SLinus Torvalds } 8081da177e4SLinus Torvalds } 8091da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 8101da177e4SLinus Torvalds return change; 8111da177e4SLinus Torvalds } 8121da177e4SLinus Torvalds 813eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = 8141da177e4SLinus Torvalds { 8151da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 8161da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8171da177e4SLinus Torvalds .name = "Multichannel PCM Send Routing", 8181da177e4SLinus Torvalds .count = 16, 8191da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_routing_info, 8201da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_routing_get, 8211da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_routing_put 8221da177e4SLinus Torvalds }; 8231da177e4SLinus Torvalds 824eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 8251da177e4SLinus Torvalds { 826eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 8271da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 8281da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 8291da177e4SLinus Torvalds uinfo->value.integer.min = 0; 8301da177e4SLinus Torvalds uinfo->value.integer.max = 255; 8311da177e4SLinus Torvalds return 0; 8321da177e4SLinus Torvalds } 8331da177e4SLinus Torvalds 834eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, 835eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 8361da177e4SLinus Torvalds { 8371da177e4SLinus Torvalds unsigned long flags; 838eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 839eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 840eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 8411da177e4SLinus Torvalds int idx; 8421da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 8431da177e4SLinus Torvalds 8441da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 8451da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 8461da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; 8471da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 8481da177e4SLinus Torvalds return 0; 8491da177e4SLinus Torvalds } 8501da177e4SLinus Torvalds 851eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, 852eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 8531da177e4SLinus Torvalds { 8541da177e4SLinus Torvalds unsigned long flags; 855eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 8561da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 857eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 8581da177e4SLinus Torvalds int change = 0, idx, val; 8591da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 8601da177e4SLinus Torvalds 8611da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 8621da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 8631da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 8641da177e4SLinus Torvalds if (mix->send_volume[0][idx] != val) { 8651da177e4SLinus Torvalds mix->send_volume[0][idx] = val; 8661da177e4SLinus Torvalds change = 1; 8671da177e4SLinus Torvalds } 8681da177e4SLinus Torvalds } 8691da177e4SLinus Torvalds if (change && mix->epcm) { 8701da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 8711da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, 8721da177e4SLinus Torvalds &mix->send_volume[0][0]); 8731da177e4SLinus Torvalds } 8741da177e4SLinus Torvalds } 8751da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 8761da177e4SLinus Torvalds return change; 8771da177e4SLinus Torvalds } 8781da177e4SLinus Torvalds 8791da177e4SLinus Torvalds 880eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = 8811da177e4SLinus Torvalds { 8821da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 8831da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8841da177e4SLinus Torvalds .name = "Multichannel PCM Send Volume", 8851da177e4SLinus Torvalds .count = 16, 8861da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_volume_info, 8871da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_volume_get, 8881da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_volume_put 8891da177e4SLinus Torvalds }; 8901da177e4SLinus Torvalds 891eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 8921da177e4SLinus Torvalds { 8931da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 8941da177e4SLinus Torvalds uinfo->count = 1; 8951da177e4SLinus Torvalds uinfo->value.integer.min = 0; 8961da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 8971da177e4SLinus Torvalds return 0; 8981da177e4SLinus Torvalds } 8991da177e4SLinus Torvalds 900eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, 901eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9021da177e4SLinus Torvalds { 903eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 904eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 905eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 9061da177e4SLinus Torvalds unsigned long flags; 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 9091da177e4SLinus Torvalds ucontrol->value.integer.value[0] = mix->attn[0]; 9101da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 9111da177e4SLinus Torvalds return 0; 9121da177e4SLinus Torvalds } 9131da177e4SLinus Torvalds 914eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, 915eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9161da177e4SLinus Torvalds { 9171da177e4SLinus Torvalds unsigned long flags; 918eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9191da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 920eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 9211da177e4SLinus Torvalds int change = 0, val; 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 9241da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] & 0xffff; 9251da177e4SLinus Torvalds if (mix->attn[0] != val) { 9261da177e4SLinus Torvalds mix->attn[0] = val; 9271da177e4SLinus Torvalds change = 1; 9281da177e4SLinus Torvalds } 9291da177e4SLinus Torvalds if (change && mix->epcm) { 9301da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 9311da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); 9321da177e4SLinus Torvalds } 9331da177e4SLinus Torvalds } 9341da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 9351da177e4SLinus Torvalds return change; 9361da177e4SLinus Torvalds } 9371da177e4SLinus Torvalds 938eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_attn_control = 9391da177e4SLinus Torvalds { 9401da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 9411da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 9421da177e4SLinus Torvalds .name = "Multichannel PCM Volume", 9431da177e4SLinus Torvalds .count = 16, 9441da177e4SLinus Torvalds .info = snd_emu10k1_efx_attn_info, 9451da177e4SLinus Torvalds .get = snd_emu10k1_efx_attn_get, 9461da177e4SLinus Torvalds .put = snd_emu10k1_efx_attn_put 9471da177e4SLinus Torvalds }; 9481da177e4SLinus Torvalds 949eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 9501da177e4SLinus Torvalds { 9511da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 9521da177e4SLinus Torvalds uinfo->count = 1; 9531da177e4SLinus Torvalds uinfo->value.integer.min = 0; 9541da177e4SLinus Torvalds uinfo->value.integer.max = 1; 9551da177e4SLinus Torvalds return 0; 9561da177e4SLinus Torvalds } 9571da177e4SLinus Torvalds 958eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, 959eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9601da177e4SLinus Torvalds { 961eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds if (emu->audigy) 9641da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; 9651da177e4SLinus Torvalds else 9661da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; 9671da177e4SLinus Torvalds return 0; 9681da177e4SLinus Torvalds } 9691da177e4SLinus Torvalds 970eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, 971eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9721da177e4SLinus Torvalds { 9731da177e4SLinus Torvalds unsigned long flags; 974eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9751da177e4SLinus Torvalds unsigned int reg, val; 9761da177e4SLinus Torvalds int change = 0; 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 9791da177e4SLinus Torvalds if (emu->audigy) { 9801da177e4SLinus Torvalds reg = inl(emu->port + A_IOCFG); 9811da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; 9821da177e4SLinus Torvalds change = (reg & A_IOCFG_GPOUT0) != val; 9831da177e4SLinus Torvalds if (change) { 9841da177e4SLinus Torvalds reg &= ~A_IOCFG_GPOUT0; 9851da177e4SLinus Torvalds reg |= val; 9861da177e4SLinus Torvalds outl(reg | val, emu->port + A_IOCFG); 9871da177e4SLinus Torvalds } 9881da177e4SLinus Torvalds } 9891da177e4SLinus Torvalds reg = inl(emu->port + HCFG); 9901da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0; 9911da177e4SLinus Torvalds change |= (reg & HCFG_GPOUT0) != val; 9921da177e4SLinus Torvalds if (change) { 9931da177e4SLinus Torvalds reg &= ~HCFG_GPOUT0; 9941da177e4SLinus Torvalds reg |= val; 9951da177e4SLinus Torvalds outl(reg | val, emu->port + HCFG); 9961da177e4SLinus Torvalds } 9971da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 9981da177e4SLinus Torvalds return change; 9991da177e4SLinus Torvalds } 10001da177e4SLinus Torvalds 1001eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata = 10021da177e4SLinus Torvalds { 10031da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 10041da177e4SLinus Torvalds .name = "SB Live Analog/Digital Output Jack", 10051da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 10061da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 10071da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 10081da177e4SLinus Torvalds }; 10091da177e4SLinus Torvalds 1010eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata = 10111da177e4SLinus Torvalds { 10121da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 10131da177e4SLinus Torvalds .name = "Audigy Analog/Digital Output Jack", 10141da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 10151da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 10161da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 10171da177e4SLinus Torvalds }; 10181da177e4SLinus Torvalds 10191da177e4SLinus Torvalds /* 10201da177e4SLinus Torvalds */ 1021eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) 10221da177e4SLinus Torvalds { 1023eb4698f3STakashi Iwai struct snd_emu10k1 *emu = ac97->private_data; 10241da177e4SLinus Torvalds emu->ac97 = NULL; 10251da177e4SLinus Torvalds } 10261da177e4SLinus Torvalds 10271da177e4SLinus Torvalds /* 10281da177e4SLinus Torvalds */ 1029eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name) 10301da177e4SLinus Torvalds { 1031eb4698f3STakashi Iwai struct snd_ctl_elem_id id; 10321da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 10331da177e4SLinus Torvalds strcpy(id.name, name); 10341da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 10351da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 10361da177e4SLinus Torvalds } 10371da177e4SLinus Torvalds 1038eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) 10391da177e4SLinus Torvalds { 1040eb4698f3STakashi Iwai struct snd_ctl_elem_id sid; 10411da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 10421da177e4SLinus Torvalds strcpy(sid.name, name); 10431da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 10441da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 10451da177e4SLinus Torvalds } 10461da177e4SLinus Torvalds 1047eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst) 10481da177e4SLinus Torvalds { 1049eb4698f3STakashi Iwai struct snd_kcontrol *kctl = ctl_find(card, src); 10501da177e4SLinus Torvalds if (kctl) { 10511da177e4SLinus Torvalds strcpy(kctl->id.name, dst); 10521da177e4SLinus Torvalds return 0; 10531da177e4SLinus Torvalds } 10541da177e4SLinus Torvalds return -ENOENT; 10551da177e4SLinus Torvalds } 10561da177e4SLinus Torvalds 1057eb4698f3STakashi Iwai int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, 105867ed4161SClemens Ladisch int pcm_device, int multi_device) 10591da177e4SLinus Torvalds { 10601da177e4SLinus Torvalds int err, pcm; 1061eb4698f3STakashi Iwai struct snd_kcontrol *kctl; 1062eb4698f3STakashi Iwai struct snd_card *card = emu->card; 10631da177e4SLinus Torvalds char **c; 10641da177e4SLinus Torvalds static char *emu10k1_remove_ctls[] = { 10651da177e4SLinus Torvalds /* no AC97 mono, surround, center/lfe */ 10661da177e4SLinus Torvalds "Master Mono Playback Switch", 10671da177e4SLinus Torvalds "Master Mono Playback Volume", 10681da177e4SLinus Torvalds "PCM Out Path & Mute", 10691da177e4SLinus Torvalds "Mono Output Select", 10707eae36fbSTakashi Iwai "Front Playback Switch", 10717eae36fbSTakashi Iwai "Front Playback Volume", 10721da177e4SLinus Torvalds "Surround Playback Switch", 10731da177e4SLinus Torvalds "Surround Playback Volume", 10741da177e4SLinus Torvalds "Center Playback Switch", 10751da177e4SLinus Torvalds "Center Playback Volume", 10761da177e4SLinus Torvalds "LFE Playback Switch", 10771da177e4SLinus Torvalds "LFE Playback Volume", 10781da177e4SLinus Torvalds NULL 10791da177e4SLinus Torvalds }; 10801da177e4SLinus Torvalds static char *emu10k1_rename_ctls[] = { 10811da177e4SLinus Torvalds "Surround Digital Playback Volume", "Surround Playback Volume", 10821da177e4SLinus Torvalds "Center Digital Playback Volume", "Center Playback Volume", 10831da177e4SLinus Torvalds "LFE Digital Playback Volume", "LFE Playback Volume", 10841da177e4SLinus Torvalds NULL 10851da177e4SLinus Torvalds }; 10861da177e4SLinus Torvalds static char *audigy_remove_ctls[] = { 10871da177e4SLinus Torvalds /* Master/PCM controls on ac97 of Audigy has no effect */ 108821fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 108921fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 10901da177e4SLinus Torvalds "PCM Playback Switch", 10911da177e4SLinus Torvalds "PCM Playback Volume", 10921da177e4SLinus Torvalds "Master Mono Playback Switch", 10931da177e4SLinus Torvalds "Master Mono Playback Volume", 10941da177e4SLinus Torvalds "Master Playback Switch", 10951da177e4SLinus Torvalds "Master Playback Volume", 10961da177e4SLinus Torvalds "PCM Out Path & Mute", 10971da177e4SLinus Torvalds "Mono Output Select", 10981da177e4SLinus Torvalds /* remove unused AC97 capture controls */ 10991da177e4SLinus Torvalds "Capture Source", 11001da177e4SLinus Torvalds "Capture Switch", 11011da177e4SLinus Torvalds "Capture Volume", 11021da177e4SLinus Torvalds "Mic Select", 11031da177e4SLinus Torvalds "Video Playback Switch", 11041da177e4SLinus Torvalds "Video Playback Volume", 11051da177e4SLinus Torvalds "Mic Playback Switch", 11061da177e4SLinus Torvalds "Mic Playback Volume", 11071da177e4SLinus Torvalds NULL 11081da177e4SLinus Torvalds }; 11091da177e4SLinus Torvalds static char *audigy_rename_ctls[] = { 11101da177e4SLinus Torvalds /* use conventional names */ 11111da177e4SLinus Torvalds "Wave Playback Volume", "PCM Playback Volume", 11121da177e4SLinus Torvalds /* "Wave Capture Volume", "PCM Capture Volume", */ 11131da177e4SLinus Torvalds "Wave Master Playback Volume", "Master Playback Volume", 11141da177e4SLinus Torvalds "AMic Playback Volume", "Mic Playback Volume", 11151da177e4SLinus Torvalds NULL 11161da177e4SLinus Torvalds }; 111721fdddeaSJames Courtier-Dutton static char *audigy_remove_ctls_1361t_adc[] = { 111821fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 111921fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 112021fdddeaSJames Courtier-Dutton "PCM Playback Switch", 112121fdddeaSJames Courtier-Dutton "PCM Playback Volume", 112221fdddeaSJames Courtier-Dutton "Master Mono Playback Switch", 112321fdddeaSJames Courtier-Dutton "Master Mono Playback Volume", 112421fdddeaSJames Courtier-Dutton "Capture Source", 112521fdddeaSJames Courtier-Dutton "Capture Switch", 112621fdddeaSJames Courtier-Dutton "Capture Volume", 112721fdddeaSJames Courtier-Dutton "Mic Capture Volume", 112821fdddeaSJames Courtier-Dutton "Headphone Playback Switch", 112921fdddeaSJames Courtier-Dutton "Headphone Playback Volume", 113021fdddeaSJames Courtier-Dutton "3D Control - Center", 113121fdddeaSJames Courtier-Dutton "3D Control - Depth", 113221fdddeaSJames Courtier-Dutton "3D Control - Switch", 113321fdddeaSJames Courtier-Dutton "Line2 Playback Volume", 113421fdddeaSJames Courtier-Dutton "Line2 Capture Volume", 113521fdddeaSJames Courtier-Dutton NULL 113621fdddeaSJames Courtier-Dutton }; 113721fdddeaSJames Courtier-Dutton static char *audigy_rename_ctls_1361t_adc[] = { 113821fdddeaSJames Courtier-Dutton "Master Playback Switch", "Master Capture Switch", 113921fdddeaSJames Courtier-Dutton "Master Playback Volume", "Master Capture Volume", 114021fdddeaSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 114121fdddeaSJames Courtier-Dutton "PC Speaker Playback Switch", "PC Speaker Capture Switch", 114221fdddeaSJames Courtier-Dutton "PC Speaker Playback Volume", "PC Speaker Capture Volume", 114321fdddeaSJames Courtier-Dutton "Phone Playback Switch", "Phone Capture Switch", 114421fdddeaSJames Courtier-Dutton "Phone Playback Volume", "Phone Capture Volume", 114521fdddeaSJames Courtier-Dutton "Mic Playback Switch", "Mic Capture Switch", 114621fdddeaSJames Courtier-Dutton "Mic Playback Volume", "Mic Capture Volume", 114721fdddeaSJames Courtier-Dutton "Line Playback Switch", "Line Capture Switch", 114821fdddeaSJames Courtier-Dutton "Line Playback Volume", "Line Capture Volume", 114921fdddeaSJames Courtier-Dutton "CD Playback Switch", "CD Capture Switch", 115021fdddeaSJames Courtier-Dutton "CD Playback Volume", "CD Capture Volume", 115121fdddeaSJames Courtier-Dutton "Aux Playback Switch", "Aux Capture Switch", 115221fdddeaSJames Courtier-Dutton "Aux Playback Volume", "Aux Capture Volume", 115321fdddeaSJames Courtier-Dutton "Video Playback Switch", "Video Capture Switch", 115421fdddeaSJames Courtier-Dutton "Video Playback Volume", "Video Capture Volume", 115521fdddeaSJames Courtier-Dutton 115621fdddeaSJames Courtier-Dutton NULL 115721fdddeaSJames Courtier-Dutton }; 11581da177e4SLinus Torvalds 11592b637da5SLee Revell if (emu->card_capabilities->ac97_chip) { 1160eb4698f3STakashi Iwai struct snd_ac97_bus *pbus; 1161eb4698f3STakashi Iwai struct snd_ac97_template ac97; 1162eb4698f3STakashi Iwai static struct snd_ac97_bus_ops ops = { 11631da177e4SLinus Torvalds .write = snd_emu10k1_ac97_write, 11641da177e4SLinus Torvalds .read = snd_emu10k1_ac97_read, 11651da177e4SLinus Torvalds }; 11661da177e4SLinus Torvalds 1167b1508693STakashi Iwai if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0) 11681da177e4SLinus Torvalds return err; 11691da177e4SLinus Torvalds pbus->no_vra = 1; /* we don't need VRA */ 11701da177e4SLinus Torvalds 11711da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97)); 11721da177e4SLinus Torvalds ac97.private_data = emu; 11731da177e4SLinus Torvalds ac97.private_free = snd_emu10k1_mixer_free_ac97; 11741da177e4SLinus Torvalds ac97.scaps = AC97_SCAP_NO_SPDIF; 1175b1508693STakashi Iwai if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) { 1176b1508693STakashi Iwai if (emu->card_capabilities->ac97_chip == 1) 11771da177e4SLinus Torvalds return err; 1178b1508693STakashi Iwai snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n"); 1179b1508693STakashi Iwai snd_printd(KERN_INFO" Proceeding without ac97 mixers...\n"); 1180b1508693STakashi Iwai snd_device_free(emu->card, pbus); 1181b1508693STakashi Iwai goto no_ac97; /* FIXME: get rid of ugly gotos.. */ 1182b1508693STakashi Iwai } 11831da177e4SLinus Torvalds if (emu->audigy) { 11841da177e4SLinus Torvalds /* set master volume to 0 dB */ 11854d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); 11861da177e4SLinus Torvalds /* set capture source to mic */ 11874d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); 118821fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 118921fdddeaSJames Courtier-Dutton c = audigy_remove_ctls_1361t_adc; 119021fdddeaSJames Courtier-Dutton else 11911da177e4SLinus Torvalds c = audigy_remove_ctls; 11921da177e4SLinus Torvalds } else { 11931da177e4SLinus Torvalds /* 11941da177e4SLinus Torvalds * Credits for cards based on STAC9758: 11951da177e4SLinus Torvalds * James Courtier-Dutton <James@superbug.demon.co.uk> 11961da177e4SLinus Torvalds * Voluspa <voluspa@comhem.se> 11971da177e4SLinus Torvalds */ 11981da177e4SLinus Torvalds if (emu->ac97->id == AC97_ID_STAC9758) { 11991da177e4SLinus Torvalds emu->rear_ac97 = 1; 12001da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); 12011da177e4SLinus Torvalds } 12021da177e4SLinus Torvalds /* remove unused AC97 controls */ 12034d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); 12044d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); 12051da177e4SLinus Torvalds c = emu10k1_remove_ctls; 12061da177e4SLinus Torvalds } 12071da177e4SLinus Torvalds for (; *c; c++) 12081da177e4SLinus Torvalds remove_ctl(card, *c); 12091da177e4SLinus Torvalds } else { 1210f12aa40cSTakashi Iwai no_ac97: 12112b637da5SLee Revell if (emu->card_capabilities->ecard) 12121da177e4SLinus Torvalds strcpy(emu->card->mixername, "EMU APS"); 12131da177e4SLinus Torvalds else if (emu->audigy) 12141da177e4SLinus Torvalds strcpy(emu->card->mixername, "SB Audigy"); 12151da177e4SLinus Torvalds else 12161da177e4SLinus Torvalds strcpy(emu->card->mixername, "Emu10k1"); 12171da177e4SLinus Torvalds } 12181da177e4SLinus Torvalds 12191da177e4SLinus Torvalds if (emu->audigy) 122021fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 122121fdddeaSJames Courtier-Dutton c = audigy_rename_ctls_1361t_adc; 122221fdddeaSJames Courtier-Dutton else 12231da177e4SLinus Torvalds c = audigy_rename_ctls; 12241da177e4SLinus Torvalds else 12251da177e4SLinus Torvalds c = emu10k1_rename_ctls; 12261da177e4SLinus Torvalds for (; *c; c += 2) 12271da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 122821fdddeaSJames Courtier-Dutton 1229e3b9bc0eSJames Courtier-Dutton if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ 1230e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); 1231e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); 1232e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); 1233e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); 1234e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "Headphone Playback Switch"); 1235e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "Headphone Playback Volume"); 1236e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "3D Control - Center"); 1237e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "3D Control - Depth"); 1238e3b9bc0eSJames Courtier-Dutton remove_ctl(card, "3D Control - Switch"); 1239e3b9bc0eSJames Courtier-Dutton } 12401da177e4SLinus Torvalds if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) 12411da177e4SLinus Torvalds return -ENOMEM; 124267ed4161SClemens Ladisch kctl->id.device = pcm_device; 12431da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 12441da177e4SLinus Torvalds return err; 12451da177e4SLinus Torvalds if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL) 12461da177e4SLinus Torvalds return -ENOMEM; 124767ed4161SClemens Ladisch kctl->id.device = pcm_device; 12481da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 12491da177e4SLinus Torvalds return err; 12501da177e4SLinus Torvalds if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL) 12511da177e4SLinus Torvalds return -ENOMEM; 125267ed4161SClemens Ladisch kctl->id.device = pcm_device; 12531da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 12541da177e4SLinus Torvalds return err; 12551da177e4SLinus Torvalds 12561da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL) 12571da177e4SLinus Torvalds return -ENOMEM; 125867ed4161SClemens Ladisch kctl->id.device = multi_device; 12591da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 12601da177e4SLinus Torvalds return err; 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL) 12631da177e4SLinus Torvalds return -ENOMEM; 126467ed4161SClemens Ladisch kctl->id.device = multi_device; 12651da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 12661da177e4SLinus Torvalds return err; 12671da177e4SLinus Torvalds 12681da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL) 12691da177e4SLinus Torvalds return -ENOMEM; 127067ed4161SClemens Ladisch kctl->id.device = multi_device; 12711da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 12721da177e4SLinus Torvalds return err; 12731da177e4SLinus Torvalds 12741da177e4SLinus Torvalds /* initialize the routing and volume table for each pcm playback stream */ 12751da177e4SLinus Torvalds for (pcm = 0; pcm < 32; pcm++) { 1276eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 12771da177e4SLinus Torvalds int v; 12781da177e4SLinus Torvalds 12791da177e4SLinus Torvalds mix = &emu->pcm_mixer[pcm]; 12801da177e4SLinus Torvalds mix->epcm = NULL; 12811da177e4SLinus Torvalds 12821da177e4SLinus Torvalds for (v = 0; v < 4; v++) 12831da177e4SLinus Torvalds mix->send_routing[0][v] = 12841da177e4SLinus Torvalds mix->send_routing[1][v] = 12851da177e4SLinus Torvalds mix->send_routing[2][v] = v; 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 12881da177e4SLinus Torvalds mix->send_volume[0][0] = mix->send_volume[0][1] = 12891da177e4SLinus Torvalds mix->send_volume[1][0] = mix->send_volume[2][1] = 255; 12901da177e4SLinus Torvalds 12911da177e4SLinus Torvalds mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; 12921da177e4SLinus Torvalds } 12931da177e4SLinus Torvalds 12941da177e4SLinus Torvalds /* initialize the routing and volume table for the multichannel playback stream */ 12951da177e4SLinus Torvalds for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) { 1296eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 12971da177e4SLinus Torvalds int v; 12981da177e4SLinus Torvalds 12991da177e4SLinus Torvalds mix = &emu->efx_pcm_mixer[pcm]; 13001da177e4SLinus Torvalds mix->epcm = NULL; 13011da177e4SLinus Torvalds 13021da177e4SLinus Torvalds mix->send_routing[0][0] = pcm; 13031da177e4SLinus Torvalds mix->send_routing[0][1] = (pcm == 0) ? 1 : 0; 13041da177e4SLinus Torvalds for (v = 0; v < 2; v++) 13051da177e4SLinus Torvalds mix->send_routing[0][2+v] = 13+v; 13061da177e4SLinus Torvalds if (emu->audigy) 13071da177e4SLinus Torvalds for (v = 0; v < 4; v++) 13081da177e4SLinus Torvalds mix->send_routing[0][4+v] = 60+v; 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 13111da177e4SLinus Torvalds mix->send_volume[0][0] = 255; 13121da177e4SLinus Torvalds 13131da177e4SLinus Torvalds mix->attn[0] = 0xffff; 13141da177e4SLinus Torvalds } 13151da177e4SLinus Torvalds 13162b637da5SLee Revell if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */ 13171da177e4SLinus Torvalds /* sb live! and audigy */ 13181da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) 13191da177e4SLinus Torvalds return -ENOMEM; 13205549d549SClemens Ladisch if (!emu->audigy) 13215549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 13221da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 13231da177e4SLinus Torvalds return err; 13241da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) 13251da177e4SLinus Torvalds return -ENOMEM; 13265549d549SClemens Ladisch if (!emu->audigy) 13275549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 13281da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 13291da177e4SLinus Torvalds return err; 13301da177e4SLinus Torvalds } 13311da177e4SLinus Torvalds 1332*9f4bd5ddSJames Courtier-Dutton if ( emu->card_capabilities->emu1010) { 133319b99fbaSJames Courtier-Dutton ; /* Disable the snd_audigy_spdif_shared_spdif */ 133419b99fbaSJames Courtier-Dutton } else if (emu->audigy) { 13351da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) 13361da177e4SLinus Torvalds return -ENOMEM; 13371da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 13381da177e4SLinus Torvalds return err; 1339001f7589SJames Courtier-Dutton #if 0 13401da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) 13411da177e4SLinus Torvalds return -ENOMEM; 13421da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 13431da177e4SLinus Torvalds return err; 1344001f7589SJames Courtier-Dutton #endif 13452b637da5SLee Revell } else if (! emu->card_capabilities->ecard) { 13461da177e4SLinus Torvalds /* sb live! */ 13471da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) 13481da177e4SLinus Torvalds return -ENOMEM; 13491da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 13501da177e4SLinus Torvalds return err; 13511da177e4SLinus Torvalds } 13522b637da5SLee Revell if (emu->card_capabilities->ca0151_chip) { /* P16V */ 13531da177e4SLinus Torvalds if ((err = snd_p16v_mixer(emu))) 13541da177e4SLinus Torvalds return err; 13551da177e4SLinus Torvalds } 13561da177e4SLinus Torvalds 1357*9f4bd5ddSJames Courtier-Dutton if ( emu->card_capabilities->emu1010) { 1358*9f4bd5ddSJames Courtier-Dutton int i; 1359*9f4bd5ddSJames Courtier-Dutton 1360*9f4bd5ddSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { 1361*9f4bd5ddSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu)); 1362*9f4bd5ddSJames Courtier-Dutton if (err < 0) 1363*9f4bd5ddSJames Courtier-Dutton return err; 1364*9f4bd5ddSJames Courtier-Dutton } 1365*9f4bd5ddSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { 1366*9f4bd5ddSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu)); 1367*9f4bd5ddSJames Courtier-Dutton if (err < 0) 1368*9f4bd5ddSJames Courtier-Dutton return err; 1369*9f4bd5ddSJames Courtier-Dutton } 1370*9f4bd5ddSJames Courtier-Dutton } 1371*9f4bd5ddSJames Courtier-Dutton 13721da177e4SLinus Torvalds return 0; 13731da177e4SLinus Torvalds } 1374