diff options
Diffstat (limited to 'sound/pci/ca0106/ca0106_mixer.c')
-rw-r--r-- | sound/pci/ca0106/ca0106_mixer.c | 69 |
1 files changed, 68 insertions, 1 deletions
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index a135b9c4c3c8..7fbfe17438b4 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.17 + * Version: 0.0.18 * * FEATURES currently supported: * See ca0106_main.c for features. @@ -39,6 +39,8 @@ * Modified Copyright message. * 0.0.17 * Implement Mic and Line in Capture. + * 0.0.18 + * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) * * This code was initally based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> @@ -462,6 +464,42 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, return change; } +#define spi_mute_info snd_ctl_boolean_mono_info + +static int spi_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT; + unsigned int bit = kcontrol->private_value & SPI_REG_MASK; + + ucontrol->value.integer.value[0] = !(emu->spi_dac_reg[reg] & bit); + return 0; +} + +static int spi_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT; + unsigned int bit = kcontrol->private_value & SPI_REG_MASK; + int ret; + + ret = emu->spi_dac_reg[reg] & bit; + if (ucontrol->value.integer.value[0]) { + if (!ret) /* bit already cleared, do nothing */ + return 0; + emu->spi_dac_reg[reg] &= ~bit; + } else { + if (ret) /* bit already set, do nothing */ + return 0; + emu->spi_dac_reg[reg] |= bit; + } + + ret = snd_ca0106_spi_write(emu, emu->spi_dac_reg[reg]); + return ret ? -1 : 1; +} + #define CA_VOLUME(xname,chid,reg) \ { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ @@ -554,6 +592,28 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = I2C_VOLUME("Aux Capture Volume", 3), }; +#define SPI_SWITCH(xname,reg,bit) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = spi_mute_info, \ + .get = spi_mute_get, \ + .put = spi_mute_put, \ + .private_value = (reg<<SPI_REG_SHIFT) | (1<<bit) \ +} + +static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[] +__devinitdata = { + SPI_SWITCH("Analog Front Playback Switch", + SPI_DMUTE4_REG, SPI_DMUTE4_BIT), + SPI_SWITCH("Analog Rear Playback Switch", + SPI_DMUTE0_REG, SPI_DMUTE0_BIT), + SPI_SWITCH("Analog Center/LFE Playback Switch", + SPI_DMUTE2_REG, SPI_DMUTE2_BIT), + SPI_SWITCH("Analog Side Playback Switch", + SPI_DMUTE1_REG, SPI_DMUTE1_BIT), +}; + static int __devinit remove_ctl(struct snd_card *card, const char *name) { struct snd_ctl_elem_id id; @@ -650,6 +710,13 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) if (err < 0) return err; } + if (emu->details->spi_dac == 1) { + for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_spi_dac_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_spi_dac_ctls[i], emu)); + if (err < 0) + return err; + } + } return 0; } |