From d0ce9946c52e7bdf95afb09553775cf28b752254 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 23 Dec 2007 19:50:57 +0100 Subject: [ALSA] add CMI8788 driver Add the snd-oxygen driver for the C-Media CMI8788 (Oxygen) chip, used on the Asound A-8788, AuzenTech X-Meridian, Bgears b-Enspirer, Club3D Theatron DTS, HT-Omega Claro, Razer Barracuda AC-1, Sondigo Inferno, and TempoTec HIFIER sound cards. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 623 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 623 insertions(+) create mode 100644 sound/pci/oxygen/oxygen_mixer.c (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c new file mode 100644 index 000000000000..e252abac004e --- /dev/null +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -0,0 +1,623 @@ +/* + * C-Media CMI8788 driver - mixer code + * + * Copyright (c) Clemens Ladisch + * + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this driver; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "oxygen.h" + +static int dac_volume_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + struct oxygen *chip = ctl->private_data; + + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 8; + info->value.integer.min = chip->model->dac_minimum_volume; + info->value.integer.max = 0xff; + return 0; +} + +static int dac_volume_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + unsigned int i; + + mutex_lock(&chip->mutex); + for (i = 0; i < 8; ++i) + value->value.integer.value[i] = chip->dac_volume[i]; + mutex_unlock(&chip->mutex); + return 0; +} + +static int dac_volume_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + unsigned int i; + int changed; + + changed = 0; + mutex_lock(&chip->mutex); + for (i = 0; i < 8; ++i) + if (value->value.integer.value[i] != chip->dac_volume[i]) { + chip->dac_volume[i] = value->value.integer.value[i]; + changed = 1; + } + if (changed) + chip->model->update_dac_volume(chip); + mutex_unlock(&chip->mutex); + return changed; +} + +static int dac_mute_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + + mutex_lock(&chip->mutex); + value->value.integer.value[0] = !chip->dac_mute; + mutex_unlock(&chip->mutex); + return 0; +} + +static int dac_mute_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + int changed; + + mutex_lock(&chip->mutex); + changed = !value->value.integer.value[0] != chip->dac_mute; + if (changed) { + chip->dac_mute = !value->value.integer.value[0]; + chip->model->update_dac_mute(chip); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) +{ + static const char *const names[3] = { + "Front", "Front+Rear", "Front+Rear+Side" + }; + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 3; + if (info->value.enumerated.item > 2) + info->value.enumerated.item = 2; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + + mutex_lock(&chip->mutex); + value->value.enumerated.item[0] = chip->dac_routing; + mutex_unlock(&chip->mutex); + return 0; +} + +void oxygen_update_dac_routing(struct oxygen *chip) +{ + /* + * hardware channel order: front, side, center/lfe, rear + * ALSA channel order: front, rear, center/lfe, side + */ + static const unsigned int reg_values[3] = { + 0x6c00, 0x2c00, 0x2000 + }; + unsigned int reg_value; + + if ((oxygen_read8(chip, OXYGEN_PLAY_CHANNELS) & + OXYGEN_PLAY_CHANNELS_MASK) == OXYGEN_PLAY_CHANNELS_2) + reg_value = reg_values[chip->dac_routing]; + else + reg_value = 0x6c00; + oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value, 0xff00); +} + +static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + int changed; + + mutex_lock(&chip->mutex); + changed = value->value.enumerated.item[0] != chip->dac_routing; + if (changed) { + chip->dac_routing = min(value->value.enumerated.item[0], 2u); + spin_lock_irq(&chip->reg_lock); + oxygen_update_dac_routing(chip); + spin_unlock_irq(&chip->reg_lock); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static int spdif_switch_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + + mutex_lock(&chip->mutex); + value->value.integer.value[0] = chip->spdif_playback_enable; + mutex_unlock(&chip->mutex); + return 0; +} + +static unsigned int oxygen_spdif_rate(unsigned int oxygen_rate) +{ + switch (oxygen_rate) { + case OXYGEN_RATE_32000: + return IEC958_AES3_CON_FS_32000 << OXYGEN_SPDIF_CS_RATE_SHIFT; + case OXYGEN_RATE_44100: + return IEC958_AES3_CON_FS_44100 << OXYGEN_SPDIF_CS_RATE_SHIFT; + default: /* OXYGEN_RATE_48000 */ + return IEC958_AES3_CON_FS_48000 << OXYGEN_SPDIF_CS_RATE_SHIFT; + case OXYGEN_RATE_64000: + return 0xb << OXYGEN_SPDIF_CS_RATE_SHIFT; + case OXYGEN_RATE_88200: + return 0x8 << OXYGEN_SPDIF_CS_RATE_SHIFT; + case OXYGEN_RATE_96000: + return 0xa << OXYGEN_SPDIF_CS_RATE_SHIFT; + case OXYGEN_RATE_176400: + return 0xc << OXYGEN_SPDIF_CS_RATE_SHIFT; + case OXYGEN_RATE_192000: + return 0xe << OXYGEN_SPDIF_CS_RATE_SHIFT; + } +} + +void oxygen_update_spdif_source(struct oxygen *chip) +{ + u32 old_control, new_control; + u16 old_routing, new_routing; + unsigned int oxygen_rate; + + old_control = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); + old_routing = oxygen_read16(chip, OXYGEN_PLAY_ROUTING); + if (chip->pcm_active & (1 << PCM_SPDIF)) { + new_control = old_control | OXYGEN_SPDIF_OUT_ENABLE; + new_routing = (old_routing & ~0x00e0) | 0x0000; + oxygen_rate = (old_control >> OXYGEN_SPDIF_OUT_RATE_SHIFT) + & OXYGEN_I2S_RATE_MASK; + /* S/PDIF rate was already set by the caller */ + } else if ((chip->pcm_active & (1 << PCM_MULTICH)) && + chip->spdif_playback_enable) { + new_routing = (old_routing & ~0x00e0) | 0x0020; + oxygen_rate = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT) + & OXYGEN_I2S_RATE_MASK; + new_control = (old_control & ~OXYGEN_SPDIF_OUT_RATE_MASK) | + (oxygen_rate << OXYGEN_SPDIF_OUT_RATE_SHIFT) | + OXYGEN_SPDIF_OUT_ENABLE; + } else { + new_control = old_control & ~OXYGEN_SPDIF_OUT_ENABLE; + new_routing = old_routing; + oxygen_rate = OXYGEN_RATE_44100; + } + if (old_routing != new_routing) { + oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, + new_control & ~OXYGEN_SPDIF_OUT_ENABLE); + oxygen_write16(chip, OXYGEN_PLAY_ROUTING, new_routing); + } + if (new_control & OXYGEN_SPDIF_OUT_ENABLE) + oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, + oxygen_spdif_rate(oxygen_rate) | + ((chip->pcm_active & (1 << PCM_SPDIF)) ? + chip->spdif_pcm_bits : chip->spdif_bits)); + oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, new_control); +} + +static int spdif_switch_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + int changed; + + mutex_lock(&chip->mutex); + changed = value->value.integer.value[0] != chip->spdif_playback_enable; + if (changed) { + chip->spdif_playback_enable = !!value->value.integer.value[0]; + spin_lock_irq(&chip->reg_lock); + oxygen_update_spdif_source(chip); + spin_unlock_irq(&chip->reg_lock); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static int spdif_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_IEC958; + info->count = 1; + return 0; +} + +static void oxygen_to_iec958(u32 bits, struct snd_ctl_elem_value *value) +{ + value->value.iec958.status[0] = + bits & (OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C | + OXYGEN_SPDIF_PREEMPHASIS); + value->value.iec958.status[1] = /* category and original */ + bits >> OXYGEN_SPDIF_CATEGORY_SHIFT; +} + +static u32 iec958_to_oxygen(struct snd_ctl_elem_value *value) +{ + u32 bits; + + bits = value->value.iec958.status[0] & + (OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C | + OXYGEN_SPDIF_PREEMPHASIS); + bits |= value->value.iec958.status[1] << OXYGEN_SPDIF_CATEGORY_SHIFT; + if (bits & OXYGEN_SPDIF_NONAUDIO) + bits |= OXYGEN_SPDIF_V; + return bits; +} + +static inline void write_spdif_bits(struct oxygen *chip, u32 bits) +{ + oxygen_write32_masked(chip, OXYGEN_SPDIF_OUTPUT_BITS, bits, + OXYGEN_SPDIF_NONAUDIO | + OXYGEN_SPDIF_C | + OXYGEN_SPDIF_PREEMPHASIS | + OXYGEN_SPDIF_CATEGORY_MASK | + OXYGEN_SPDIF_ORIGINAL | + OXYGEN_SPDIF_V); +} + +static int spdif_default_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + + mutex_lock(&chip->mutex); + oxygen_to_iec958(chip->spdif_bits, value); + mutex_unlock(&chip->mutex); + return 0; +} + +static int spdif_default_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u32 new_bits; + int changed; + + new_bits = iec958_to_oxygen(value); + mutex_lock(&chip->mutex); + changed = new_bits != chip->spdif_bits; + if (changed) { + chip->spdif_bits = new_bits; + if (!(chip->pcm_active & (1 << PCM_SPDIF))) + write_spdif_bits(chip, new_bits); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static int spdif_mask_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + value->value.iec958.status[0] = IEC958_AES0_NONAUDIO | + IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS; + value->value.iec958.status[1] = + IEC958_AES1_CON_CATEGORY | IEC958_AES1_CON_ORIGINAL; + return 0; +} + +static int spdif_pcm_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + + mutex_lock(&chip->mutex); + oxygen_to_iec958(chip->spdif_pcm_bits, value); + mutex_unlock(&chip->mutex); + return 0; +} + +static int spdif_pcm_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u32 new_bits; + int changed; + + new_bits = iec958_to_oxygen(value); + mutex_lock(&chip->mutex); + changed = new_bits != chip->spdif_pcm_bits; + if (changed) { + chip->spdif_pcm_bits = new_bits; + if (chip->pcm_active & (1 << PCM_SPDIF)) + write_spdif_bits(chip, new_bits); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static int spdif_input_mask_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + value->value.iec958.status[0] = 0xff; + value->value.iec958.status[1] = 0xff; + value->value.iec958.status[2] = 0xff; + value->value.iec958.status[3] = 0xff; + return 0; +} + +static int spdif_input_default_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u32 bits; + + bits = oxygen_read32(chip, OXYGEN_SPDIF_INPUT_BITS); + value->value.iec958.status[0] = bits; + value->value.iec958.status[1] = bits >> 8; + value->value.iec958.status[2] = bits >> 16; + value->value.iec958.status[3] = bits >> 24; + return 0; +} + +static int ac97_switch_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + unsigned int index = ctl->private_value & 0xff; + unsigned int bitnr = (ctl->private_value >> 8) & 0xff; + int invert = ctl->private_value & (1 << 16); + u16 reg; + + mutex_lock(&chip->mutex); + reg = oxygen_read_ac97(chip, 0, index); + mutex_unlock(&chip->mutex); + if (!(reg & (1 << bitnr)) ^ !invert) + value->value.integer.value[0] = 1; + else + value->value.integer.value[0] = 0; + return 0; +} + +static int ac97_switch_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + unsigned int index = ctl->private_value & 0xff; + unsigned int bitnr = (ctl->private_value >> 8) & 0xff; + int invert = ctl->private_value & (1 << 16); + u16 oldreg, newreg; + int change; + + mutex_lock(&chip->mutex); + oldreg = oxygen_read_ac97(chip, 0, index); + newreg = oldreg; + if (!value->value.integer.value[0] ^ !invert) + newreg |= 1 << bitnr; + else + newreg &= ~(1 << bitnr); + change = newreg != oldreg; + if (change) { + oxygen_write_ac97(chip, 0, index, newreg); + if (index == AC97_LINE) + oxygen_write_ac97_masked(chip, 0, 0x72, + !!(newreg & 0x8000), 0x0001); + } + mutex_unlock(&chip->mutex); + return change; +} + +static int ac97_volume_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 2; + info->value.integer.min = 0; + info->value.integer.max = 0x1f; + return 0; +} + +static int ac97_volume_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + unsigned int index = ctl->private_value; + u16 reg; + + mutex_lock(&chip->mutex); + reg = oxygen_read_ac97(chip, 0, index); + mutex_unlock(&chip->mutex); + value->value.integer.value[0] = 31 - (reg & 0x1f); + value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f); + return 0; +} + +static int ac97_volume_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + unsigned int index = ctl->private_value; + u16 oldreg, newreg; + int change; + + mutex_lock(&chip->mutex); + oldreg = oxygen_read_ac97(chip, 0, index); + newreg = oldreg; + newreg = (newreg & ~0x1f) | + (31 - (value->value.integer.value[0] & 0x1f)); + newreg = (newreg & ~0x1f00) | + ((31 - (value->value.integer.value[0] & 0x1f)) << 8); + change = newreg != oldreg; + if (change) + oxygen_write_ac97(chip, 0, index, newreg); + mutex_unlock(&chip->mutex); + return change; +} + +#define AC97_SWITCH(xname, index, bitnr, invert) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = snd_ctl_boolean_mono_info, \ + .get = ac97_switch_get, \ + .put = ac97_switch_put, \ + .private_value = ((invert) << 16) | ((bitnr) << 8) | (index), \ + } +#define AC97_VOLUME(xname, index) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = ac97_volume_info, \ + .get = ac97_volume_get, \ + .put = ac97_volume_put, \ + .tlv = { .p = ac97_db_scale, }, \ + .private_value = (index), \ + } + +static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); + +static const struct snd_kcontrol_new controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = dac_volume_info, + .get = dac_volume_get, + .put = dac_volume_put, + .tlv = { + .p = NULL, /* set later */ + }, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = dac_mute_get, + .put = dac_mute_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Stereo Upmixing", + .info = upmix_info, + .get = upmix_get, + .put = upmix_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), + .info = snd_ctl_boolean_mono_info, + .get = spdif_switch_get, + .put = spdif_switch_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .device = 1, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = spdif_info, + .get = spdif_default_get, + .put = spdif_default_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .device = 1, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = spdif_info, + .get = spdif_mask_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .device = 1, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_INACTIVE, + .info = spdif_info, + .get = spdif_pcm_get, + .put = spdif_pcm_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .device = 1, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = spdif_info, + .get = spdif_input_mask_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .device = 1, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = spdif_info, + .get = spdif_input_default_get, + }, + AC97_VOLUME("Mic Capture Volume", AC97_MIC), + AC97_SWITCH("Mic Capture Switch", AC97_MIC, 15, 1), + AC97_SWITCH("Mic Boost (+20dB)", AC97_MIC, 6, 0), + AC97_SWITCH("Line Capture Switch", AC97_LINE, 15, 1), + AC97_VOLUME("CD Capture Volume", AC97_CD), + AC97_SWITCH("CD Capture Switch", AC97_CD, 15, 1), + AC97_VOLUME("Aux Capture Volume", AC97_AUX), + AC97_SWITCH("Aux Capture Switch", AC97_AUX, 15, 1), +}; + +static void oxygen_any_ctl_free(struct snd_kcontrol *ctl) +{ + struct oxygen *chip = ctl->private_data; + + /* I'm too lazy to write a function for each control :-) */ + chip->spdif_pcm_ctl = NULL; + chip->spdif_input_bits_ctl = NULL; +} + +int oxygen_mixer_init(struct oxygen *chip) +{ + unsigned int i; + struct snd_kcontrol *ctl; + int err; + + for (i = 0; i < ARRAY_SIZE(controls); ++i) { + ctl = snd_ctl_new1(&controls[i], chip); + if (!ctl) + return -ENOMEM; + if (!strcmp(ctl->id.name, "PCM Playback Volume")) + ctl->tlv.p = chip->model->dac_tlv; + else if (chip->model->cd_in_from_video_in && + !strncmp(ctl->id.name, "CD Capture ", 11)) + ctl->private_value ^= AC97_CD ^ AC97_VIDEO; + err = snd_ctl_add(chip->card, ctl); + if (err < 0) + return err; + if (!strcmp(ctl->id.name, + SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM))) { + chip->spdif_pcm_ctl = ctl; + ctl->private_free = oxygen_any_ctl_free; + } else if (!strcmp(ctl->id.name, + SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT))) { + chip->spdif_input_bits_ctl = ctl; + ctl->private_free = oxygen_any_ctl_free; + } + } + return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0; +} -- cgit v1.2.1 From 9004acc70e8c49c50c4c7b652f906f1e0ed5709d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Jan 2008 18:13:27 +0100 Subject: [ALSA] Remove sound/driver.h This header file exists only for some hacks to adapt alsa-driver tree. It's useless for building in the kernel. Let's move a few lines in it to sound/core.h and remove it. With this patch, sound/driver.h isn't removed but has just a single compile warning to include it. This should be really killed in future. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index e252abac004e..7208b0fb3ee5 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -17,7 +17,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include -- cgit v1.2.1 From 7113e95812f508bff10f95f2e52ce6ee8cda1875 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 14 Jan 2008 08:55:03 +0100 Subject: [ALSA] oxygen: fix channel routing Do not exchange the surround and back jacks except when in 7.1 mode where the surround jack is not rear but side. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 7208b0fb3ee5..ca72799bea27 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -99,7 +99,7 @@ static int dac_mute_put(struct snd_kcontrol *ctl, static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { static const char *const names[3] = { - "Front", "Front+Rear", "Front+Rear+Side" + "Front", "Front+Surround", "Front+Surround+Back" }; info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; info->count = 1; @@ -122,20 +122,22 @@ static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) void oxygen_update_dac_routing(struct oxygen *chip) { - /* - * hardware channel order: front, side, center/lfe, rear - * ALSA channel order: front, rear, center/lfe, side - */ static const unsigned int reg_values[3] = { - 0x6c00, 0x2c00, 0x2000 + 0xe100, /* front <- 0, surround <- 1, center <- 2, back <- 3 */ + 0xe000, /* front <- 0, surround <- 0, center <- 2, back <- 3 */ + 0x2000 /* front <- 0, surround <- 0, center <- 2, back <- 0 */ }; + u8 channels; unsigned int reg_value; - if ((oxygen_read8(chip, OXYGEN_PLAY_CHANNELS) & - OXYGEN_PLAY_CHANNELS_MASK) == OXYGEN_PLAY_CHANNELS_2) + channels = oxygen_read8(chip, OXYGEN_PLAY_CHANNELS) & + OXYGEN_PLAY_CHANNELS_MASK; + if (channels == OXYGEN_PLAY_CHANNELS_2) reg_value = reg_values[chip->dac_routing]; + else if (channels == OXYGEN_PLAY_CHANNELS_8) + reg_value = 0x6c00; /* surround <- 3, back <- 1 */ else - reg_value = 0x6c00; + reg_value = 0xe100; oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value, 0xff00); } -- cgit v1.2.1 From 01a3affb2eebfd6c996c36d82bbbc6040eb3a7f1 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 14 Jan 2008 08:56:01 +0100 Subject: [ALSA] oxygen: use an array of snd_kcontrol pointers Use an array for the pointers to known controls so that it is easier to add more. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index ca72799bea27..f7350faada1a 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -586,15 +586,22 @@ static const struct snd_kcontrol_new controls[] = { static void oxygen_any_ctl_free(struct snd_kcontrol *ctl) { struct oxygen *chip = ctl->private_data; + unsigned int i; /* I'm too lazy to write a function for each control :-) */ - chip->spdif_pcm_ctl = NULL; - chip->spdif_input_bits_ctl = NULL; + for (i = 0; i < ARRAY_SIZE(chip->controls); ++i) + chip->controls[i] = NULL; } int oxygen_mixer_init(struct oxygen *chip) { - unsigned int i; + static const char *const known_ctl_names[CONTROL_COUNT] = { + [CONTROL_SPDIF_PCM] = + SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), + [CONTROL_SPDIF_INPUT_BITS] = + SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), + }; + unsigned int i, j; struct snd_kcontrol *ctl; int err; @@ -610,15 +617,11 @@ int oxygen_mixer_init(struct oxygen *chip) err = snd_ctl_add(chip->card, ctl); if (err < 0) return err; - if (!strcmp(ctl->id.name, - SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM))) { - chip->spdif_pcm_ctl = ctl; - ctl->private_free = oxygen_any_ctl_free; - } else if (!strcmp(ctl->id.name, - SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT))) { - chip->spdif_input_bits_ctl = ctl; - ctl->private_free = oxygen_any_ctl_free; - } + for (j = 0; j < CONTROL_COUNT; ++j) + if (!strcmp(ctl->id.name, known_ctl_names[j])) { + chip->controls[j] = ctl; + ctl->private_free = oxygen_any_ctl_free; + } } return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0; } -- cgit v1.2.1 From 893e44ba5a7cc05d66b69806defc17dd762c3ba8 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 14 Jan 2008 08:57:05 +0100 Subject: [ALSA] oxygen: make line-in switch exclusive The line input cannot be mixed with the other inputs, so we have to mute the other input switches when it is selected. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index f7350faada1a..fcb5813183fb 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -402,6 +402,19 @@ static int ac97_switch_get(struct snd_kcontrol *ctl, return 0; } +static void ac97_mute_ctl(struct oxygen *chip, unsigned int control) +{ + unsigned int index = chip->controls[control]->private_value & 0xff; + u16 value; + + value = oxygen_read_ac97(chip, 0, index); + if (!(value & 0x8000)) { + oxygen_write_ac97(chip, 0, index, value | 0x8000); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->controls[control]->id); + } +} + static int ac97_switch_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { @@ -422,9 +435,20 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, change = newreg != oldreg; if (change) { oxygen_write_ac97(chip, 0, index, newreg); - if (index == AC97_LINE) + if (index == AC97_LINE) { oxygen_write_ac97_masked(chip, 0, 0x72, !!(newreg & 0x8000), 0x0001); + if (!(newreg & 0x8000)) { + ac97_mute_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH); + ac97_mute_ctl(chip, CONTROL_CD_CAPTURE_SWITCH); + ac97_mute_ctl(chip, CONTROL_AUX_CAPTURE_SWITCH); + } + } else if ((index == AC97_MIC || index == AC97_CD || + index == AC97_VIDEO || index == AC97_AUX) && + bitnr == 15 && !(newreg & 0x8000)) { + ac97_mute_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH); + oxygen_write_ac97_masked(chip, 0, 0x72, 0x0001, 0x0001); + } } mutex_unlock(&chip->mutex); return change; @@ -600,6 +624,10 @@ int oxygen_mixer_init(struct oxygen *chip) SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), [CONTROL_SPDIF_INPUT_BITS] = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), + [CONTROL_MIC_CAPTURE_SWITCH] = "Mic Capture Switch", + [CONTROL_LINE_CAPTURE_SWITCH] = "Line Capture Switch", + [CONTROL_CD_CAPTURE_SWITCH] = "CD Capture Switch", + [CONTROL_AUX_CAPTURE_SWITCH] = "Aux Capture Switch", }; unsigned int i, j; struct snd_kcontrol *ctl; -- cgit v1.2.1 From fb920b7d8b65f253671073d40d490d0968151680 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 15 Jan 2008 08:39:06 +0100 Subject: [ALSA] oxygen: rename PCM to Master Rename the 'PCM Playback Volume'/'Switch' mixer controls to 'Master'. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index fcb5813183fb..aa3a5c53d605 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -524,7 +524,7 @@ static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); static const struct snd_kcontrol_new controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", + .name = "Master Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = dac_volume_info, @@ -536,7 +536,7 @@ static const struct snd_kcontrol_new controls[] = { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", + .name = "Master Playback Switch", .info = snd_ctl_boolean_mono_info, .get = dac_mute_get, .put = dac_mute_put, @@ -637,7 +637,7 @@ int oxygen_mixer_init(struct oxygen *chip) ctl = snd_ctl_new1(&controls[i], chip); if (!ctl) return -ENOMEM; - if (!strcmp(ctl->id.name, "PCM Playback Volume")) + if (!strcmp(ctl->id.name, "Master Playback Volume")) ctl->tlv.p = chip->model->dac_tlv; else if (chip->model->cd_in_from_video_in && !strncmp(ctl->id.name, "CD Capture ", 11)) -- cgit v1.2.1 From 31c77643a06313b3a26f4c38c75ceec2a89ad31a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 16 Jan 2008 08:28:17 +0100 Subject: [ALSA] oxygen: make AC97 codec optional Only initialize and create mixer controls for the first AC97 codec when one has actually been detected. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index aa3a5c53d605..8b08e6d02cc9 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -597,6 +597,9 @@ static const struct snd_kcontrol_new controls[] = { .info = spdif_info, .get = spdif_input_default_get, }, +}; + +static const struct snd_kcontrol_new ac97_controls[] = { AC97_VOLUME("Mic Capture Volume", AC97_MIC), AC97_SWITCH("Mic Capture Switch", AC97_MIC, 15, 1), AC97_SWITCH("Mic Boost (+20dB)", AC97_MIC, 6, 0), @@ -617,7 +620,9 @@ static void oxygen_any_ctl_free(struct snd_kcontrol *ctl) chip->controls[i] = NULL; } -int oxygen_mixer_init(struct oxygen *chip) +static int add_controls(struct oxygen *chip, + const struct snd_kcontrol_new controls[], + unsigned int count) { static const char *const known_ctl_names[CONTROL_COUNT] = { [CONTROL_SPDIF_PCM] = @@ -633,7 +638,7 @@ int oxygen_mixer_init(struct oxygen *chip) struct snd_kcontrol *ctl; int err; - for (i = 0; i < ARRAY_SIZE(controls); ++i) { + for (i = 0; i < count; ++i) { ctl = snd_ctl_new1(&controls[i], chip); if (!ctl) return -ENOMEM; @@ -651,5 +656,21 @@ int oxygen_mixer_init(struct oxygen *chip) ctl->private_free = oxygen_any_ctl_free; } } + return 0; +} + +int oxygen_mixer_init(struct oxygen *chip) +{ + int err; + + err = add_controls(chip, controls, ARRAY_SIZE(controls)); + if (err < 0) + return err; + if (chip->has_ac97_0) { + err = add_controls(chip, ac97_controls, + ARRAY_SIZE(ac97_controls)); + if (err < 0) + return err; + } return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0; } -- cgit v1.2.1 From ccc80fb467a88ceb7ce1b68546632b91e5ba6c18 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 16 Jan 2008 08:32:08 +0100 Subject: [ALSA] oxygen: add control filter to model struct Allow the models to modify mixer controls before they are added to the card. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 8b08e6d02cc9..fae7c0f060a0 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -27,11 +27,9 @@ static int dac_volume_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { - struct oxygen *chip = ctl->private_data; - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; info->count = 8; - info->value.integer.min = chip->model->dac_minimum_volume; + info->value.integer.min = 0; info->value.integer.max = 0xff; return 0; } @@ -525,14 +523,10 @@ static const struct snd_kcontrol_new controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = dac_volume_info, .get = dac_volume_get, .put = dac_volume_put, - .tlv = { - .p = NULL, /* set later */ - }, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -635,18 +629,18 @@ static int add_controls(struct oxygen *chip, [CONTROL_AUX_CAPTURE_SWITCH] = "Aux Capture Switch", }; unsigned int i, j; + struct snd_kcontrol_new template; struct snd_kcontrol *ctl; int err; for (i = 0; i < count; ++i) { + template = controls[i]; + err = chip->model->control_filter(&template); + if (err < 0) + return err; ctl = snd_ctl_new1(&controls[i], chip); if (!ctl) return -ENOMEM; - if (!strcmp(ctl->id.name, "Master Playback Volume")) - ctl->tlv.p = chip->model->dac_tlv; - else if (chip->model->cd_in_from_video_in && - !strncmp(ctl->id.name, "CD Capture ", 11)) - ctl->private_value ^= AC97_CD ^ AC97_VIDEO; err = snd_ctl_add(chip->card, ctl); if (err < 0) return err; -- cgit v1.2.1 From e0059549345903195d6eb796c22048204c40a785 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Jan 2008 09:18:32 +0100 Subject: [ALSA] oxygen: fix playback routing The default playback routing must be 0xe4, not 0xe1; the front and surround DACs were exchanged. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index fae7c0f060a0..6fd2a594e89e 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -121,7 +121,7 @@ static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) void oxygen_update_dac_routing(struct oxygen *chip) { static const unsigned int reg_values[3] = { - 0xe100, /* front <- 0, surround <- 1, center <- 2, back <- 3 */ + 0xe400, /* front <- 0, surround <- 1, center <- 2, back <- 3 */ 0xe000, /* front <- 0, surround <- 0, center <- 2, back <- 3 */ 0x2000 /* front <- 0, surround <- 0, center <- 2, back <- 0 */ }; @@ -135,7 +135,7 @@ void oxygen_update_dac_routing(struct oxygen *chip) else if (channels == OXYGEN_PLAY_CHANNELS_8) reg_value = 0x6c00; /* surround <- 3, back <- 1 */ else - reg_value = 0xe100; + reg_value = 0xe400; oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value, 0xff00); } -- cgit v1.2.1 From c9946b2c807aa2e6829765accc267415a893f74a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 21 Jan 2008 08:44:24 +0100 Subject: [ALSA] oxygen: remove magic numbers Replace some magic numbers with register symbols. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 42 +++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 6fd2a594e89e..d23d18aed25c 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -120,10 +120,23 @@ static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) void oxygen_update_dac_routing(struct oxygen *chip) { + /* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */ static const unsigned int reg_values[3] = { - 0xe400, /* front <- 0, surround <- 1, center <- 2, back <- 3 */ - 0xe000, /* front <- 0, surround <- 0, center <- 2, back <- 3 */ - 0x2000 /* front <- 0, surround <- 0, center <- 2, back <- 0 */ + /* stereo -> front */ + (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | + (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | + (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | + (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), + /* stereo -> front+surround */ + (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | + (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | + (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), + /* stereo -> front+surround+back */ + (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | + (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), }; u8 channels; unsigned int reg_value; @@ -133,10 +146,21 @@ void oxygen_update_dac_routing(struct oxygen *chip) if (channels == OXYGEN_PLAY_CHANNELS_2) reg_value = reg_values[chip->dac_routing]; else if (channels == OXYGEN_PLAY_CHANNELS_8) - reg_value = 0x6c00; /* surround <- 3, back <- 1 */ + /* in 7.1 mode, "rear" channels go to the "back" jack */ + reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | + (3 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | + (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | + (1 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT); else - reg_value = 0xe400; - oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value, 0xff00); + reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | + (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | + (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | + (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT); + oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value, + OXYGEN_PLAY_DAC0_SOURCE_MASK | + OXYGEN_PLAY_DAC1_SOURCE_MASK | + OXYGEN_PLAY_DAC2_SOURCE_MASK | + OXYGEN_PLAY_DAC3_SOURCE_MASK); } static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) @@ -199,13 +223,15 @@ void oxygen_update_spdif_source(struct oxygen *chip) old_routing = oxygen_read16(chip, OXYGEN_PLAY_ROUTING); if (chip->pcm_active & (1 << PCM_SPDIF)) { new_control = old_control | OXYGEN_SPDIF_OUT_ENABLE; - new_routing = (old_routing & ~0x00e0) | 0x0000; + new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK) + | OXYGEN_PLAY_SPDIF_SPDIF; oxygen_rate = (old_control >> OXYGEN_SPDIF_OUT_RATE_SHIFT) & OXYGEN_I2S_RATE_MASK; /* S/PDIF rate was already set by the caller */ } else if ((chip->pcm_active & (1 << PCM_MULTICH)) && chip->spdif_playback_enable) { - new_routing = (old_routing & ~0x00e0) | 0x0020; + new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK) + | OXYGEN_PLAY_SPDIF_MULTICH_01; oxygen_rate = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT) & OXYGEN_I2S_RATE_MASK; new_control = (old_control & ~OXYGEN_SPDIF_OUT_RATE_MASK) | -- cgit v1.2.1 From 878ac3ee76a5abb4952396570207f6ebe0597e52 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 21 Jan 2008 08:50:19 +0100 Subject: [ALSA] oxygen: add more symbols Add symbol definitions for the various codecs and GPIO pins. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index d23d18aed25c..11114cedc05d 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -23,6 +23,7 @@ #include #include #include "oxygen.h" +#include "cm9780.h" static int dac_volume_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) @@ -460,8 +461,9 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, if (change) { oxygen_write_ac97(chip, 0, index, newreg); if (index == AC97_LINE) { - oxygen_write_ac97_masked(chip, 0, 0x72, - !!(newreg & 0x8000), 0x0001); + oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS, + newreg & 0x8000 ? + CM9780_GPO0 : 0, CM9780_GPO0); if (!(newreg & 0x8000)) { ac97_mute_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH); ac97_mute_ctl(chip, CONTROL_CD_CAPTURE_SWITCH); @@ -471,7 +473,8 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, index == AC97_VIDEO || index == AC97_AUX) && bitnr == 15 && !(newreg & 0x8000)) { ac97_mute_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH); - oxygen_write_ac97_masked(chip, 0, 0x72, 0x0001, 0x0001); + oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS, + CM9780_GPO0, CM9780_GPO0); } } mutex_unlock(&chip->mutex); -- cgit v1.2.1 From e9d88a8bd9fb85d2a4a0adb89c47dcae437fa308 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 21 Jan 2008 08:52:11 +0100 Subject: [ALSA] oxygen: fix control filter Actually use the template that was maybe changed by the control filter instead of the original one. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 11114cedc05d..0993c29e62f1 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -667,7 +667,7 @@ static int add_controls(struct oxygen *chip, err = chip->model->control_filter(&template); if (err < 0) return err; - ctl = snd_ctl_new1(&controls[i], chip); + ctl = snd_ctl_new1(&template, chip); if (!ctl) return -ENOMEM; err = snd_ctl_add(chip->card, ctl); -- cgit v1.2.1 From 02f21c9d6ba863aa86c33e1335cb1307322f7fb8 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 22 Jan 2008 08:36:03 +0100 Subject: [ALSA] oxygen: add SPDIF loopback control Add a mixer control for the SPDIF loopback function. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 0993c29e62f1..6b7420fdd026 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -408,6 +408,37 @@ static int spdif_input_default_get(struct snd_kcontrol *ctl, return 0; } +static int spdif_loopback_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + + value->value.integer.value[0] = + !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) + & OXYGEN_SPDIF_LOOPBACK); + return 0; +} + +static int spdif_loopback_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u32 oldreg, newreg; + int changed; + + spin_lock_irq(&chip->reg_lock); + oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); + if (value->value.integer.value[0]) + newreg = oldreg | OXYGEN_SPDIF_LOOPBACK; + else + newreg = oldreg & ~OXYGEN_SPDIF_LOOPBACK; + changed = newreg != oldreg; + if (changed) + oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg); + spin_unlock_irq(&chip->reg_lock); + return changed; +} + static int ac97_switch_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { @@ -620,6 +651,13 @@ static const struct snd_kcontrol_new controls[] = { .info = spdif_info, .get = spdif_input_default_get, }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH), + .info = snd_ctl_boolean_mono_info, + .get = spdif_loopback_get, + .put = spdif_loopback_put, + }, }; static const struct snd_kcontrol_new ac97_controls[] = { -- cgit v1.2.1 From 976cd62700ae378df330ec82112da3d17e33a0fe Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 25 Jan 2008 08:37:49 +0100 Subject: [ALSA] oxygen: make the number of analog output configurable Add a field to struct oxygen_model to allow model drivers for cards with less than eight output channels. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 6b7420fdd026..21b227a94ace 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -28,8 +28,10 @@ static int dac_volume_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { + struct oxygen *chip = ctl->private_data; + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 8; + info->count = chip->model->dac_channels; info->value.integer.min = 0; info->value.integer.max = 0xff; return 0; @@ -42,7 +44,7 @@ static int dac_volume_get(struct snd_kcontrol *ctl, unsigned int i; mutex_lock(&chip->mutex); - for (i = 0; i < 8; ++i) + for (i = 0; i < chip->model->dac_channels; ++i) value->value.integer.value[i] = chip->dac_volume[i]; mutex_unlock(&chip->mutex); return 0; @@ -57,7 +59,7 @@ static int dac_volume_put(struct snd_kcontrol *ctl, changed = 0; mutex_lock(&chip->mutex); - for (i = 0; i < 8; ++i) + for (i = 0; i < chip->model->dac_channels; ++i) if (value->value.integer.value[i] != chip->dac_volume[i]) { chip->dac_volume[i] = value->value.integer.value[i]; changed = 1; @@ -100,11 +102,14 @@ static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) static const char *const names[3] = { "Front", "Front+Surround", "Front+Surround+Back" }; + struct oxygen *chip = ctl->private_data; + unsigned int count = 2 + (chip->model->dac_channels == 8); + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item > 2) - info->value.enumerated.item = 2; + info->value.enumerated.items = count; + if (info->value.enumerated.item >= count) + info->value.enumerated.item = count - 1; strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); return 0; } @@ -167,12 +172,14 @@ void oxygen_update_dac_routing(struct oxygen *chip) static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; + unsigned int count = 2 + (chip->model->dac_channels == 8); int changed; mutex_lock(&chip->mutex); changed = value->value.enumerated.item[0] != chip->dac_routing; if (changed) { - chip->dac_routing = min(value->value.enumerated.item[0], 2u); + chip->dac_routing = min(value->value.enumerated.item[0], + count - 1); spin_lock_irq(&chip->reg_lock); oxygen_update_dac_routing(chip); spin_unlock_irq(&chip->reg_lock); -- cgit v1.2.1 From c626026dd72ec8363aaa862178adeacfa7ac09c5 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 25 Jan 2008 08:41:52 +0100 Subject: [ALSA] add TempoTec HiFier driver Add a driver for the MediaTek/TempoTec HiFier Fantasia sound card. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 21b227a94ace..fe53318e94e0 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -712,6 +712,8 @@ static int add_controls(struct oxygen *chip, err = chip->model->control_filter(&template); if (err < 0) return err; + if (err == 1) + continue; ctl = snd_ctl_new1(&template, chip); if (!ctl) return -ENOMEM; -- cgit v1.2.1 From 911b499af45e879ccf4b8db234278a7136d056c9 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Jan 2008 08:33:44 +0100 Subject: [ALSA] oxygen: make line-in exclusive only on Xonar Move the line input switching code to the Virtuoso driver because only the Xonar cards bypass the analog mixer for line input. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index fe53318e94e0..cf34b1229b0b 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -465,19 +465,6 @@ static int ac97_switch_get(struct snd_kcontrol *ctl, return 0; } -static void ac97_mute_ctl(struct oxygen *chip, unsigned int control) -{ - unsigned int index = chip->controls[control]->private_value & 0xff; - u16 value; - - value = oxygen_read_ac97(chip, 0, index); - if (!(value & 0x8000)) { - oxygen_write_ac97(chip, 0, index, value | 0x8000); - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, - &chip->controls[control]->id); - } -} - static int ac97_switch_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { @@ -498,22 +485,9 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, change = newreg != oldreg; if (change) { oxygen_write_ac97(chip, 0, index, newreg); - if (index == AC97_LINE) { - oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS, - newreg & 0x8000 ? - CM9780_GPO0 : 0, CM9780_GPO0); - if (!(newreg & 0x8000)) { - ac97_mute_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH); - ac97_mute_ctl(chip, CONTROL_CD_CAPTURE_SWITCH); - ac97_mute_ctl(chip, CONTROL_AUX_CAPTURE_SWITCH); - } - } else if ((index == AC97_MIC || index == AC97_CD || - index == AC97_VIDEO || index == AC97_AUX) && - bitnr == 15 && !(newreg & 0x8000)) { - ac97_mute_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH); - oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS, - CM9780_GPO0, CM9780_GPO0); - } + if (bitnr == 15 && chip->model->ac97_switch_hook) + chip->model->ac97_switch_hook(chip, index, + newreg & 0x8000); } mutex_unlock(&chip->mutex); return change; @@ -671,6 +645,7 @@ static const struct snd_kcontrol_new ac97_controls[] = { AC97_VOLUME("Mic Capture Volume", AC97_MIC), AC97_SWITCH("Mic Capture Switch", AC97_MIC, 15, 1), AC97_SWITCH("Mic Boost (+20dB)", AC97_MIC, 6, 0), + AC97_VOLUME("Line Capture Volume", AC97_LINE), AC97_SWITCH("Line Capture Switch", AC97_LINE, 15, 1), AC97_VOLUME("CD Capture Volume", AC97_CD), AC97_SWITCH("CD Capture Switch", AC97_CD, 15, 1), -- cgit v1.2.1 From a3601560496d7b46d2d1187169824d11570ff63a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Jan 2008 08:35:20 +0100 Subject: [ALSA] oxygen: add front panel controls Add mixer controls for the front panel AC97 codec. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/oxygen_mixer.c | 117 ++++++++++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 22 deletions(-) (limited to 'sound/pci/oxygen/oxygen_mixer.c') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index cf34b1229b0b..a8e4623415d9 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -450,13 +450,14 @@ static int ac97_switch_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; + unsigned int codec = (ctl->private_value >> 24) & 1; unsigned int index = ctl->private_value & 0xff; unsigned int bitnr = (ctl->private_value >> 8) & 0xff; int invert = ctl->private_value & (1 << 16); u16 reg; mutex_lock(&chip->mutex); - reg = oxygen_read_ac97(chip, 0, index); + reg = oxygen_read_ac97(chip, codec, index); mutex_unlock(&chip->mutex); if (!(reg & (1 << bitnr)) ^ !invert) value->value.integer.value[0] = 1; @@ -469,6 +470,7 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; + unsigned int codec = (ctl->private_value >> 24) & 1; unsigned int index = ctl->private_value & 0xff; unsigned int bitnr = (ctl->private_value >> 8) & 0xff; int invert = ctl->private_value & (1 << 16); @@ -476,7 +478,7 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, int change; mutex_lock(&chip->mutex); - oldreg = oxygen_read_ac97(chip, 0, index); + oldreg = oxygen_read_ac97(chip, codec, index); newreg = oldreg; if (!value->value.integer.value[0] ^ !invert) newreg |= 1 << bitnr; @@ -484,9 +486,9 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, newreg &= ~(1 << bitnr); change = newreg != oldreg; if (change) { - oxygen_write_ac97(chip, 0, index, newreg); + oxygen_write_ac97(chip, codec, index, newreg); if (bitnr == 15 && chip->model->ac97_switch_hook) - chip->model->ac97_switch_hook(chip, index, + chip->model->ac97_switch_hook(chip, codec, index, newreg & 0x8000); } mutex_unlock(&chip->mutex); @@ -507,11 +509,12 @@ static int ac97_volume_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; - unsigned int index = ctl->private_value; + unsigned int codec = (ctl->private_value >> 24) & 1; + unsigned int index = ctl->private_value & 0xff; u16 reg; mutex_lock(&chip->mutex); - reg = oxygen_read_ac97(chip, 0, index); + reg = oxygen_read_ac97(chip, codec, index); mutex_unlock(&chip->mutex); value->value.integer.value[0] = 31 - (reg & 0x1f); value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f); @@ -522,12 +525,13 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; - unsigned int index = ctl->private_value; + unsigned int codec = (ctl->private_value >> 24) & 1; + unsigned int index = ctl->private_value & 0xff; u16 oldreg, newreg; int change; mutex_lock(&chip->mutex); - oldreg = oxygen_read_ac97(chip, 0, index); + oldreg = oxygen_read_ac97(chip, codec, index); newreg = oldreg; newreg = (newreg & ~0x1f) | (31 - (value->value.integer.value[0] & 0x1f)); @@ -535,30 +539,77 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, ((31 - (value->value.integer.value[0] & 0x1f)) << 8); change = newreg != oldreg; if (change) - oxygen_write_ac97(chip, 0, index, newreg); + oxygen_write_ac97(chip, codec, index, newreg); mutex_unlock(&chip->mutex); return change; } -#define AC97_SWITCH(xname, index, bitnr, invert) { \ +static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 2; + info->value.integer.min = 0; + info->value.integer.max = 7; + return 0; +} + +static int ac97_fp_rec_volume_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 reg; + + mutex_lock(&chip->mutex); + reg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); + mutex_unlock(&chip->mutex); + value->value.integer.value[0] = reg & 7; + value->value.integer.value[1] = (reg >> 8) & 7; + return 0; +} + +static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 oldreg, newreg; + int change; + + mutex_lock(&chip->mutex); + oldreg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); + newreg = oldreg & ~0x0707; + newreg = newreg | (value->value.integer.value[0] & 7); + newreg = newreg | ((value->value.integer.value[0] & 7) << 8); + change = newreg != oldreg; + if (change) + oxygen_write_ac97(chip, 1, AC97_REC_GAIN, newreg); + mutex_unlock(&chip->mutex); + return change; +} + +#define AC97_SWITCH(xname, codec, index, bitnr, invert) { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ .info = snd_ctl_boolean_mono_info, \ .get = ac97_switch_get, \ .put = ac97_switch_put, \ - .private_value = ((invert) << 16) | ((bitnr) << 8) | (index), \ + .private_value = ((codec) << 24) | ((invert) << 16) | \ + ((bitnr) << 8) | (index), \ } -#define AC97_VOLUME(xname, index) { \ +#define AC97_VOLUME(xname, codec, index) { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .info = ac97_volume_info, \ .get = ac97_volume_get, \ .put = ac97_volume_put, \ .tlv = { .p = ac97_db_scale, }, \ - .private_value = (index), \ + .private_value = ((codec) << 24) | (index), \ } static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); +static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); static const struct snd_kcontrol_new controls[] = { { @@ -642,15 +693,31 @@ static const struct snd_kcontrol_new controls[] = { }; static const struct snd_kcontrol_new ac97_controls[] = { - AC97_VOLUME("Mic Capture Volume", AC97_MIC), - AC97_SWITCH("Mic Capture Switch", AC97_MIC, 15, 1), - AC97_SWITCH("Mic Boost (+20dB)", AC97_MIC, 6, 0), - AC97_VOLUME("Line Capture Volume", AC97_LINE), - AC97_SWITCH("Line Capture Switch", AC97_LINE, 15, 1), - AC97_VOLUME("CD Capture Volume", AC97_CD), - AC97_SWITCH("CD Capture Switch", AC97_CD, 15, 1), - AC97_VOLUME("Aux Capture Volume", AC97_AUX), - AC97_SWITCH("Aux Capture Switch", AC97_AUX, 15, 1), + AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC), + AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), + AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), + AC97_VOLUME("Line Capture Volume", 0, AC97_LINE), + AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), + AC97_VOLUME("CD Capture Volume", 0, AC97_CD), + AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), + AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX), + AC97_SWITCH("Aux Capture Switch", 0, AC97_AUX, 15, 1), +}; + +static const struct snd_kcontrol_new ac97_fp_controls[] = { + AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE), + AC97_SWITCH("Front Panel Playback Switch", 1, AC97_HEADPHONE, 15, 1), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Front Panel Capture Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = ac97_fp_rec_volume_info, + .get = ac97_fp_rec_volume_get, + .put = ac97_fp_rec_volume_put, + .tlv = { .p = ac97_rec_db_scale, }, + }, + AC97_SWITCH("Front Panel Capture Switch", 1, AC97_REC_GAIN, 15, 1), }; static void oxygen_any_ctl_free(struct snd_kcontrol *ctl) @@ -717,5 +784,11 @@ int oxygen_mixer_init(struct oxygen *chip) if (err < 0) return err; } + if (chip->has_ac97_1) { + err = add_controls(chip, ac97_fp_controls, + ARRAY_SIZE(ac97_fp_controls)); + if (err < 0) + return err; + } return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0; } -- cgit v1.2.1