diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index bd615dbffadb..2ac3b3c8253f 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -84,6 +84,7 @@ struct oxygen_model { struct snd_pcm_hw_params *params); void (*update_dac_volume)(struct oxygen *chip); void (*update_dac_mute)(struct oxygen *chip); + void (*update_center_lfe_mix)(struct oxygen *chip, bool mixed); void (*gpio_changed)(struct oxygen *chip); void (*uart_input)(struct oxygen *chip); void (*ac97_switch)(struct oxygen *chip, diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index e8e911a86c8e..5dfb5fb73381 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -99,11 +99,15 @@ 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+Surround", "Front+Surround+Back" + static const char *const names[5] = { + "Front", + "Front+Surround", + "Front+Surround+Back", + "Front+Surround+Center/LFE", + "Front+Surround+Center/LFE+Back", }; struct oxygen *chip = ctl->private_data; - unsigned int count = 2 + (chip->model.dac_channels == 8); + unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3; info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; info->count = 1; @@ -127,7 +131,7 @@ 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] = { + static const unsigned int reg_values[5] = { /* stereo -> front */ (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | @@ -143,6 +147,16 @@ void oxygen_update_dac_routing(struct oxygen *chip) (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), + /* stereo -> front+surround+center/LFE */ + (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | + (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), + /* stereo -> front+surround+center/LFE+back */ + (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), }; u8 channels; unsigned int reg_value; @@ -167,22 +181,23 @@ void oxygen_update_dac_routing(struct oxygen *chip) OXYGEN_PLAY_DAC1_SOURCE_MASK | OXYGEN_PLAY_DAC2_SOURCE_MASK | OXYGEN_PLAY_DAC3_SOURCE_MASK); + if (chip->model.update_center_lfe_mix) + chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2); } 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); + unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3; int changed; + if (value->value.enumerated.item[0] >= count) + return -EINVAL; mutex_lock(&chip->mutex); changed = value->value.enumerated.item[0] != chip->dac_routing; if (changed) { - chip->dac_routing = min(value->value.enumerated.item[0], - count - 1); - spin_lock_irq(&chip->reg_lock); + chip->dac_routing = value->value.enumerated.item[0]; oxygen_update_dac_routing(chip); - spin_unlock_irq(&chip->reg_lock); } mutex_unlock(&chip->mutex); return changed; diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index ef2345d82b86..1e98333366df 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -435,6 +435,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; + mutex_lock(&chip->mutex); spin_lock_irq(&chip->reg_lock); oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, OXYGEN_SPDIF_OUT_ENABLE); @@ -446,6 +447,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream, OXYGEN_SPDIF_OUT_RATE_MASK); oxygen_update_spdif_source(chip); spin_unlock_irq(&chip->reg_lock); + mutex_unlock(&chip->mutex); return 0; } @@ -459,6 +461,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; + mutex_lock(&chip->mutex); spin_lock_irq(&chip->reg_lock); oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS, oxygen_play_channels(hw_params), @@ -475,12 +478,11 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, OXYGEN_I2S_FORMAT_MASK | OXYGEN_I2S_MCLK_MASK | OXYGEN_I2S_BITS_MASK); - oxygen_update_dac_routing(chip); oxygen_update_spdif_source(chip); spin_unlock_irq(&chip->reg_lock); - mutex_lock(&chip->mutex); chip->model.set_dac_params(chip, hw_params); + oxygen_update_dac_routing(chip); mutex_unlock(&chip->mutex); return 0; } diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 8fb5797577dd..0fa05ed6681d 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -67,6 +67,7 @@ struct xonar_cs43xx { struct xonar_generic generic; u8 cs4398_fm; u8 cs4362a_fm; + u8 cs4362a_fm_c; }; static void cs4398_write(struct oxygen *chip, u8 reg, u8 value) @@ -128,7 +129,7 @@ static void cs43xx_init(struct oxygen *chip) cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); cs4362a_write(chip, 0x05, 0); cs4362a_write(chip, 0x06, data->cs4362a_fm); - cs4362a_write(chip, 0x09, data->cs4362a_fm); + cs4362a_write(chip, 0x09, data->cs4362a_fm_c); cs4362a_write(chip, 0x0c, data->cs4362a_fm); update_cs43xx_volume(chip); update_cs43xx_mute(chip); @@ -146,6 +147,7 @@ static void xonar_d1_init(struct oxygen *chip) data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; data->cs4362a_fm = CS4362A_FM_SINGLE | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; + data->cs4362a_fm_c = data->cs4362a_fm; oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, OXYGEN_2WIRE_LENGTH_8 | @@ -202,25 +204,41 @@ static void set_cs43xx_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { struct xonar_cs43xx *data = chip->model_data; + u8 cs4398_fm, cs4362a_fm; - data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST; - data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; if (params_rate(params) <= 50000) { - data->cs4398_fm |= CS4398_FM_SINGLE; - data->cs4362a_fm |= CS4362A_FM_SINGLE; + cs4398_fm = CS4398_FM_SINGLE; + cs4362a_fm = CS4362A_FM_SINGLE; } else if (params_rate(params) <= 100000) { - data->cs4398_fm |= CS4398_FM_DOUBLE; - data->cs4362a_fm |= CS4362A_FM_DOUBLE; + cs4398_fm = CS4398_FM_DOUBLE; + cs4362a_fm = CS4362A_FM_DOUBLE; } else { - data->cs4398_fm |= CS4398_FM_QUAD; - data->cs4362a_fm |= CS4362A_FM_QUAD; + cs4398_fm = CS4398_FM_QUAD; + cs4362a_fm = CS4362A_FM_QUAD; } + data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST | cs4398_fm; + data->cs4362a_fm = + (data->cs4362a_fm & ~CS4362A_FM_MASK) | cs4362a_fm; + data->cs4362a_fm_c = + (data->cs4362a_fm_c & ~CS4362A_FM_MASK) | cs4362a_fm; cs4398_write(chip, 2, data->cs4398_fm); cs4362a_write(chip, 0x06, data->cs4362a_fm); - cs4362a_write(chip, 0x09, data->cs4362a_fm); + cs4362a_write(chip, 0x09, data->cs4362a_fm_c); cs4362a_write(chip, 0x0c, data->cs4362a_fm); } +static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed) +{ + struct xonar_cs43xx *data = chip->model_data; + + data->cs4362a_fm_c &= ~CS4362A_ATAPI_MASK; + if (mixed) + data->cs4362a_fm_c |= CS4362A_ATAPI_B_LR | CS4362A_ATAPI_A_LR; + else + data->cs4362a_fm_c |= CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; + cs4362a_write(chip, 0x09, data->cs4362a_fm_c); +} + static const struct snd_kcontrol_new front_panel_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Front Panel Switch", @@ -269,6 +287,7 @@ static const struct oxygen_model model_xonar_d1 = { .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_cs43xx_volume, .update_dac_mute = update_cs43xx_mute, + .update_center_lfe_mix = update_cs43xx_center_lfe_mix, .ac97_switch = xonar_d1_line_mic_ac97_switch, .dac_tlv = cs4362a_db_scale, .model_data_size = sizeof(struct xonar_cs43xx),