summary refs log tree commit diff
path: root/sound/pci
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/Kconfig17
-rw-r--r--sound/pci/au88x0/au88x0_mixer.c2
-rw-r--r--sound/pci/ca0106/ca0106.h5
-rw-r--r--sound/pci/ca0106/ca0106_main.c136
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c93
-rw-r--r--sound/pci/emu10k1/emumpu401.c2
-rw-r--r--sound/pci/ice1712/delta.c10
-rw-r--r--sound/pci/ice1712/delta.h4
-rw-r--r--sound/pci/ice1712/pontis.c6
-rw-r--r--sound/pci/ice1712/prodigy192.c2
-rw-r--r--sound/pci/oxygen/oxygen.c4
-rw-r--r--sound/pci/oxygen/oxygen.h1
-rw-r--r--sound/pci/oxygen/oxygen_lib.c55
-rw-r--r--sound/pci/oxygen/oxygen_mixer.c5
-rw-r--r--sound/pci/oxygen/oxygen_pcm.c12
-rw-r--r--sound/pci/oxygen/oxygen_regs.h10
-rw-r--r--sound/pci/oxygen/virtuoso.c5
-rw-r--r--sound/pci/oxygen/xonar_cs43xx.c8
-rw-r--r--sound/pci/oxygen/xonar_pcm179x.c29
-rw-r--r--sound/pci/oxygen/xonar_wm87x6.c121
-rw-r--r--sound/pci/rme96.c8
-rw-r--r--sound/pci/rme9652/hdsp.c8
22 files changed, 377 insertions, 166 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index e7a8cd058efb..12e34653b8a8 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -207,12 +207,12 @@ config SND_CMIPCI
 
 config SND_OXYGEN_LIB
         tristate
-	select SND_PCM
-	select SND_MPU401_UART
 
 config SND_OXYGEN
 	tristate "C-Media 8788 (Oxygen)"
 	select SND_OXYGEN_LIB
+	select SND_PCM
+	select SND_MPU401_UART
 	help
 	  Say Y here to include support for sound cards based on the
 	  C-Media CMI8788 (Oxygen HD Audio) chip:
@@ -581,6 +581,8 @@ config SND_HDSPM
 config SND_HIFIER
 	tristate "TempoTec HiFier Fantasia"
 	select SND_OXYGEN_LIB
+	select SND_PCM
+	select SND_MPU401_UART
 	help
 	  Say Y here to include support for the MediaTek/TempoTec HiFier
 	  Fantasia sound card.
@@ -815,14 +817,17 @@ config SND_VIA82XX_MODEM
 	  will be called snd-via82xx-modem.
 
 config SND_VIRTUOSO
-	tristate "Asus Virtuoso 100/200 (Xonar)"
+	tristate "Asus Virtuoso 66/100/200 (Xonar)"
 	select SND_OXYGEN_LIB
+	select SND_PCM
+	select SND_MPU401_UART
+	select SND_JACK if INPUT=y || INPUT=SND
 	help
 	  Say Y here to include support for sound cards based on the
-	  Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
+	  Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS,
 	  Essence ST (Deluxe), and Essence STX.
-	  Support for the DS is experimental.
-	  Support for the HDAV1.3 (Deluxe) is very experimental.
+	  Support for the HDAV1.3 (Deluxe) is incomplete; for the
+	  HDAV1.3 Slim and Xense, missing.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-virtuoso.
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c
index c92f493d341e..557c782ae4fc 100644
--- a/sound/pci/au88x0/au88x0_mixer.c
+++ b/sound/pci/au88x0/au88x0_mixer.c
@@ -23,7 +23,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex)
 	if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0)
 		return err;
 	memset(&ac97, 0, sizeof(ac97));
-	// Intialize AC97 codec stuff.
+	// Initialize AC97 codec stuff.
 	ac97.private_data = vortex;
 	ac97.scaps = AC97_SCAP_NO_SPDIF;
 	err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index 14b8d9a91aae..f19c11077255 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -670,8 +670,9 @@ struct snd_ca0106_details {
 			   gpio_type = 2 -> shared side-out/line-in. */
 	int i2c_adc;	/* with i2c_adc=1, the driver adds some capture volume
 			   controls, phone, mic, line-in and aux. */
-	int spi_dac;	/* spi_dac=1 adds the mute switch for each analog
-			   output, front, rear, etc. */
+	u16 spi_dac;	/* spi_dac = 0 -> no spi interface for DACs
+			   spi_dac = 0x<front><rear><center-lfe><side>
+			   -> specifies DAC id for each channel pair. */
 };
 
 // definition of the chip-specific record
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 0a3d3d6e77b4..d2d12c08f937 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -227,7 +227,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
 	   .name   = "Audigy SE [SB0570]",
 	   .gpio_type = 1,
 	   .i2c_adc = 1,
-	   .spi_dac = 1 } ,
+	   .spi_dac = 0x4021 } ,
 	 /* New Audigy LS. Has a different DAC. */
 	 /* SB0570:
 	  * CTRL:CA0106-DAT
@@ -238,7 +238,17 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
 	   .name   = "Audigy SE OEM [SB0570a]",
 	   .gpio_type = 1,
 	   .i2c_adc = 1,
-	   .spi_dac = 1 } ,
+	   .spi_dac = 0x4021 } ,
+	/* Sound Blaster 5.1vx
+	 * Tested: Playback on front, rear, center/lfe speakers
+	 * Not-Tested: Capture
+	 */
+	{ .serial = 0x10041102,
+	  .name   = "Sound Blaster 5.1vx [SB1070]",
+	  .gpio_type = 1,
+	  .i2c_adc = 0,
+	  .spi_dac = 0x0124
+	 } ,
 	 /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
 	 /* SB0438
 	  * CTRL:CA0106-DAT
@@ -254,7 +264,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
 	   .name   = "MSI K8N Diamond MB",
 	   .gpio_type = 2,
 	   .i2c_adc = 1,
-	   .spi_dac = 1 } ,
+	   .spi_dac = 0x4021 } ,
 	/* Giga-byte GA-G1975X mobo
 	 * Novell bnc#395807
 	 */
@@ -483,16 +493,18 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime)
 }
 
 static const int spi_dacd_reg[] = {
-	[PCM_FRONT_CHANNEL]	= SPI_DACD4_REG,
-	[PCM_REAR_CHANNEL]	= SPI_DACD0_REG,
-	[PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG,
-	[PCM_UNKNOWN_CHANNEL]	= SPI_DACD1_REG,
+	SPI_DACD0_REG,
+	SPI_DACD1_REG,
+	SPI_DACD2_REG,
+	0,
+	SPI_DACD4_REG,
 };
 static const int spi_dacd_bit[] = {
-	[PCM_FRONT_CHANNEL]	= SPI_DACD4_BIT,
-	[PCM_REAR_CHANNEL]	= SPI_DACD0_BIT,
-	[PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT,
-	[PCM_UNKNOWN_CHANNEL]	= SPI_DACD1_BIT,
+	SPI_DACD0_BIT,
+	SPI_DACD1_BIT,
+	SPI_DACD2_BIT,
+	0,
+	SPI_DACD4_BIT,
 };
 
 static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
@@ -504,6 +516,45 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
 	}
 }
 
+static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
+				  int channel_id)
+{
+	switch (channel_id) {
+	case PCM_FRONT_CHANNEL:
+		return (details->spi_dac & 0xf000) >> (4 * 3);
+	case PCM_REAR_CHANNEL:
+		return (details->spi_dac & 0x0f00) >> (4 * 2);
+	case PCM_CENTER_LFE_CHANNEL:
+		return (details->spi_dac & 0x00f0) >> (4 * 1);
+	case PCM_UNKNOWN_CHANNEL:
+		return (details->spi_dac & 0x000f) >> (4 * 0);
+	default:
+		snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n",
+			   channel_id);
+	}
+	return 0;
+}
+
+static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
+				    int power)
+{
+	if (chip->details->spi_dac) {
+		const int dac = snd_ca0106_channel_dac(chip->details,
+						       channel_id);
+		const int reg = spi_dacd_reg[dac];
+		const int bit = spi_dacd_bit[dac];
+
+		if (power)
+			/* Power up */
+			chip->spi_dac_reg[reg] &= ~bit;
+		else
+			/* Power down */
+			chip->spi_dac_reg[reg] |= bit;
+		return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+	}
+	return 0;
+}
+
 /* open_playback callback */
 static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
 						int channel_id)
@@ -543,12 +594,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
                 return err;
 	snd_pcm_set_sync(substream);
 
-	if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) {
-		const int reg = spi_dacd_reg[channel_id];
-
-		/* Power up dac */
-		chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id];
-		err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+	/* Front channel dac should already be on */
+	if (channel_id != PCM_FRONT_CHANNEL) {
+		err = snd_ca0106_pcm_power_dac(chip, channel_id, 1);
 		if (err < 0)
 			return err;
 	}
@@ -568,13 +616,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream)
 
 	restore_spdif_bits(chip, epcm->channel_id);
 
-	if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) {
-		const int reg = spi_dacd_reg[epcm->channel_id];
-
-		/* Power down DAC */
-		chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id];
-		snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+	/* Front channel dac should stay on */
+	if (epcm->channel_id != PCM_FRONT_CHANNEL) {
+		int err;
+		err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0);
+		if (err < 0)
+			return err;
 	}
+
 	/* FIXME: maybe zero others */
 	return 0;
 }
@@ -1002,29 +1051,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
 	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_ca0106_pcm *epcm = runtime->private_data;
-	snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;
+	unsigned int ptr, prev_ptr;
 	int channel = epcm->channel_id;
+	int timeout = 10;
 
 	if (!epcm->running)
 		return 0;
 
-	ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
-	ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
-	ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
-	if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
-	ptr2 = bytes_to_frames(runtime, ptr1);
-	ptr2+= (ptr4 >> 3) * runtime->period_size;
-	ptr=ptr2;
-        if (ptr >= runtime->buffer_size)
-		ptr -= runtime->buffer_size;
-	/*
-	printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
-	       "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
-	       ptr1, ptr2, ptr, (int)runtime->buffer_size,
-	       (int)runtime->period_size, (int)runtime->frame_bits,
-	       (int)runtime->rate);
-	*/
-	return ptr;
+	prev_ptr = -1;
+	do {
+		ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
+		ptr = (ptr >> 3) * runtime->period_size;
+		ptr += bytes_to_frames(runtime,
+			snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
+		if (ptr >= runtime->buffer_size)
+			ptr -= runtime->buffer_size;
+		if (prev_ptr == ptr)
+			return ptr;
+		prev_ptr = ptr;
+	} while (--timeout);
+	snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
+	return 0;
 }
 
 /* pointer_capture callback */
@@ -1362,7 +1409,7 @@ static unsigned int spi_dac_init[] = {
 	SPI_REG(12,		0x00),
 	SPI_REG(SPI_LDA4_REG,	SPI_DA_BIT_0dB),
 	SPI_REG(SPI_RDA4_REG,	SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE),
-	SPI_REG(SPI_DACD4_REG,	0x00),
+	SPI_REG(SPI_DACD4_REG,	SPI_DACD4_BIT),
 };
 
 static unsigned int i2c_adc_init[][2] = {
@@ -1541,7 +1588,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
 		/* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */
 	}
 
-	if (chip->details->spi_dac == 1) {
+	if (chip->details->spi_dac) {
 		/* The SB0570 use SPI to control DAC. */
 		int size, n;
 
@@ -1553,6 +1600,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
 			if (reg < ARRAY_SIZE(chip->spi_dac_reg))
 				chip->spi_dac_reg[reg] = spi_dac_init[n];
 		}
+
+		/* Enable front dac only */
+		snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1);
 	}
 }
 
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 85fd315d9999..630aa4998189 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -676,28 +676,65 @@ 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) | (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 const int spi_dmute_reg[] = {
+	SPI_DMUTE0_REG,
+	SPI_DMUTE1_REG,
+	SPI_DMUTE2_REG,
+	0,
+	SPI_DMUTE4_REG,
+};
+static const int spi_dmute_bit[] = {
+	SPI_DMUTE0_BIT,
+	SPI_DMUTE1_BIT,
+	SPI_DMUTE2_BIT,
+	0,
+	SPI_DMUTE4_BIT,
 };
 
+static struct snd_kcontrol_new __devinit
+snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details,
+			      int channel_id)
+{
+	struct snd_kcontrol_new spi_switch = {0};
+	int reg, bit;
+	int dac_id;
+
+	spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	spi_switch.info = spi_mute_info;
+	spi_switch.get = spi_mute_get;
+	spi_switch.put = spi_mute_put;
+
+	switch (channel_id) {
+	case PCM_FRONT_CHANNEL:
+		spi_switch.name = "Analog Front Playback Switch";
+		dac_id = (details->spi_dac & 0xf000) >> (4 * 3);
+		break;
+	case PCM_REAR_CHANNEL:
+		spi_switch.name = "Analog Rear Playback Switch";
+		dac_id = (details->spi_dac & 0x0f00) >> (4 * 2);
+		break;
+	case PCM_CENTER_LFE_CHANNEL:
+		spi_switch.name = "Analog Center/LFE Playback Switch";
+		dac_id = (details->spi_dac & 0x00f0) >> (4 * 1);
+		break;
+	case PCM_UNKNOWN_CHANNEL:
+		spi_switch.name = "Analog Side Playback Switch";
+		dac_id = (details->spi_dac & 0x000f) >> (4 * 0);
+		break;
+	default:
+		/* Unused channel */
+		spi_switch.name = NULL;
+		dac_id = 0;
+	}
+	reg = spi_dmute_reg[dac_id];
+	bit = spi_dmute_bit[dac_id];
+
+	spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit;
+
+	return spi_switch;
+}
+
 static int __devinit remove_ctl(struct snd_card *card, const char *name)
 {
 	struct snd_ctl_elem_id id;
@@ -832,8 +869,18 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
 		if (err < 0)
 			return err;
 	}
-	if (emu->details->spi_dac == 1)
-		ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls);
+	if (emu->details->spi_dac) {
+		int i;
+		for (i = 0;; i++) {
+			struct snd_kcontrol_new ctl;
+			ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i);
+			if (!ctl.name)
+				break;
+			err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu));
+			if (err < 0)
+				return err;
+		}
+	}
 
 	/* Create virtual master controls */
 	vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
@@ -845,7 +892,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
 		return err;
 	add_slaves(card, vmaster, slave_vols);
 
-	if (emu->details->spi_dac == 1) {
+	if (emu->details->spi_dac) {
 		vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
 						      NULL);
 		if (!vmaster)
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c
index 8578c70c61f2..bab564824efe 100644
--- a/sound/pci/emu10k1/emumpu401.c
+++ b/sound/pci/emu10k1/emumpu401.c
@@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input =
 
 static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
 {
-	struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data;
+	struct snd_emu10k1_midi *midi = rmidi->private_data;
 	midi->interrupt = NULL;
 	midi->rmidi = NULL;
 }
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index d216362626d0..712c1710f9a2 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -563,6 +563,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
 	case ICE1712_SUBDEVICE_DELTA1010E:
 	case ICE1712_SUBDEVICE_DELTA1010LT:
 	case ICE1712_SUBDEVICE_MEDIASTATION:
+	case ICE1712_SUBDEVICE_EDIROLDA2496:
 		ice->num_total_dacs = 8;
 		ice->num_total_adcs = 8;
 		break;
@@ -635,6 +636,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
 		err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice);
 		break;
 	case ICE1712_SUBDEVICE_DELTA1010LT:
+	case ICE1712_SUBDEVICE_EDIROLDA2496:
 		err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice);
 		break;
 	case ICE1712_SUBDEVICE_DELTA66:
@@ -734,6 +736,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice)
 	case ICE1712_SUBDEVICE_DELTA66:
 	case ICE1712_SUBDEVICE_VX442:
 	case ICE1712_SUBDEVICE_DELTA66E:
+	case ICE1712_SUBDEVICE_EDIROLDA2496:
 		err = snd_ice1712_akm4xxx_build_controls(ice);
 		if (err < 0)
 			return err;
@@ -813,5 +816,12 @@ struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
 		.chip_init = snd_ice1712_delta_init,
 		.build_controls = snd_ice1712_delta_add_controls,
 	},
+	{
+		.subvendor = ICE1712_SUBDEVICE_EDIROLDA2496,
+		.name = "Edirol DA2496",
+		.model = "da2496",
+		.chip_init = snd_ice1712_delta_init,
+		.build_controls = snd_ice1712_delta_add_controls,
+	},
 	{ } /* terminator */
 };
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index f7f14df81f26..1a0ac6cd6501 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -34,7 +34,8 @@
 		"{MidiMan M Audio,Delta 410},"\
 		"{MidiMan M Audio,Audiophile 24/96},"\
 		"{Digigram,VX442},"\
-		"{Lionstracs,Mediastation},"
+		"{Lionstracs,Mediastation},"\
+		"{Edirol,DA2496},"
 
 #define ICE1712_SUBDEVICE_DELTA1010	0x121430d6
 #define ICE1712_SUBDEVICE_DELTA1010E	0xff1430d6
@@ -47,6 +48,7 @@
 #define ICE1712_SUBDEVICE_DELTA1010LT	0x12143bd6
 #define ICE1712_SUBDEVICE_VX442		0x12143cd6
 #define ICE1712_SUBDEVICE_MEDIASTATION	0x694c0100
+#define ICE1712_SUBDEVICE_EDIROLDA2496	0xce164010
 
 /* entry point */
 extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 6bc3f91b7281..cdb873f5da50 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -638,7 +638,7 @@ static struct snd_kcontrol_new pontis_controls[] __devinitdata = {
  */
 static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-	struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+	struct snd_ice1712 *ice = entry->private_data;
 	char line[64];
 	unsigned int reg, val;
 	mutex_lock(&ice->gpio_mutex);
@@ -653,7 +653,7 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf
 
 static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-	struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+	struct snd_ice1712 *ice = entry->private_data;
 	int reg, val;
 
 	mutex_lock(&ice->gpio_mutex);
@@ -676,7 +676,7 @@ static void wm_proc_init(struct snd_ice1712 *ice)
 
 static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-	struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+	struct snd_ice1712 *ice = entry->private_data;
 	int reg, val;
 
 	mutex_lock(&ice->gpio_mutex);
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
index 2a8e5cd8f2d8..e36ddb94c382 100644
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -654,7 +654,7 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice)
 static void stac9460_proc_regs_read(struct snd_info_entry *entry,
 		struct snd_info_buffer *buffer)
 {
-	struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+	struct snd_ice1712 *ice = entry->private_data;
 	int reg, val;
 	/* registers 0x0 - 0x14 */
 	for (reg = 0; reg <= 0x15; reg++) {
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 6c0a11adb2a8..98a8eb3c92f7 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -79,6 +79,7 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
 	{ OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
 	{ OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
 	{ OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
+	{ OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF },
 	{ OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
 	{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
 	{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
@@ -505,7 +506,8 @@ static const struct oxygen_model model_generic = {
 			 PLAYBACK_2_TO_AC97_1 |
 			 CAPTURE_0_FROM_I2S_1 |
 			 CAPTURE_1_FROM_SPDIF |
-			 CAPTURE_2_FROM_AC97_1,
+			 CAPTURE_2_FROM_AC97_1 |
+			 AC97_CD_INPUT,
 	.dac_channels = 8,
 	.dac_volume_min = 0,
 	.dac_volume_max = 255,
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index a3409edcfb50..7d5222caa0a9 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -34,6 +34,7 @@
      /* CAPTURE_3_FROM_I2S_3		not implemented */
 #define MIDI_OUTPUT		0x0800
 #define MIDI_INPUT		0x1000
+#define AC97_CD_INPUT		0x2000
 
 enum {
 	CONTROL_SPDIF_PCM,
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 7e93cf884437..e5ebe56fb0c5 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -308,25 +308,46 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
 	}
 }
 
-static void pci_bridge_magic(void)
+static void configure_pcie_bridge(struct pci_dev *pci)
 {
-	struct pci_dev *pci = NULL;
+	enum { PEX811X, PI7C9X110 };
+	static const struct pci_device_id bridge_ids[] = {
+		{ PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X },
+		{ PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X },
+		{ PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 },
+		{ }
+	};
+	struct pci_dev *bridge;
+	const struct pci_device_id *id;
 	u32 tmp;
 
-	for (;;) {
-		/* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */
-		pci = pci_get_device(0x12d8, 0xe110, pci);
-		if (!pci)
-			break;
-		/*
-		 * ... configure its secondary internal arbiter to park to
-		 * the secondary port, instead of to the last master.
-		 */
-		if (!pci_read_config_dword(pci, 0x40, &tmp)) {
-			tmp |= 1;
-			pci_write_config_dword(pci, 0x40, tmp);
-		}
-		/* Why?  Try asking C-Media. */
+	if (!pci->bus || !pci->bus->self)
+		return;
+	bridge = pci->bus->self;
+
+	id = pci_match_id(bridge_ids, bridge);
+	if (!id)
+		return;
+
+	switch (id->driver_data) {
+	case PEX811X:	/* PLX PEX8111/PEX8112 PCIe/PCI bridge */
+		pci_read_config_dword(bridge, 0x48, &tmp);
+		tmp |= 1;	/* enable blind prefetching */
+		tmp |= 1 << 11;	/* enable beacon generation */
+		pci_write_config_dword(bridge, 0x48, tmp);
+
+		pci_write_config_dword(bridge, 0x84, 0x0c);
+		pci_read_config_dword(bridge, 0x88, &tmp);
+		tmp &= ~(7 << 27);
+		tmp |= 2 << 27;	/* set prefetch size to 128 bytes */
+		pci_write_config_dword(bridge, 0x88, tmp);
+		break;
+
+	case PI7C9X110:	/* Pericom PI7C9X110 PCIe/PCI bridge */
+		pci_read_config_dword(bridge, 0x40, &tmp);
+		tmp |= 1;	/* park the PCI arbiter to the sound chip */
+		pci_write_config_dword(bridge, 0x40, tmp);
+		break;
 	}
 }
 
@@ -613,7 +634,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
 	snd_card_set_dev(card, &pci->dev);
 	card->private_free = oxygen_card_free;
 
-	pci_bridge_magic();
+	configure_pcie_bridge(pci);
 	oxygen_init(chip);
 	chip->model.init(chip);
 
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index f375b8a27862..2849b36f5f7e 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -708,7 +708,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
 		.private_value = ((codec) << 24) | ((stereo) << 16) | (index), \
 	}
 
-static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0);
+static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0);
 static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0);
 static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0);
 
@@ -972,6 +972,9 @@ static int add_controls(struct oxygen *chip,
 		if (!strcmp(template.name, "Stereo Upmixing") &&
 		    chip->model.dac_channels == 2)
 			continue;
+		if (!strncmp(template.name, "CD Capture ", 11) &&
+		    !(chip->model.device_config & AC97_CD_INPUT))
+			continue;
 		if (!strcmp(template.name, "Master Playback Volume") &&
 		    chip->model.dac_tlv) {
 			template.tlv.p = chip->model.dac_tlv;
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index 9dff6954c397..814667442eb0 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -56,8 +56,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = {
 	.channels_max = 2,
 	.buffer_bytes_max = BUFFER_BYTES_MAX,
 	.period_bytes_min = PERIOD_BYTES_MIN,
-	.period_bytes_max = BUFFER_BYTES_MAX / 2,
-	.periods_min = 2,
+	.period_bytes_max = BUFFER_BYTES_MAX,
+	.periods_min = 1,
 	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
 };
 static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
@@ -82,8 +82,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
 	.channels_max = 8,
 	.buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH,
 	.period_bytes_min = PERIOD_BYTES_MIN,
-	.period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2,
-	.periods_min = 2,
+	.period_bytes_max = BUFFER_BYTES_MAX_MULTICH,
+	.periods_min = 1,
 	.periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN,
 };
 static const struct snd_pcm_hardware oxygen_ac97_hardware = {
@@ -100,8 +100,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = {
 	.channels_max = 2,
 	.buffer_bytes_max = BUFFER_BYTES_MAX,
 	.period_bytes_min = PERIOD_BYTES_MIN,
-	.period_bytes_max = BUFFER_BYTES_MAX / 2,
-	.periods_min = 2,
+	.period_bytes_max = BUFFER_BYTES_MAX,
+	.periods_min = 1,
 	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
 };
 
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h
index 72de159d4567..4dcd41b78258 100644
--- a/sound/pci/oxygen/oxygen_regs.h
+++ b/sound/pci/oxygen/oxygen_regs.h
@@ -436,13 +436,15 @@
 /* OXYGEN_CHANNEL_* */
 
 #define OXYGEN_CODEC_VERSION		0xe4
-#define  OXYGEN_XCID_MASK		0x07
+#define  OXYGEN_CODEC_ID_MASK		0x07
 
 #define OXYGEN_REVISION			0xe6
-#define  OXYGEN_REVISION_XPKGID_MASK	0x0007
+#define  OXYGEN_PACKAGE_ID_MASK		0x0007
+#define  OXYGEN_PACKAGE_ID_8786		0x0004
+#define  OXYGEN_PACKAGE_ID_8787		0x0006
+#define  OXYGEN_PACKAGE_ID_8788		0x0007
 #define  OXYGEN_REVISION_MASK		0xfff8
-#define  OXYGEN_REVISION_2		0x0008	/* bit flag */
-#define  OXYGEN_REVISION_8787		0x0014	/* 8 bits */
+#define  OXYGEN_REVISION_2		0x0008
 
 #define OXYGEN_OFFSIN_48K		0xe8
 #define OXYGEN_OFFSBASE_48K		0xe9
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 06c863e86e3d..469010a8b849 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -25,9 +25,9 @@
 #include "xonar.h"
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_DESCRIPTION("Asus AVx00 driver");
+MODULE_DESCRIPTION("Asus Virtuoso driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}");
+MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -49,6 +49,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = {
 	{ OXYGEN_PCI_SUBID(0x1043, 0x834f) },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x835c) },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x835d) },
+	{ OXYGEN_PCI_SUBID(0x1043, 0x835e) },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x838e) },
 	{ OXYGEN_PCI_SUBID_BROKEN_EEPROM },
 	{ }
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c
index 7c4986b27f2b..aa27c31049af 100644
--- a/sound/pci/oxygen/xonar_cs43xx.c
+++ b/sound/pci/oxygen/xonar_cs43xx.c
@@ -367,13 +367,6 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip,
 
 static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
 
-static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
-{
-	if (!strncmp(template->name, "CD Capture ", 11))
-		return 1; /* no CD input */
-	return 0;
-}
-
 static int xonar_d1_mixer_init(struct oxygen *chip)
 {
 	int err;
@@ -391,7 +384,6 @@ static const struct oxygen_model model_xonar_d1 = {
 	.longname = "Asus Virtuoso 100",
 	.chip = "AV200",
 	.init = xonar_d1_init,
-	.control_filter = xonar_d1_control_filter,
 	.mixer_init = xonar_d1_mixer_init,
 	.cleanup = xonar_d1_cleanup,
 	.suspend = xonar_d1_suspend,
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c
index ba18fb546b4f..d491fd6c0be2 100644
--- a/sound/pci/oxygen/xonar_pcm179x.c
+++ b/sound/pci/oxygen/xonar_pcm179x.c
@@ -132,6 +132,18 @@
  * GPIO 5 <- 0
  */
 
+/*
+ * Xonar HDAV1.3 Slim
+ * ------------------
+ *
+ * CMI8788:
+ *
+ * GPIO 1 -> enable output
+ *
+ * TXD -> HDMI controller
+ * RXD <- HDMI controller
+ */
+
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
@@ -362,7 +374,6 @@ static void xonar_st_init_common(struct oxygen *chip)
 {
 	struct xonar_pcm179x *data = chip->model_data;
 
-	data->generic.anti_pop_delay = 100;
 	data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
 	data->dacs = chip->model.private_data ? 4 : 1;
 	data->hp_gain_offset = 2*-18;
@@ -408,6 +419,7 @@ static void xonar_st_init(struct oxygen *chip)
 {
 	struct xonar_pcm179x *data = chip->model_data;
 
+	data->generic.anti_pop_delay = 100;
 	data->has_cs2000 = 1;
 	data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
 
@@ -428,6 +440,7 @@ static void xonar_stx_init(struct oxygen *chip)
 	struct xonar_pcm179x *data = chip->model_data;
 
 	xonar_st_init_i2c(chip);
+	data->generic.anti_pop_delay = 800;
 	data->generic.ext_power_reg = OXYGEN_GPI_DATA;
 	data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
 	data->generic.ext_power_bit = GPI_EXT_POWER;
@@ -915,13 +928,6 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
 	return 0;
 }
 
-static int xonar_st_control_filter(struct snd_kcontrol_new *template)
-{
-	if (!strncmp(template->name, "CD Capture ", 11))
-		return 1; /* no CD input */
-	return 0;
-}
-
 static int add_pcm1796_controls(struct oxygen *chip)
 {
 	int err;
@@ -991,7 +997,8 @@ static const struct oxygen_model model_xonar_d2 = {
 			 CAPTURE_0_FROM_I2S_2 |
 			 CAPTURE_1_FROM_SPDIF |
 			 MIDI_OUTPUT |
-			 MIDI_INPUT,
+			 MIDI_INPUT |
+			 AC97_CD_INPUT,
 	.dac_channels = 8,
 	.dac_volume_min = 255 - 2*60,
 	.dac_volume_max = 255,
@@ -1037,7 +1044,6 @@ static const struct oxygen_model model_xonar_st = {
 	.longname = "Asus Virtuoso 100",
 	.chip = "AV200",
 	.init = xonar_st_init,
-	.control_filter = xonar_st_control_filter,
 	.mixer_init = xonar_st_mixer_init,
 	.cleanup = xonar_st_cleanup,
 	.suspend = xonar_st_suspend,
@@ -1108,6 +1114,9 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
 		chip->model.resume = xonar_stx_resume;
 		chip->model.set_dac_params = set_pcm1796_params;
 		break;
+	case 0x835e:
+		snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n");
+		return -ENODEV;
 	default:
 		return -EINVAL;
 	}
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c
index b82c1cfa96f5..200f7601276f 100644
--- a/sound/pci/oxygen/xonar_wm87x6.c
+++ b/sound/pci/oxygen/xonar_wm87x6.c
@@ -25,16 +25,24 @@
  * SPI 0 -> WM8766 (surround, center/LFE, back)
  * SPI 1 -> WM8776 (front, input)
  *
- * GPIO 4 <- headphone detect
- * GPIO 6 -> route input jack to input 1/2 (1/0)
- * GPIO 7 -> enable output to speakers
- * GPIO 8 -> enable output to speakers
+ * GPIO 4 <- headphone detect, 0 = plugged
+ * GPIO 6 -> route input jack to mic-in (0) or line-in (1)
+ * GPIO 7 -> enable output to front L/R speaker channels
+ * GPIO 8 -> enable output to other speaker channels and front panel headphone
+ *
+ * WM8766:
+ *
+ * input 1 <- line
+ * input 2 <- mic
+ * input 3 <- front mic
+ * input 4 <- aux
  */
 
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <sound/control.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
@@ -44,7 +52,8 @@
 
 #define GPIO_DS_HP_DETECT	0x0010
 #define GPIO_DS_INPUT_ROUTE	0x0040
-#define GPIO_DS_OUTPUT_ENABLE	0x0180
+#define GPIO_DS_OUTPUT_FRONTLR	0x0080
+#define GPIO_DS_OUTPUT_ENABLE	0x0100
 
 #define LC_CONTROL_LIMITER	0x40000000
 #define LC_CONTROL_ALC		0x20000000
@@ -56,6 +65,7 @@ struct xonar_wm87x6 {
 	struct snd_kcontrol *line_adcmux_control;
 	struct snd_kcontrol *mic_adcmux_control;
 	struct snd_kcontrol *lc_controls[13];
+	struct snd_jack *hp_jack;
 };
 
 static void wm8776_write(struct oxygen *chip,
@@ -97,8 +107,12 @@ static void wm8766_write(struct oxygen *chip,
 			 (0 << OXYGEN_SPI_CODEC_SHIFT) |
 			 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
 			 (reg << 9) | value);
-	if (reg < ARRAY_SIZE(data->wm8766_regs))
+	if (reg < ARRAY_SIZE(data->wm8766_regs)) {
+		if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
+		    (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
+			value &= ~WM8766_UPDATE;
 		data->wm8766_regs[reg] = value;
+	}
 }
 
 static void wm8766_write_cached(struct oxygen *chip,
@@ -107,12 +121,8 @@ static void wm8766_write_cached(struct oxygen *chip,
 	struct xonar_wm87x6 *data = chip->model_data;
 
 	if (reg >= ARRAY_SIZE(data->wm8766_regs) ||
-	    value != data->wm8766_regs[reg]) {
-		if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
-		    (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
-			value &= ~WM8766_UPDATE;
+	    value != data->wm8766_regs[reg])
 		wm8766_write(chip, reg, value);
-	}
 }
 
 static void wm8776_registers_init(struct oxygen *chip)
@@ -141,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip)
 
 static void wm8766_registers_init(struct oxygen *chip)
 {
+	struct xonar_wm87x6 *data = chip->model_data;
+
 	wm8766_write(chip, WM8766_RESET, 0);
+	wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]);
 	wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24);
 	wm8766_write(chip, WM8766_DAC_CTRL2,
 		     WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
@@ -170,6 +183,40 @@ static void wm8776_init(struct oxygen *chip)
 	wm8776_registers_init(chip);
 }
 
+static void wm8766_init(struct oxygen *chip)
+{
+	struct xonar_wm87x6 *data = chip->model_data;
+
+	data->wm8766_regs[WM8766_DAC_CTRL] =
+		WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
+	wm8766_registers_init(chip);
+}
+
+static void xonar_ds_handle_hp_jack(struct oxygen *chip)
+{
+	struct xonar_wm87x6 *data = chip->model_data;
+	bool hp_plugged;
+	unsigned int reg;
+
+	mutex_lock(&chip->mutex);
+
+	hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+		       GPIO_DS_HP_DETECT);
+
+	oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+			      hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR,
+			      GPIO_DS_OUTPUT_FRONTLR);
+
+	reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL;
+	if (hp_plugged)
+		reg |= WM8766_MUTEALL;
+	wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
+
+	snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0);
+
+	mutex_unlock(&chip->mutex);
+}
+
 static void xonar_ds_init(struct oxygen *chip)
 {
 	struct xonar_wm87x6 *data = chip->model_data;
@@ -178,16 +225,22 @@ static void xonar_ds_init(struct oxygen *chip)
 	data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
 
 	wm8776_init(chip);
-	wm8766_registers_init(chip);
+	wm8766_init(chip);
 
-	oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE,
-			      GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE);
+	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+			  GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR);
+	oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+			    GPIO_DS_HP_DETECT);
 	oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE);
 	oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT);
 	chip->interrupt_mask |= OXYGEN_INT_GPIO;
 
 	xonar_enable_output(chip);
 
+	snd_jack_new(chip->card, "Headphone",
+		     SND_JACK_HEADPHONE, &data->hp_jack);
+	xonar_ds_handle_hp_jack(chip);
+
 	snd_component_add(chip->card, "WM8776");
 	snd_component_add(chip->card, "WM8766");
 }
@@ -208,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip)
 	wm8776_registers_init(chip);
 	wm8766_registers_init(chip);
 	xonar_enable_output(chip);
+	xonar_ds_handle_hp_jack(chip);
 }
 
 static void wm8776_adc_hardware_filter(unsigned int channel,
@@ -323,12 +377,27 @@ static void update_wm87x6_mute(struct oxygen *chip)
 			    (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
 }
 
-static void xonar_ds_gpio_changed(struct oxygen *chip)
+static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed)
 {
-	u16 bits;
+	struct xonar_wm87x6 *data = chip->model_data;
+	unsigned int reg;
 
-	bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
-	snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT));
+	/*
+	 * The WM8766 can mix left and right channels, but this setting
+	 * applies to all three stereo pairs.
+	 */
+	reg = data->wm8766_regs[WM8766_DAC_CTRL] &
+		~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK);
+	if (mixed)
+		reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX;
+	else
+		reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
+	wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
+}
+
+static void xonar_ds_gpio_changed(struct oxygen *chip)
+{
+	xonar_ds_handle_hp_jack(chip);
 }
 
 static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
@@ -896,7 +965,10 @@ static const struct snd_kcontrol_new ds_controls[] = {
 		.put = wm8776_input_mux_put,
 		.private_value = 1 << 1,
 	},
-	WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0),
+	WM8776_BIT_SWITCH("Front Mic Capture Switch",
+			  WM8776_ADCMUX, 1 << 2, 0, 0),
+	WM8776_BIT_SWITCH("Aux Capture Switch",
+			  WM8776_ADCMUX, 1 << 3, 0, 0),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "ADC Filter Capture Enum",
@@ -956,13 +1028,6 @@ static const struct snd_kcontrol_new lc_controls[] = {
 				LC_CONTROL_ALC, wm8776_ngth_db_scale),
 };
 
-static int xonar_ds_control_filter(struct snd_kcontrol_new *template)
-{
-	if (!strncmp(template->name, "CD Capture ", 11))
-		return 1; /* no CD input */
-	return 0;
-}
-
 static int xonar_ds_mixer_init(struct oxygen *chip)
 {
 	struct xonar_wm87x6 *data = chip->model_data;
@@ -999,10 +1064,9 @@ static int xonar_ds_mixer_init(struct oxygen *chip)
 
 static const struct oxygen_model model_xonar_ds = {
 	.shortname = "Xonar DS",
-	.longname = "Asus Virtuoso 200",
+	.longname = "Asus Virtuoso 66",
 	.chip = "AV200",
 	.init = xonar_ds_init,
-	.control_filter = xonar_ds_control_filter,
 	.mixer_init = xonar_ds_mixer_init,
 	.cleanup = xonar_ds_cleanup,
 	.suspend = xonar_ds_suspend,
@@ -1013,6 +1077,7 @@ static const struct oxygen_model model_xonar_ds = {
 	.set_adc_params = set_wm8776_adc_params,
 	.update_dac_volume = update_wm87x6_volume,
 	.update_dac_mute = update_wm87x6_mute,
+	.update_center_lfe_mix = update_wm8766_center_lfe_mix,
 	.gpio_changed = xonar_ds_gpio_changed,
 	.dac_tlv = wm87x6_dac_db_scale,
 	.model_data_size = sizeof(struct xonar_wm87x6),
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index d19dc052c391..d5f5b440fc40 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -1527,14 +1527,14 @@ snd_rme96_free(void *private_data)
 static void
 snd_rme96_free_spdif_pcm(struct snd_pcm *pcm)
 {
-	struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+	struct rme96 *rme96 = pcm->private_data;
 	rme96->spdif_pcm = NULL;
 }
 
 static void
 snd_rme96_free_adat_pcm(struct snd_pcm *pcm)
 {
-	struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+	struct rme96 *rme96 = pcm->private_data;
 	rme96->adat_pcm = NULL;
 }
 
@@ -1661,7 +1661,7 @@ static void
 snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
 	int n;
-	struct rme96 *rme96 = (struct rme96 *)entry->private_data;
+	struct rme96 *rme96 = entry->private_data;
 	
 	rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
 
@@ -2348,7 +2348,7 @@ snd_rme96_probe(struct pci_dev *pci,
 	if (err < 0)
 		return err;
 	card->private_free = snd_rme96_card_free;
-	rme96 = (struct rme96 *)card->private_data;	
+	rme96 = card->private_data;
 	rme96->card = card;
 	rme96->pci = pci;
 	snd_card_set_dev(card, &pci->dev);
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index d6fa7bfd9aa1..0b720cf7783e 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -3284,7 +3284,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
 static void
 snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-	struct hdsp *hdsp = (struct hdsp *) entry->private_data;
+	struct hdsp *hdsp = entry->private_data;
 	unsigned int status;
 	unsigned int status2;
 	char *pref_sync_ref;
@@ -4566,7 +4566,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm
 
 static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	struct hdsp *hdsp = (struct hdsp *)hw->private_data;
+	struct hdsp *hdsp = hw->private_data;
 	void __user *argp = (void __user *)arg;
 	int err;
 
@@ -5156,7 +5156,7 @@ static int snd_hdsp_free(struct hdsp *hdsp)
 
 static void snd_hdsp_card_free(struct snd_card *card)
 {
-	struct hdsp *hdsp = (struct hdsp *) card->private_data;
+	struct hdsp *hdsp = card->private_data;
 
 	if (hdsp)
 		snd_hdsp_free(hdsp);
@@ -5182,7 +5182,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci,
 	if (err < 0)
 		return err;
 
-	hdsp = (struct hdsp *) card->private_data;
+	hdsp = card->private_data;
 	card->private_free = snd_hdsp_card_free;
 	hdsp->dev = dev;
 	hdsp->pci = pci;