ALSA: virtuoso: fix front panel routing for D1/DX/ST(X)
authorClemens Ladisch <clemens@ladisch.de>
Thu, 2 Dec 2010 10:39:34 +0000 (11:39 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 6 Dec 2010 13:48:08 +0000 (14:48 +0100)
The "Front Panel" switch on the Xonar D1/DX actually switches only the
output direction, so mark it appropriately.

The front panel microphone is controlled by the FMIC2MIC bit of the
CM9780.  It was unconditionally enabled on the D1/DX and never set on
the ST(X); add a control for it.  Selecting the front panel microphone
as source does not actually disable the microphone jack, but this is
bug-compatible with the Windows driver, and users rely on it.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_mixer.c
sound/pci/oxygen/xonar_cs43xx.c
sound/pci/oxygen/xonar_pcm179x.c

index 7d5222caa0a92e5ca844269e02253fed98cfba98..cf9054ecb97b8566e66b3b9ba7d5f055c539aca0 100644 (file)
@@ -35,6 +35,7 @@
 #define MIDI_OUTPUT            0x0800
 #define MIDI_INPUT             0x1000
 #define AC97_CD_INPUT          0x2000
+#define AC97_FMIC_SWITCH       0x4000
 
 enum {
        CONTROL_SPDIF_PCM,
index 2849b36f5f7e72100c1691414cb6279e17f5d1ce..605e84b9e1ecbaea1820103ec53e87c8e7b10c6b 100644 (file)
@@ -644,6 +644,51 @@ static int ac97_volume_put(struct snd_kcontrol *ctl,
        return change;
 }
 
+static int mic_fmic_source_info(struct snd_kcontrol *ctl,
+                          struct snd_ctl_elem_info *info)
+{
+       static const char *const names[] = { "Mic Jack", "Front Panel" };
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 2;
+       info->value.enumerated.item &= 1;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int mic_fmic_source_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] =
+               !!(oxygen_read_ac97(chip, 0, CM9780_JACK) & CM9780_FMIC2MIC);
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int mic_fmic_source_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, 0, CM9780_JACK);
+       if (value->value.enumerated.item[0])
+               newreg = oldreg | CM9780_FMIC2MIC;
+       else
+               newreg = oldreg & ~CM9780_FMIC2MIC;
+       change = newreg != oldreg;
+       if (change)
+               oxygen_write_ac97(chip, 0, CM9780_JACK, newreg);
+       mutex_unlock(&chip->mutex);
+       return change;
+}
+
 static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl,
                                   struct snd_ctl_elem_info *info)
 {
@@ -908,6 +953,13 @@ static const struct snd_kcontrol_new ac97_controls[] = {
        AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0),
        AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1),
        AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Mic Source Capture Enum",
+               .info = mic_fmic_source_info,
+               .get = mic_fmic_source_get,
+               .put = mic_fmic_source_put,
+       },
        AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1),
        AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1),
        AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1),
@@ -972,6 +1024,9 @@ static int add_controls(struct oxygen *chip,
                if (!strcmp(template.name, "Stereo Upmixing") &&
                    chip->model.dac_channels == 2)
                        continue;
+               if (!strcmp(template.name, "Mic Source Capture Enum") &&
+                   !(chip->model.device_config & AC97_FMIC_SWITCH))
+                       continue;
                if (!strncmp(template.name, "CD Capture ", 11) &&
                    !(chip->model.device_config & AC97_CD_INPUT))
                        continue;
index ae4e5b51248344c7e1f66a2849cf9bbe44ac169a..501fe45bbdce80a0287e870d8ba463c8d699a802 100644 (file)
@@ -28,7 +28,7 @@
  * GPI 0 <- external power present (DX only)
  *
  * GPIO 0 -> enable output to speakers
- * GPIO 1 -> enable front panel I/O
+ * GPIO 1 -> route output to front panel
  * GPIO 2 -> M0 of CS5361
  * GPIO 3 -> M1 of CS5361
  * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
@@ -176,8 +176,6 @@ static void xonar_d1_init(struct oxygen *chip)
        oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
                            GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE);
 
-       oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
-
        xonar_init_cs53x1(chip);
        xonar_enable_output(chip);
 
@@ -287,7 +285,7 @@ static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed)
 
 static const struct snd_kcontrol_new front_panel_switch = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Front Panel Switch",
+       .name = "Front Panel Playback Switch",
        .info = snd_ctl_boolean_mono_info,
        .get = xonar_gpio_bit_switch_get,
        .put = xonar_gpio_bit_switch_put,
@@ -402,7 +400,8 @@ static const struct oxygen_model model_xonar_d1 = {
        .model_data_size = sizeof(struct xonar_cs43xx),
        .device_config = PLAYBACK_0_TO_I2S |
                         PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_2,
+                        CAPTURE_0_FROM_I2S_2 |
+                        AC97_FMIC_SWITCH,
        .dac_channels = 8,
        .dac_volume_min = 127 - 60,
        .dac_volume_max = 127,
index 3850834f989c64558d99ba4e70a5f8ab4a423544..5193d73a916dbb5b2a9bae90b64df5a64b433bd1 100644 (file)
@@ -1079,7 +1079,8 @@ static const struct oxygen_model model_xonar_st = {
        .model_data_size = sizeof(struct xonar_pcm179x),
        .device_config = PLAYBACK_0_TO_I2S |
                         PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_2,
+                        CAPTURE_0_FROM_I2S_2 |
+                        AC97_FMIC_SWITCH,
        .dac_channels = 2,
        .dac_volume_min = 255 - 2*60,
        .dac_volume_max = 255,