[ALSA] virtuoso: correctly switch input jack on Xonar DX

When selecting the capture source on the Xonar DX, the input jack must
be routed to either the line input or the microphone input by setting a
GPIO pin.  This requires an additional callback so that the model driver
can hook into the toggling of AC97 switches.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index d53c18c..7efbf54 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -98,6 +98,8 @@
 	void (*update_dac_volume)(struct oxygen *chip);
 	void (*update_dac_mute)(struct oxygen *chip);
 	void (*gpio_changed)(struct oxygen *chip);
+	void (*ac97_switch)(struct oxygen *chip,
+			    unsigned int reg, unsigned int mute);
 	size_t model_data_size;
 	unsigned int pcm_dev_cfg;
 	u8 dac_channels;
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index 9a7c880..d0bef09 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -518,6 +518,8 @@
 	value = oxygen_read_ac97(chip, 0, priv_idx);
 	if (!(value & 0x8000)) {
 		oxygen_write_ac97(chip, 0, priv_idx, value | 0x8000);
+		if (chip->model->ac97_switch)
+			chip->model->ac97_switch(chip, priv_idx, 0x8000);
 		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
 			       &chip->controls[control]->id);
 	}
@@ -544,6 +546,8 @@
 	change = newreg != oldreg;
 	if (change) {
 		oxygen_write_ac97(chip, codec, index, newreg);
+		if (codec == 0 && chip->model->ac97_switch)
+			chip->model->ac97_switch(chip, index, newreg & 0x8000);
 		if (index == AC97_LINE) {
 			oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
 						 newreg & 0x8000 ?
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 1db4aa5..b678e2d 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -47,10 +47,10 @@
  * GPI 0 <- external power present
  *
  * GPIO 0 -> enable output to speakers
- * GPIO 1 -> ALT?
+ * GPIO 1 -> ?
  * GPIO 2 -> M0 of CS5361
  * GPIO 3 -> M1 of CS5361
- * GPIO 8 -> line-in/mic-in/digital-out switch?
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
  *
  * CS4398:
  *
@@ -120,7 +120,7 @@
 #define GPI_DX_EXT_POWER	0x01
 #define GPIO_DX_OUTPUT_ENABLE	0x0001
 #define GPIO_DX_UNKNOWN1	0x0002
-#define GPIO_DX_UNKNOWN2	0x0100
+#define GPIO_DX_INPUT_ROUTE	0x0100
 
 #define I2C_DEVICE_CS4398	0x9e	/* 10011, AD1=1, AD0=1, /W=0 */
 #define I2C_DEVICE_CS4362A	0x30	/* 001100, AD0=0, /W=0 */
@@ -267,7 +267,8 @@
 	cs4362a_write(chip, 0x01, CS4362A_CPEN);
 
 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
-			  GPIO_DX_UNKNOWN1 | GPIO_DX_UNKNOWN2);
+			  GPIO_DX_UNKNOWN1 | GPIO_DX_INPUT_ROUTE);
+	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DX_INPUT_ROUTE);
 
 	xonar_common_init(chip);
 
@@ -469,6 +470,18 @@
 	.put = alt_switch_put,
 };
 
+static void xonar_dx_ac97_switch(struct oxygen *chip,
+				 unsigned int reg, unsigned int mute)
+{
+	if (reg == AC97_LINE) {
+		spin_lock_irq(&chip->reg_lock);
+		oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+				      mute ? GPIO_DX_INPUT_ROUTE : 0,
+				      GPIO_DX_INPUT_ROUTE);
+		spin_unlock_irq(&chip->reg_lock);
+	}
+}
+
 static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -12000, 50, 0);
 static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -12700, 100, 0);
 
@@ -572,6 +585,7 @@
 		.update_dac_volume = update_cs43xx_volume,
 		.update_dac_mute = update_cs43xx_mute,
 		.gpio_changed = xonar_gpio_changed,
+		.ac97_switch = xonar_dx_ac97_switch,
 		.model_data_size = sizeof(struct xonar_data),
 		.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
 			       PLAYBACK_1_TO_SPDIF |