1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * Copyright (c) by Jaroslav Kysela <perex@suse.cz>, 3*1da177e4SLinus Torvalds * Takashi Iwai <tiwai@suse.de> 4*1da177e4SLinus Torvalds * Creative Labs, Inc. 5*1da177e4SLinus Torvalds * Routines for control of EMU10K1 chips / mixer routines 6*1da177e4SLinus Torvalds * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * BUGS: 9*1da177e4SLinus Torvalds * -- 10*1da177e4SLinus Torvalds * 11*1da177e4SLinus Torvalds * TODO: 12*1da177e4SLinus Torvalds * -- 13*1da177e4SLinus Torvalds * 14*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 15*1da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 16*1da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 17*1da177e4SLinus Torvalds * (at your option) any later version. 18*1da177e4SLinus Torvalds * 19*1da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 20*1da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 21*1da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22*1da177e4SLinus Torvalds * GNU General Public License for more details. 23*1da177e4SLinus Torvalds * 24*1da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 25*1da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 26*1da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 27*1da177e4SLinus Torvalds * 28*1da177e4SLinus Torvalds */ 29*1da177e4SLinus Torvalds 30*1da177e4SLinus Torvalds #include <sound/driver.h> 31*1da177e4SLinus Torvalds #include <linux/time.h> 32*1da177e4SLinus Torvalds #include <linux/init.h> 33*1da177e4SLinus Torvalds #include <sound/core.h> 34*1da177e4SLinus Torvalds #include <sound/emu10k1.h> 35*1da177e4SLinus Torvalds 36*1da177e4SLinus Torvalds #define AC97_ID_STAC9758 0x83847658 37*1da177e4SLinus Torvalds 38*1da177e4SLinus Torvalds static int snd_emu10k1_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 39*1da177e4SLinus Torvalds { 40*1da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 41*1da177e4SLinus Torvalds uinfo->count = 1; 42*1da177e4SLinus Torvalds return 0; 43*1da177e4SLinus Torvalds } 44*1da177e4SLinus Torvalds 45*1da177e4SLinus Torvalds static int snd_emu10k1_spdif_get(snd_kcontrol_t * kcontrol, 46*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 47*1da177e4SLinus Torvalds { 48*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 49*1da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 50*1da177e4SLinus Torvalds unsigned long flags; 51*1da177e4SLinus Torvalds 52*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 53*1da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 54*1da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 55*1da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 56*1da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 57*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 58*1da177e4SLinus Torvalds return 0; 59*1da177e4SLinus Torvalds } 60*1da177e4SLinus Torvalds 61*1da177e4SLinus Torvalds static int snd_emu10k1_spdif_get_mask(snd_kcontrol_t * kcontrol, 62*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 63*1da177e4SLinus Torvalds { 64*1da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = 0xff; 65*1da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = 0xff; 66*1da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = 0xff; 67*1da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = 0xff; 68*1da177e4SLinus Torvalds return 0; 69*1da177e4SLinus Torvalds } 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds static int snd_audigy_spdif_output_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 72*1da177e4SLinus Torvalds { 73*1da177e4SLinus Torvalds static char *texts[] = {"44100", "48000", "96000"}; 74*1da177e4SLinus Torvalds 75*1da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 76*1da177e4SLinus Torvalds uinfo->count = 1; 77*1da177e4SLinus Torvalds uinfo->value.enumerated.items = 3; 78*1da177e4SLinus Torvalds if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 79*1da177e4SLinus Torvalds uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 80*1da177e4SLinus Torvalds strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 81*1da177e4SLinus Torvalds return 0; 82*1da177e4SLinus Torvalds } 83*1da177e4SLinus Torvalds 84*1da177e4SLinus Torvalds static int snd_audigy_spdif_output_rate_get(snd_kcontrol_t * kcontrol, 85*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 86*1da177e4SLinus Torvalds { 87*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 88*1da177e4SLinus Torvalds unsigned int tmp; 89*1da177e4SLinus Torvalds unsigned long flags; 90*1da177e4SLinus Torvalds 91*1da177e4SLinus Torvalds 92*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 93*1da177e4SLinus Torvalds tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 94*1da177e4SLinus Torvalds switch (tmp & A_SPDIF_RATE_MASK) { 95*1da177e4SLinus Torvalds case A_SPDIF_44100: 96*1da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 97*1da177e4SLinus Torvalds break; 98*1da177e4SLinus Torvalds case A_SPDIF_48000: 99*1da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 100*1da177e4SLinus Torvalds break; 101*1da177e4SLinus Torvalds case A_SPDIF_96000: 102*1da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 103*1da177e4SLinus Torvalds break; 104*1da177e4SLinus Torvalds default: 105*1da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 106*1da177e4SLinus Torvalds } 107*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 108*1da177e4SLinus Torvalds return 0; 109*1da177e4SLinus Torvalds } 110*1da177e4SLinus Torvalds 111*1da177e4SLinus Torvalds static int snd_audigy_spdif_output_rate_put(snd_kcontrol_t * kcontrol, 112*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 113*1da177e4SLinus Torvalds { 114*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 115*1da177e4SLinus Torvalds int change; 116*1da177e4SLinus Torvalds unsigned int reg, val, tmp; 117*1da177e4SLinus Torvalds unsigned long flags; 118*1da177e4SLinus Torvalds 119*1da177e4SLinus Torvalds switch(ucontrol->value.enumerated.item[0]) { 120*1da177e4SLinus Torvalds case 0: 121*1da177e4SLinus Torvalds val = A_SPDIF_44100; 122*1da177e4SLinus Torvalds break; 123*1da177e4SLinus Torvalds case 1: 124*1da177e4SLinus Torvalds val = A_SPDIF_48000; 125*1da177e4SLinus Torvalds break; 126*1da177e4SLinus Torvalds case 2: 127*1da177e4SLinus Torvalds val = A_SPDIF_96000; 128*1da177e4SLinus Torvalds break; 129*1da177e4SLinus Torvalds default: 130*1da177e4SLinus Torvalds val = A_SPDIF_48000; 131*1da177e4SLinus Torvalds break; 132*1da177e4SLinus Torvalds } 133*1da177e4SLinus Torvalds 134*1da177e4SLinus Torvalds 135*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 136*1da177e4SLinus Torvalds reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 137*1da177e4SLinus Torvalds tmp = reg & ~A_SPDIF_RATE_MASK; 138*1da177e4SLinus Torvalds tmp |= val; 139*1da177e4SLinus Torvalds if ((change = (tmp != reg))) 140*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); 141*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 142*1da177e4SLinus Torvalds return change; 143*1da177e4SLinus Torvalds } 144*1da177e4SLinus Torvalds 145*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_audigy_spdif_output_rate = 146*1da177e4SLinus Torvalds { 147*1da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 148*1da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 149*1da177e4SLinus Torvalds .name = "Audigy SPDIF Output Sample Rate", 150*1da177e4SLinus Torvalds .count = 1, 151*1da177e4SLinus Torvalds .info = snd_audigy_spdif_output_rate_info, 152*1da177e4SLinus Torvalds .get = snd_audigy_spdif_output_rate_get, 153*1da177e4SLinus Torvalds .put = snd_audigy_spdif_output_rate_put 154*1da177e4SLinus Torvalds }; 155*1da177e4SLinus Torvalds 156*1da177e4SLinus Torvalds static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol, 157*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 158*1da177e4SLinus Torvalds { 159*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 160*1da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 161*1da177e4SLinus Torvalds int change; 162*1da177e4SLinus Torvalds unsigned int val; 163*1da177e4SLinus Torvalds unsigned long flags; 164*1da177e4SLinus Torvalds 165*1da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 166*1da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 167*1da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 168*1da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 169*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 170*1da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 171*1da177e4SLinus Torvalds if (change) { 172*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); 173*1da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 174*1da177e4SLinus Torvalds } 175*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 176*1da177e4SLinus Torvalds return change; 177*1da177e4SLinus Torvalds } 178*1da177e4SLinus Torvalds 179*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control = 180*1da177e4SLinus Torvalds { 181*1da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 182*1da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 183*1da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 184*1da177e4SLinus Torvalds .count = 4, 185*1da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 186*1da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get_mask 187*1da177e4SLinus Torvalds }; 188*1da177e4SLinus Torvalds 189*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_spdif_control = 190*1da177e4SLinus Torvalds { 191*1da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 192*1da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 193*1da177e4SLinus Torvalds .count = 4, 194*1da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 195*1da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get, 196*1da177e4SLinus Torvalds .put = snd_emu10k1_spdif_put 197*1da177e4SLinus Torvalds }; 198*1da177e4SLinus Torvalds 199*1da177e4SLinus Torvalds 200*1da177e4SLinus Torvalds static void update_emu10k1_fxrt(emu10k1_t *emu, int voice, unsigned char *route) 201*1da177e4SLinus Torvalds { 202*1da177e4SLinus Torvalds if (emu->audigy) { 203*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT1, voice, 204*1da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt1(route)); 205*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 206*1da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt2(route)); 207*1da177e4SLinus Torvalds } else { 208*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXRT, voice, 209*1da177e4SLinus Torvalds snd_emu10k1_compose_send_routing(route)); 210*1da177e4SLinus Torvalds } 211*1da177e4SLinus Torvalds } 212*1da177e4SLinus Torvalds 213*1da177e4SLinus Torvalds static void update_emu10k1_send_volume(emu10k1_t *emu, int voice, unsigned char *volume) 214*1da177e4SLinus Torvalds { 215*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); 216*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); 217*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); 218*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); 219*1da177e4SLinus Torvalds if (emu->audigy) { 220*1da177e4SLinus Torvalds unsigned int val = ((unsigned int)volume[4] << 24) | 221*1da177e4SLinus Torvalds ((unsigned int)volume[5] << 16) | 222*1da177e4SLinus Torvalds ((unsigned int)volume[6] << 8) | 223*1da177e4SLinus Torvalds (unsigned int)volume[7]; 224*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val); 225*1da177e4SLinus Torvalds } 226*1da177e4SLinus Torvalds } 227*1da177e4SLinus Torvalds 228*1da177e4SLinus Torvalds /* PCM stream controls */ 229*1da177e4SLinus Torvalds 230*1da177e4SLinus Torvalds static int snd_emu10k1_send_routing_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 231*1da177e4SLinus Torvalds { 232*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 233*1da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 234*1da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 235*1da177e4SLinus Torvalds uinfo->value.integer.min = 0; 236*1da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 237*1da177e4SLinus Torvalds return 0; 238*1da177e4SLinus Torvalds } 239*1da177e4SLinus Torvalds 240*1da177e4SLinus Torvalds static int snd_emu10k1_send_routing_get(snd_kcontrol_t * kcontrol, 241*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 242*1da177e4SLinus Torvalds { 243*1da177e4SLinus Torvalds unsigned long flags; 244*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 245*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 246*1da177e4SLinus Torvalds int voice, idx; 247*1da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 248*1da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 249*1da177e4SLinus Torvalds 250*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 251*1da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 252*1da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 253*1da177e4SLinus Torvalds ucontrol->value.integer.value[(voice * num_efx) + idx] = 254*1da177e4SLinus Torvalds mix->send_routing[voice][idx] & mask; 255*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 256*1da177e4SLinus Torvalds return 0; 257*1da177e4SLinus Torvalds } 258*1da177e4SLinus Torvalds 259*1da177e4SLinus Torvalds static int snd_emu10k1_send_routing_put(snd_kcontrol_t * kcontrol, 260*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 261*1da177e4SLinus Torvalds { 262*1da177e4SLinus Torvalds unsigned long flags; 263*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 264*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 265*1da177e4SLinus Torvalds int change = 0, voice, idx, val; 266*1da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 267*1da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 268*1da177e4SLinus Torvalds 269*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 270*1da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 271*1da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 272*1da177e4SLinus Torvalds val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; 273*1da177e4SLinus Torvalds if (mix->send_routing[voice][idx] != val) { 274*1da177e4SLinus Torvalds mix->send_routing[voice][idx] = val; 275*1da177e4SLinus Torvalds change = 1; 276*1da177e4SLinus Torvalds } 277*1da177e4SLinus Torvalds } 278*1da177e4SLinus Torvalds if (change && mix->epcm) { 279*1da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 280*1da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 281*1da177e4SLinus Torvalds &mix->send_routing[1][0]); 282*1da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, 283*1da177e4SLinus Torvalds &mix->send_routing[2][0]); 284*1da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 285*1da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 286*1da177e4SLinus Torvalds &mix->send_routing[0][0]); 287*1da177e4SLinus Torvalds } 288*1da177e4SLinus Torvalds } 289*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 290*1da177e4SLinus Torvalds return change; 291*1da177e4SLinus Torvalds } 292*1da177e4SLinus Torvalds 293*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_send_routing_control = 294*1da177e4SLinus Torvalds { 295*1da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 296*1da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 297*1da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Routing", 298*1da177e4SLinus Torvalds .count = 32, 299*1da177e4SLinus Torvalds .info = snd_emu10k1_send_routing_info, 300*1da177e4SLinus Torvalds .get = snd_emu10k1_send_routing_get, 301*1da177e4SLinus Torvalds .put = snd_emu10k1_send_routing_put 302*1da177e4SLinus Torvalds }; 303*1da177e4SLinus Torvalds 304*1da177e4SLinus Torvalds static int snd_emu10k1_send_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 305*1da177e4SLinus Torvalds { 306*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 307*1da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 308*1da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 309*1da177e4SLinus Torvalds uinfo->value.integer.min = 0; 310*1da177e4SLinus Torvalds uinfo->value.integer.max = 255; 311*1da177e4SLinus Torvalds return 0; 312*1da177e4SLinus Torvalds } 313*1da177e4SLinus Torvalds 314*1da177e4SLinus Torvalds static int snd_emu10k1_send_volume_get(snd_kcontrol_t * kcontrol, 315*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 316*1da177e4SLinus Torvalds { 317*1da177e4SLinus Torvalds unsigned long flags; 318*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 319*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 320*1da177e4SLinus Torvalds int idx; 321*1da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 322*1da177e4SLinus Torvalds 323*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 324*1da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) 325*1da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; 326*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 327*1da177e4SLinus Torvalds return 0; 328*1da177e4SLinus Torvalds } 329*1da177e4SLinus Torvalds 330*1da177e4SLinus Torvalds static int snd_emu10k1_send_volume_put(snd_kcontrol_t * kcontrol, 331*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 332*1da177e4SLinus Torvalds { 333*1da177e4SLinus Torvalds unsigned long flags; 334*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 335*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 336*1da177e4SLinus Torvalds int change = 0, idx, val; 337*1da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 338*1da177e4SLinus Torvalds 339*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 340*1da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) { 341*1da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 342*1da177e4SLinus Torvalds if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { 343*1da177e4SLinus Torvalds mix->send_volume[idx/num_efx][idx%num_efx] = val; 344*1da177e4SLinus Torvalds change = 1; 345*1da177e4SLinus Torvalds } 346*1da177e4SLinus Torvalds } 347*1da177e4SLinus Torvalds if (change && mix->epcm) { 348*1da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 349*1da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 350*1da177e4SLinus Torvalds &mix->send_volume[1][0]); 351*1da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, 352*1da177e4SLinus Torvalds &mix->send_volume[2][0]); 353*1da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 354*1da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 355*1da177e4SLinus Torvalds &mix->send_volume[0][0]); 356*1da177e4SLinus Torvalds } 357*1da177e4SLinus Torvalds } 358*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 359*1da177e4SLinus Torvalds return change; 360*1da177e4SLinus Torvalds } 361*1da177e4SLinus Torvalds 362*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_send_volume_control = 363*1da177e4SLinus Torvalds { 364*1da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 365*1da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 366*1da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Volume", 367*1da177e4SLinus Torvalds .count = 32, 368*1da177e4SLinus Torvalds .info = snd_emu10k1_send_volume_info, 369*1da177e4SLinus Torvalds .get = snd_emu10k1_send_volume_get, 370*1da177e4SLinus Torvalds .put = snd_emu10k1_send_volume_put 371*1da177e4SLinus Torvalds }; 372*1da177e4SLinus Torvalds 373*1da177e4SLinus Torvalds static int snd_emu10k1_attn_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 374*1da177e4SLinus Torvalds { 375*1da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 376*1da177e4SLinus Torvalds uinfo->count = 3; 377*1da177e4SLinus Torvalds uinfo->value.integer.min = 0; 378*1da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 379*1da177e4SLinus Torvalds return 0; 380*1da177e4SLinus Torvalds } 381*1da177e4SLinus Torvalds 382*1da177e4SLinus Torvalds static int snd_emu10k1_attn_get(snd_kcontrol_t * kcontrol, 383*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 384*1da177e4SLinus Torvalds { 385*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 386*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 387*1da177e4SLinus Torvalds unsigned long flags; 388*1da177e4SLinus Torvalds int idx; 389*1da177e4SLinus Torvalds 390*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 391*1da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) 392*1da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->attn[idx]; 393*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 394*1da177e4SLinus Torvalds return 0; 395*1da177e4SLinus Torvalds } 396*1da177e4SLinus Torvalds 397*1da177e4SLinus Torvalds static int snd_emu10k1_attn_put(snd_kcontrol_t * kcontrol, 398*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 399*1da177e4SLinus Torvalds { 400*1da177e4SLinus Torvalds unsigned long flags; 401*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 402*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 403*1da177e4SLinus Torvalds int change = 0, idx, val; 404*1da177e4SLinus Torvalds 405*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 406*1da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) { 407*1da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 0xffff; 408*1da177e4SLinus Torvalds if (mix->attn[idx] != val) { 409*1da177e4SLinus Torvalds mix->attn[idx] = val; 410*1da177e4SLinus Torvalds change = 1; 411*1da177e4SLinus Torvalds } 412*1da177e4SLinus Torvalds } 413*1da177e4SLinus Torvalds if (change && mix->epcm) { 414*1da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 415*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); 416*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); 417*1da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 418*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); 419*1da177e4SLinus Torvalds } 420*1da177e4SLinus Torvalds } 421*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 422*1da177e4SLinus Torvalds return change; 423*1da177e4SLinus Torvalds } 424*1da177e4SLinus Torvalds 425*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_attn_control = 426*1da177e4SLinus Torvalds { 427*1da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 428*1da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 429*1da177e4SLinus Torvalds .name = "EMU10K1 PCM Volume", 430*1da177e4SLinus Torvalds .count = 32, 431*1da177e4SLinus Torvalds .info = snd_emu10k1_attn_info, 432*1da177e4SLinus Torvalds .get = snd_emu10k1_attn_get, 433*1da177e4SLinus Torvalds .put = snd_emu10k1_attn_put 434*1da177e4SLinus Torvalds }; 435*1da177e4SLinus Torvalds 436*1da177e4SLinus Torvalds /* Mutichannel PCM stream controls */ 437*1da177e4SLinus Torvalds 438*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_routing_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 439*1da177e4SLinus Torvalds { 440*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 441*1da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 442*1da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 443*1da177e4SLinus Torvalds uinfo->value.integer.min = 0; 444*1da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 445*1da177e4SLinus Torvalds return 0; 446*1da177e4SLinus Torvalds } 447*1da177e4SLinus Torvalds 448*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_routing_get(snd_kcontrol_t * kcontrol, 449*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 450*1da177e4SLinus Torvalds { 451*1da177e4SLinus Torvalds unsigned long flags; 452*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 453*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 454*1da177e4SLinus Torvalds int idx; 455*1da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 456*1da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 457*1da177e4SLinus Torvalds 458*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 459*1da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 460*1da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = 461*1da177e4SLinus Torvalds mix->send_routing[0][idx] & mask; 462*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 463*1da177e4SLinus Torvalds return 0; 464*1da177e4SLinus Torvalds } 465*1da177e4SLinus Torvalds 466*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_routing_put(snd_kcontrol_t * kcontrol, 467*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 468*1da177e4SLinus Torvalds { 469*1da177e4SLinus Torvalds unsigned long flags; 470*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 471*1da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 472*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch]; 473*1da177e4SLinus Torvalds int change = 0, idx, val; 474*1da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 475*1da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 476*1da177e4SLinus Torvalds 477*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 478*1da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 479*1da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & mask; 480*1da177e4SLinus Torvalds if (mix->send_routing[0][idx] != val) { 481*1da177e4SLinus Torvalds mix->send_routing[0][idx] = val; 482*1da177e4SLinus Torvalds change = 1; 483*1da177e4SLinus Torvalds } 484*1da177e4SLinus Torvalds } 485*1da177e4SLinus Torvalds 486*1da177e4SLinus Torvalds if (change && mix->epcm) { 487*1da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 488*1da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, 489*1da177e4SLinus Torvalds &mix->send_routing[0][0]); 490*1da177e4SLinus Torvalds } 491*1da177e4SLinus Torvalds } 492*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 493*1da177e4SLinus Torvalds return change; 494*1da177e4SLinus Torvalds } 495*1da177e4SLinus Torvalds 496*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_efx_send_routing_control = 497*1da177e4SLinus Torvalds { 498*1da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 499*1da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 500*1da177e4SLinus Torvalds .name = "Multichannel PCM Send Routing", 501*1da177e4SLinus Torvalds .count = 16, 502*1da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_routing_info, 503*1da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_routing_get, 504*1da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_routing_put 505*1da177e4SLinus Torvalds }; 506*1da177e4SLinus Torvalds 507*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 508*1da177e4SLinus Torvalds { 509*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 510*1da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 511*1da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 512*1da177e4SLinus Torvalds uinfo->value.integer.min = 0; 513*1da177e4SLinus Torvalds uinfo->value.integer.max = 255; 514*1da177e4SLinus Torvalds return 0; 515*1da177e4SLinus Torvalds } 516*1da177e4SLinus Torvalds 517*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_volume_get(snd_kcontrol_t * kcontrol, 518*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 519*1da177e4SLinus Torvalds { 520*1da177e4SLinus Torvalds unsigned long flags; 521*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 522*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 523*1da177e4SLinus Torvalds int idx; 524*1da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 525*1da177e4SLinus Torvalds 526*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 527*1da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 528*1da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; 529*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 530*1da177e4SLinus Torvalds return 0; 531*1da177e4SLinus Torvalds } 532*1da177e4SLinus Torvalds 533*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_volume_put(snd_kcontrol_t * kcontrol, 534*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 535*1da177e4SLinus Torvalds { 536*1da177e4SLinus Torvalds unsigned long flags; 537*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 538*1da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 539*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch]; 540*1da177e4SLinus Torvalds int change = 0, idx, val; 541*1da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 542*1da177e4SLinus Torvalds 543*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 544*1da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 545*1da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 546*1da177e4SLinus Torvalds if (mix->send_volume[0][idx] != val) { 547*1da177e4SLinus Torvalds mix->send_volume[0][idx] = val; 548*1da177e4SLinus Torvalds change = 1; 549*1da177e4SLinus Torvalds } 550*1da177e4SLinus Torvalds } 551*1da177e4SLinus Torvalds if (change && mix->epcm) { 552*1da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 553*1da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, 554*1da177e4SLinus Torvalds &mix->send_volume[0][0]); 555*1da177e4SLinus Torvalds } 556*1da177e4SLinus Torvalds } 557*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 558*1da177e4SLinus Torvalds return change; 559*1da177e4SLinus Torvalds } 560*1da177e4SLinus Torvalds 561*1da177e4SLinus Torvalds 562*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_efx_send_volume_control = 563*1da177e4SLinus Torvalds { 564*1da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 565*1da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 566*1da177e4SLinus Torvalds .name = "Multichannel PCM Send Volume", 567*1da177e4SLinus Torvalds .count = 16, 568*1da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_volume_info, 569*1da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_volume_get, 570*1da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_volume_put 571*1da177e4SLinus Torvalds }; 572*1da177e4SLinus Torvalds 573*1da177e4SLinus Torvalds static int snd_emu10k1_efx_attn_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 574*1da177e4SLinus Torvalds { 575*1da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 576*1da177e4SLinus Torvalds uinfo->count = 1; 577*1da177e4SLinus Torvalds uinfo->value.integer.min = 0; 578*1da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 579*1da177e4SLinus Torvalds return 0; 580*1da177e4SLinus Torvalds } 581*1da177e4SLinus Torvalds 582*1da177e4SLinus Torvalds static int snd_emu10k1_efx_attn_get(snd_kcontrol_t * kcontrol, 583*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 584*1da177e4SLinus Torvalds { 585*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 586*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 587*1da177e4SLinus Torvalds unsigned long flags; 588*1da177e4SLinus Torvalds 589*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 590*1da177e4SLinus Torvalds ucontrol->value.integer.value[0] = mix->attn[0]; 591*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 592*1da177e4SLinus Torvalds return 0; 593*1da177e4SLinus Torvalds } 594*1da177e4SLinus Torvalds 595*1da177e4SLinus Torvalds static int snd_emu10k1_efx_attn_put(snd_kcontrol_t * kcontrol, 596*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 597*1da177e4SLinus Torvalds { 598*1da177e4SLinus Torvalds unsigned long flags; 599*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 600*1da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 601*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch]; 602*1da177e4SLinus Torvalds int change = 0, val; 603*1da177e4SLinus Torvalds 604*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 605*1da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] & 0xffff; 606*1da177e4SLinus Torvalds if (mix->attn[0] != val) { 607*1da177e4SLinus Torvalds mix->attn[0] = val; 608*1da177e4SLinus Torvalds change = 1; 609*1da177e4SLinus Torvalds } 610*1da177e4SLinus Torvalds if (change && mix->epcm) { 611*1da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 612*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); 613*1da177e4SLinus Torvalds } 614*1da177e4SLinus Torvalds } 615*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 616*1da177e4SLinus Torvalds return change; 617*1da177e4SLinus Torvalds } 618*1da177e4SLinus Torvalds 619*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_efx_attn_control = 620*1da177e4SLinus Torvalds { 621*1da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 622*1da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 623*1da177e4SLinus Torvalds .name = "Multichannel PCM Volume", 624*1da177e4SLinus Torvalds .count = 16, 625*1da177e4SLinus Torvalds .info = snd_emu10k1_efx_attn_info, 626*1da177e4SLinus Torvalds .get = snd_emu10k1_efx_attn_get, 627*1da177e4SLinus Torvalds .put = snd_emu10k1_efx_attn_put 628*1da177e4SLinus Torvalds }; 629*1da177e4SLinus Torvalds 630*1da177e4SLinus Torvalds static int snd_emu10k1_shared_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 631*1da177e4SLinus Torvalds { 632*1da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 633*1da177e4SLinus Torvalds uinfo->count = 1; 634*1da177e4SLinus Torvalds uinfo->value.integer.min = 0; 635*1da177e4SLinus Torvalds uinfo->value.integer.max = 1; 636*1da177e4SLinus Torvalds return 0; 637*1da177e4SLinus Torvalds } 638*1da177e4SLinus Torvalds 639*1da177e4SLinus Torvalds static int snd_emu10k1_shared_spdif_get(snd_kcontrol_t * kcontrol, 640*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 641*1da177e4SLinus Torvalds { 642*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 643*1da177e4SLinus Torvalds 644*1da177e4SLinus Torvalds if (emu->audigy) 645*1da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; 646*1da177e4SLinus Torvalds else 647*1da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; 648*1da177e4SLinus Torvalds return 0; 649*1da177e4SLinus Torvalds } 650*1da177e4SLinus Torvalds 651*1da177e4SLinus Torvalds static int snd_emu10k1_shared_spdif_put(snd_kcontrol_t * kcontrol, 652*1da177e4SLinus Torvalds snd_ctl_elem_value_t * ucontrol) 653*1da177e4SLinus Torvalds { 654*1da177e4SLinus Torvalds unsigned long flags; 655*1da177e4SLinus Torvalds emu10k1_t *emu = snd_kcontrol_chip(kcontrol); 656*1da177e4SLinus Torvalds unsigned int reg, val; 657*1da177e4SLinus Torvalds int change = 0; 658*1da177e4SLinus Torvalds 659*1da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 660*1da177e4SLinus Torvalds if (emu->audigy) { 661*1da177e4SLinus Torvalds reg = inl(emu->port + A_IOCFG); 662*1da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; 663*1da177e4SLinus Torvalds change = (reg & A_IOCFG_GPOUT0) != val; 664*1da177e4SLinus Torvalds if (change) { 665*1da177e4SLinus Torvalds reg &= ~A_IOCFG_GPOUT0; 666*1da177e4SLinus Torvalds reg |= val; 667*1da177e4SLinus Torvalds outl(reg | val, emu->port + A_IOCFG); 668*1da177e4SLinus Torvalds } 669*1da177e4SLinus Torvalds } 670*1da177e4SLinus Torvalds reg = inl(emu->port + HCFG); 671*1da177e4SLinus Torvalds val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0; 672*1da177e4SLinus Torvalds change |= (reg & HCFG_GPOUT0) != val; 673*1da177e4SLinus Torvalds if (change) { 674*1da177e4SLinus Torvalds reg &= ~HCFG_GPOUT0; 675*1da177e4SLinus Torvalds reg |= val; 676*1da177e4SLinus Torvalds outl(reg | val, emu->port + HCFG); 677*1da177e4SLinus Torvalds } 678*1da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 679*1da177e4SLinus Torvalds return change; 680*1da177e4SLinus Torvalds } 681*1da177e4SLinus Torvalds 682*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_shared_spdif __devinitdata = 683*1da177e4SLinus Torvalds { 684*1da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 685*1da177e4SLinus Torvalds .name = "SB Live Analog/Digital Output Jack", 686*1da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 687*1da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 688*1da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 689*1da177e4SLinus Torvalds }; 690*1da177e4SLinus Torvalds 691*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_audigy_shared_spdif __devinitdata = 692*1da177e4SLinus Torvalds { 693*1da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 694*1da177e4SLinus Torvalds .name = "Audigy Analog/Digital Output Jack", 695*1da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 696*1da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 697*1da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 698*1da177e4SLinus Torvalds }; 699*1da177e4SLinus Torvalds 700*1da177e4SLinus Torvalds /* 701*1da177e4SLinus Torvalds */ 702*1da177e4SLinus Torvalds static void snd_emu10k1_mixer_free_ac97(ac97_t *ac97) 703*1da177e4SLinus Torvalds { 704*1da177e4SLinus Torvalds emu10k1_t *emu = ac97->private_data; 705*1da177e4SLinus Torvalds emu->ac97 = NULL; 706*1da177e4SLinus Torvalds } 707*1da177e4SLinus Torvalds 708*1da177e4SLinus Torvalds /* 709*1da177e4SLinus Torvalds */ 710*1da177e4SLinus Torvalds static int remove_ctl(snd_card_t *card, const char *name) 711*1da177e4SLinus Torvalds { 712*1da177e4SLinus Torvalds snd_ctl_elem_id_t id; 713*1da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 714*1da177e4SLinus Torvalds strcpy(id.name, name); 715*1da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 716*1da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 717*1da177e4SLinus Torvalds } 718*1da177e4SLinus Torvalds 719*1da177e4SLinus Torvalds static snd_kcontrol_t *ctl_find(snd_card_t *card, const char *name) 720*1da177e4SLinus Torvalds { 721*1da177e4SLinus Torvalds snd_ctl_elem_id_t sid; 722*1da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 723*1da177e4SLinus Torvalds strcpy(sid.name, name); 724*1da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 725*1da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 726*1da177e4SLinus Torvalds } 727*1da177e4SLinus Torvalds 728*1da177e4SLinus Torvalds static int rename_ctl(snd_card_t *card, const char *src, const char *dst) 729*1da177e4SLinus Torvalds { 730*1da177e4SLinus Torvalds snd_kcontrol_t *kctl = ctl_find(card, src); 731*1da177e4SLinus Torvalds if (kctl) { 732*1da177e4SLinus Torvalds strcpy(kctl->id.name, dst); 733*1da177e4SLinus Torvalds return 0; 734*1da177e4SLinus Torvalds } 735*1da177e4SLinus Torvalds return -ENOENT; 736*1da177e4SLinus Torvalds } 737*1da177e4SLinus Torvalds 738*1da177e4SLinus Torvalds int __devinit snd_emu10k1_mixer(emu10k1_t *emu) 739*1da177e4SLinus Torvalds { 740*1da177e4SLinus Torvalds int err, pcm; 741*1da177e4SLinus Torvalds snd_kcontrol_t *kctl; 742*1da177e4SLinus Torvalds snd_card_t *card = emu->card; 743*1da177e4SLinus Torvalds char **c; 744*1da177e4SLinus Torvalds static char *emu10k1_remove_ctls[] = { 745*1da177e4SLinus Torvalds /* no AC97 mono, surround, center/lfe */ 746*1da177e4SLinus Torvalds "Master Mono Playback Switch", 747*1da177e4SLinus Torvalds "Master Mono Playback Volume", 748*1da177e4SLinus Torvalds "PCM Out Path & Mute", 749*1da177e4SLinus Torvalds "Mono Output Select", 750*1da177e4SLinus Torvalds "Surround Playback Switch", 751*1da177e4SLinus Torvalds "Surround Playback Volume", 752*1da177e4SLinus Torvalds "Center Playback Switch", 753*1da177e4SLinus Torvalds "Center Playback Volume", 754*1da177e4SLinus Torvalds "LFE Playback Switch", 755*1da177e4SLinus Torvalds "LFE Playback Volume", 756*1da177e4SLinus Torvalds NULL 757*1da177e4SLinus Torvalds }; 758*1da177e4SLinus Torvalds static char *emu10k1_rename_ctls[] = { 759*1da177e4SLinus Torvalds "Surround Digital Playback Volume", "Surround Playback Volume", 760*1da177e4SLinus Torvalds "Center Digital Playback Volume", "Center Playback Volume", 761*1da177e4SLinus Torvalds "LFE Digital Playback Volume", "LFE Playback Volume", 762*1da177e4SLinus Torvalds NULL 763*1da177e4SLinus Torvalds }; 764*1da177e4SLinus Torvalds static char *audigy_remove_ctls[] = { 765*1da177e4SLinus Torvalds /* Master/PCM controls on ac97 of Audigy has no effect */ 766*1da177e4SLinus Torvalds "PCM Playback Switch", 767*1da177e4SLinus Torvalds "PCM Playback Volume", 768*1da177e4SLinus Torvalds "Master Mono Playback Switch", 769*1da177e4SLinus Torvalds "Master Mono Playback Volume", 770*1da177e4SLinus Torvalds "Master Playback Switch", 771*1da177e4SLinus Torvalds "Master Playback Volume", 772*1da177e4SLinus Torvalds "PCM Out Path & Mute", 773*1da177e4SLinus Torvalds "Mono Output Select", 774*1da177e4SLinus Torvalds /* remove unused AC97 capture controls */ 775*1da177e4SLinus Torvalds "Capture Source", 776*1da177e4SLinus Torvalds "Capture Switch", 777*1da177e4SLinus Torvalds "Capture Volume", 778*1da177e4SLinus Torvalds "Mic Select", 779*1da177e4SLinus Torvalds "Video Playback Switch", 780*1da177e4SLinus Torvalds "Video Playback Volume", 781*1da177e4SLinus Torvalds "Mic Playback Switch", 782*1da177e4SLinus Torvalds "Mic Playback Volume", 783*1da177e4SLinus Torvalds NULL 784*1da177e4SLinus Torvalds }; 785*1da177e4SLinus Torvalds static char *audigy_rename_ctls[] = { 786*1da177e4SLinus Torvalds /* use conventional names */ 787*1da177e4SLinus Torvalds "Wave Playback Volume", "PCM Playback Volume", 788*1da177e4SLinus Torvalds /* "Wave Capture Volume", "PCM Capture Volume", */ 789*1da177e4SLinus Torvalds "Wave Master Playback Volume", "Master Playback Volume", 790*1da177e4SLinus Torvalds "AMic Playback Volume", "Mic Playback Volume", 791*1da177e4SLinus Torvalds NULL 792*1da177e4SLinus Torvalds }; 793*1da177e4SLinus Torvalds 794*1da177e4SLinus Torvalds if (!emu->no_ac97) { 795*1da177e4SLinus Torvalds ac97_bus_t *pbus; 796*1da177e4SLinus Torvalds ac97_template_t ac97; 797*1da177e4SLinus Torvalds static ac97_bus_ops_t ops = { 798*1da177e4SLinus Torvalds .write = snd_emu10k1_ac97_write, 799*1da177e4SLinus Torvalds .read = snd_emu10k1_ac97_read, 800*1da177e4SLinus Torvalds }; 801*1da177e4SLinus Torvalds 802*1da177e4SLinus Torvalds if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0) 803*1da177e4SLinus Torvalds return err; 804*1da177e4SLinus Torvalds pbus->no_vra = 1; /* we don't need VRA */ 805*1da177e4SLinus Torvalds 806*1da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97)); 807*1da177e4SLinus Torvalds ac97.private_data = emu; 808*1da177e4SLinus Torvalds ac97.private_free = snd_emu10k1_mixer_free_ac97; 809*1da177e4SLinus Torvalds ac97.scaps = AC97_SCAP_NO_SPDIF; 810*1da177e4SLinus Torvalds if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) 811*1da177e4SLinus Torvalds return err; 812*1da177e4SLinus Torvalds if (emu->audigy) { 813*1da177e4SLinus Torvalds /* set master volume to 0 dB */ 814*1da177e4SLinus Torvalds snd_ac97_write(emu->ac97, AC97_MASTER, 0x0000); 815*1da177e4SLinus Torvalds /* set capture source to mic */ 816*1da177e4SLinus Torvalds snd_ac97_write(emu->ac97, AC97_REC_SEL, 0x0000); 817*1da177e4SLinus Torvalds c = audigy_remove_ctls; 818*1da177e4SLinus Torvalds } else { 819*1da177e4SLinus Torvalds /* 820*1da177e4SLinus Torvalds * Credits for cards based on STAC9758: 821*1da177e4SLinus Torvalds * James Courtier-Dutton <James@superbug.demon.co.uk> 822*1da177e4SLinus Torvalds * Voluspa <voluspa@comhem.se> 823*1da177e4SLinus Torvalds */ 824*1da177e4SLinus Torvalds if (emu->ac97->id == AC97_ID_STAC9758) { 825*1da177e4SLinus Torvalds emu->rear_ac97 = 1; 826*1da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); 827*1da177e4SLinus Torvalds } 828*1da177e4SLinus Torvalds /* remove unused AC97 controls */ 829*1da177e4SLinus Torvalds snd_ac97_write(emu->ac97, AC97_SURROUND_MASTER, 0x0202); 830*1da177e4SLinus Torvalds snd_ac97_write(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); 831*1da177e4SLinus Torvalds c = emu10k1_remove_ctls; 832*1da177e4SLinus Torvalds } 833*1da177e4SLinus Torvalds for (; *c; c++) 834*1da177e4SLinus Torvalds remove_ctl(card, *c); 835*1da177e4SLinus Torvalds } else { 836*1da177e4SLinus Torvalds if (emu->APS) 837*1da177e4SLinus Torvalds strcpy(emu->card->mixername, "EMU APS"); 838*1da177e4SLinus Torvalds else if (emu->audigy) 839*1da177e4SLinus Torvalds strcpy(emu->card->mixername, "SB Audigy"); 840*1da177e4SLinus Torvalds else 841*1da177e4SLinus Torvalds strcpy(emu->card->mixername, "Emu10k1"); 842*1da177e4SLinus Torvalds } 843*1da177e4SLinus Torvalds 844*1da177e4SLinus Torvalds if (emu->audigy) 845*1da177e4SLinus Torvalds c = audigy_rename_ctls; 846*1da177e4SLinus Torvalds else 847*1da177e4SLinus Torvalds c = emu10k1_rename_ctls; 848*1da177e4SLinus Torvalds for (; *c; c += 2) 849*1da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 850*1da177e4SLinus Torvalds 851*1da177e4SLinus Torvalds if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) 852*1da177e4SLinus Torvalds return -ENOMEM; 853*1da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 854*1da177e4SLinus Torvalds return err; 855*1da177e4SLinus Torvalds if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL) 856*1da177e4SLinus Torvalds return -ENOMEM; 857*1da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 858*1da177e4SLinus Torvalds return err; 859*1da177e4SLinus Torvalds if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL) 860*1da177e4SLinus Torvalds return -ENOMEM; 861*1da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 862*1da177e4SLinus Torvalds return err; 863*1da177e4SLinus Torvalds 864*1da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL) 865*1da177e4SLinus Torvalds return -ENOMEM; 866*1da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 867*1da177e4SLinus Torvalds return err; 868*1da177e4SLinus Torvalds 869*1da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL) 870*1da177e4SLinus Torvalds return -ENOMEM; 871*1da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 872*1da177e4SLinus Torvalds return err; 873*1da177e4SLinus Torvalds 874*1da177e4SLinus Torvalds if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL) 875*1da177e4SLinus Torvalds return -ENOMEM; 876*1da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 877*1da177e4SLinus Torvalds return err; 878*1da177e4SLinus Torvalds 879*1da177e4SLinus Torvalds /* initialize the routing and volume table for each pcm playback stream */ 880*1da177e4SLinus Torvalds for (pcm = 0; pcm < 32; pcm++) { 881*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix; 882*1da177e4SLinus Torvalds int v; 883*1da177e4SLinus Torvalds 884*1da177e4SLinus Torvalds mix = &emu->pcm_mixer[pcm]; 885*1da177e4SLinus Torvalds mix->epcm = NULL; 886*1da177e4SLinus Torvalds 887*1da177e4SLinus Torvalds for (v = 0; v < 4; v++) 888*1da177e4SLinus Torvalds mix->send_routing[0][v] = 889*1da177e4SLinus Torvalds mix->send_routing[1][v] = 890*1da177e4SLinus Torvalds mix->send_routing[2][v] = v; 891*1da177e4SLinus Torvalds 892*1da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 893*1da177e4SLinus Torvalds mix->send_volume[0][0] = mix->send_volume[0][1] = 894*1da177e4SLinus Torvalds mix->send_volume[1][0] = mix->send_volume[2][1] = 255; 895*1da177e4SLinus Torvalds 896*1da177e4SLinus Torvalds mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; 897*1da177e4SLinus Torvalds } 898*1da177e4SLinus Torvalds 899*1da177e4SLinus Torvalds /* initialize the routing and volume table for the multichannel playback stream */ 900*1da177e4SLinus Torvalds for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) { 901*1da177e4SLinus Torvalds emu10k1_pcm_mixer_t *mix; 902*1da177e4SLinus Torvalds int v; 903*1da177e4SLinus Torvalds 904*1da177e4SLinus Torvalds mix = &emu->efx_pcm_mixer[pcm]; 905*1da177e4SLinus Torvalds mix->epcm = NULL; 906*1da177e4SLinus Torvalds 907*1da177e4SLinus Torvalds mix->send_routing[0][0] = pcm; 908*1da177e4SLinus Torvalds mix->send_routing[0][1] = (pcm == 0) ? 1 : 0; 909*1da177e4SLinus Torvalds for (v = 0; v < 2; v++) 910*1da177e4SLinus Torvalds mix->send_routing[0][2+v] = 13+v; 911*1da177e4SLinus Torvalds if (emu->audigy) 912*1da177e4SLinus Torvalds for (v = 0; v < 4; v++) 913*1da177e4SLinus Torvalds mix->send_routing[0][4+v] = 60+v; 914*1da177e4SLinus Torvalds 915*1da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 916*1da177e4SLinus Torvalds mix->send_volume[0][0] = 255; 917*1da177e4SLinus Torvalds 918*1da177e4SLinus Torvalds mix->attn[0] = 0xffff; 919*1da177e4SLinus Torvalds } 920*1da177e4SLinus Torvalds 921*1da177e4SLinus Torvalds if (! emu->APS) { /* FIXME: APS has these controls? */ 922*1da177e4SLinus Torvalds /* sb live! and audigy */ 923*1da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) 924*1da177e4SLinus Torvalds return -ENOMEM; 925*1da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 926*1da177e4SLinus Torvalds return err; 927*1da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) 928*1da177e4SLinus Torvalds return -ENOMEM; 929*1da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 930*1da177e4SLinus Torvalds return err; 931*1da177e4SLinus Torvalds } 932*1da177e4SLinus Torvalds 933*1da177e4SLinus Torvalds if (emu->audigy) { 934*1da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) 935*1da177e4SLinus Torvalds return -ENOMEM; 936*1da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 937*1da177e4SLinus Torvalds return err; 938*1da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) 939*1da177e4SLinus Torvalds return -ENOMEM; 940*1da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 941*1da177e4SLinus Torvalds return err; 942*1da177e4SLinus Torvalds } else if (! emu->APS) { 943*1da177e4SLinus Torvalds /* sb live! */ 944*1da177e4SLinus Torvalds if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) 945*1da177e4SLinus Torvalds return -ENOMEM; 946*1da177e4SLinus Torvalds if ((err = snd_ctl_add(card, kctl))) 947*1da177e4SLinus Torvalds return err; 948*1da177e4SLinus Torvalds } 949*1da177e4SLinus Torvalds if (emu->audigy && emu->revision == 4) { /* P16V */ 950*1da177e4SLinus Torvalds if ((err = snd_p16v_mixer(emu))) 951*1da177e4SLinus Torvalds return err; 952*1da177e4SLinus Torvalds } 953*1da177e4SLinus Torvalds 954*1da177e4SLinus Torvalds return 0; 955*1da177e4SLinus Torvalds } 956