Merge branch 'fix/misc' into for-linus
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 8edd998..45b4a8d 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -4719,7 +4719,7 @@
 			   cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
 	snd_printd("   inputs:");
 	for (i = 0; i < cfg->num_inputs; i++) {
-		snd_printdd(" %s=0x%x",
+		snd_printd(" %s=0x%x",
 			    hda_get_autocfg_input_label(codec, cfg, i),
 			    cfg->inputs[i].pin);
 	}
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 74b0560..b05f7be 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -312,23 +312,6 @@
 	return -EINVAL;
 }
 
-static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid)
-{
-	int eldv;
-	int present;
-
-	present = snd_hda_pin_sense(codec, nid);
-	eldv    = (present & AC_PINSENSE_ELDV);
-	present = (present & AC_PINSENSE_PRESENCE);
-
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-	printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n",
-			!!present, !!eldv);
-#endif
-
-	return eldv && present;
-}
-
 int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
 {
 	return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
@@ -343,7 +326,7 @@
 	int size;
 	unsigned char *buf;
 
-	if (!hdmi_eld_valid(codec, nid))
+	if (!eld->eld_valid)
 		return -ENOENT;
 
 	size = snd_hdmi_get_eld_size(codec, nid);
@@ -477,6 +460,8 @@
 
 	snd_iprintf(buffer, "monitor_present\t\t%d\n", e->monitor_present);
 	snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid);
+	if (!e->eld_valid)
+		return;
 	snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
 	snd_iprintf(buffer, "connection_type\t\t%s\n",
 				eld_connection_type_names[e->conn_type]);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 43a0367..3487056 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -391,6 +391,7 @@
 
 	/* chip type specific */
 	int driver_type;
+	unsigned int driver_caps;
 	int playback_streams;
 	int playback_index_offset;
 	int capture_streams;
@@ -464,6 +465,34 @@
 	AZX_NUM_DRIVERS, /* keep this as last entry */
 };
 
+/* driver quirks (capabilities) */
+/* bits 0-7 are used for indicating driver type */
+#define AZX_DCAPS_NO_TCSEL	(1 << 8)	/* No Intel TCSEL bit */
+#define AZX_DCAPS_NO_MSI	(1 << 9)	/* No MSI support */
+#define AZX_DCAPS_ATI_SNOOP	(1 << 10)	/* ATI snoop enable */
+#define AZX_DCAPS_NVIDIA_SNOOP	(1 << 11)	/* Nvidia snoop enable */
+#define AZX_DCAPS_SCH_SNOOP	(1 << 12)	/* SCH/PCH snoop enable */
+#define AZX_DCAPS_RIRB_DELAY	(1 << 13)	/* Long delay in read loop */
+#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)	/* Put a delay before read */
+#define AZX_DCAPS_CTX_WORKAROUND (1 << 15)	/* X-Fi workaround */
+#define AZX_DCAPS_POSFIX_LPIB	(1 << 16)	/* Use LPIB as default */
+#define AZX_DCAPS_POSFIX_VIA	(1 << 17)	/* Use VIACOMBO as default */
+#define AZX_DCAPS_NO_64BIT	(1 << 18)	/* No 64bit address */
+#define AZX_DCAPS_SYNC_WRITE	(1 << 19)	/* sync each cmd write */
+
+/* quirks for ATI SB / AMD Hudson */
+#define AZX_DCAPS_PRESET_ATI_SB \
+	(AZX_DCAPS_ATI_SNOOP | AZX_DCAPS_NO_TCSEL | \
+	 AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+
+/* quirks for ATI/AMD HDMI */
+#define AZX_DCAPS_PRESET_ATI_HDMI \
+	(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+
+/* quirks for Nvidia */
+#define AZX_DCAPS_PRESET_NVIDIA \
+	(AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI)
+
 static char *driver_short_names[] __devinitdata = {
 	[AZX_DRIVER_ICH] = "HDA Intel",
 	[AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -566,7 +595,7 @@
 	/* reset the rirb hw write pointer */
 	azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
 	/* set N=1, get RIRB response interrupt for new entry */
-	if (chip->driver_type == AZX_DRIVER_CTX)
+	if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
 		azx_writew(chip, RINTCNT, 0xc0);
 	else
 		azx_writew(chip, RINTCNT, 1);
@@ -1056,19 +1085,24 @@
 	 * codecs.
 	 * The PCI register TCSEL is defined in the Intel manuals.
 	 */
-	if (chip->driver_type != AZX_DRIVER_ATI &&
-	    chip->driver_type != AZX_DRIVER_ATIHDMI)
+	if (chip->driver_caps & AZX_DCAPS_NO_TCSEL) {
+		snd_printdd(SFX "Clearing TCSEL\n");
 		update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
+	}
 
-	switch (chip->driver_type) {
-	case AZX_DRIVER_ATI:
-		/* For ATI SB450 azalia HD audio, we need to enable snoop */
+	/* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio,
+	 * we need to enable snoop.
+	 */
+	if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) {
+		snd_printdd(SFX "Enabling ATI snoop\n");
 		update_pci_byte(chip->pci,
 				ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
 				0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);
-		break;
-	case AZX_DRIVER_NVIDIA:
-		/* For NVIDIA HDA, enable snoop */
+	}
+
+	/* For NVIDIA HDA, enable snoop */
+	if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) {
+		snd_printdd(SFX "Enabling Nvidia snoop\n");
 		update_pci_byte(chip->pci,
 				NVIDIA_HDA_TRANSREG_ADDR,
 				0x0f, NVIDIA_HDA_ENABLE_COHBITS);
@@ -1078,9 +1112,10 @@
 		update_pci_byte(chip->pci,
 				NVIDIA_HDA_OSTRM_COH,
 				0x01, NVIDIA_HDA_ENABLE_COHBIT);
-		break;
-	case AZX_DRIVER_SCH:
-	case AZX_DRIVER_PCH:
+	}
+
+	/* Enable SCH/PCH snoop if needed */
+	if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) {
 		pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
 		if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
 			pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC,
@@ -1091,14 +1126,6 @@
 				(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)
 				? "Failed" : "OK");
 		}
-		break;
-	default:
-		/* AMD Hudson needs the similar snoop, as it seems... */
-		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
-			update_pci_byte(chip->pci,
-				ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
-				0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);
-		break;
         }
 }
 
@@ -1152,7 +1179,7 @@
 	status = azx_readb(chip, RIRBSTS);
 	if (status & RIRB_INT_MASK) {
 		if (status & RIRB_INT_RESPONSE) {
-			if (chip->driver_type == AZX_DRIVER_CTX)
+			if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
 				udelay(80);
 			azx_update_rirb(chip);
 		}
@@ -1421,8 +1448,10 @@
 	if (err < 0)
 		return err;
 
-	if (chip->driver_type == AZX_DRIVER_NVIDIA)
+	if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
+		snd_printd(SFX "Enable delay in RIRB handling\n");
 		chip->bus->needs_damn_long_delay = 1;
+	}
 
 	codecs = 0;
 	max_slots = azx_max_codecs[chip->driver_type];
@@ -1457,9 +1486,8 @@
 	 * sequence like the pin-detection.  It seems that forcing the synced
 	 * access works around the stall.  Grrr...
 	 */
-	if (chip->pci->vendor == PCI_VENDOR_ID_AMD ||
-	    chip->pci->vendor == PCI_VENDOR_ID_ATI) {
-		snd_printk(KERN_INFO SFX "Enable sync_write for AMD chipset\n");
+	if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
+		snd_printd(SFX "Enable sync_write for stable communication\n");
 		chip->bus->sync_write = 1;
 		chip->bus->allow_bus_reset = 1;
 	}
@@ -1720,7 +1748,7 @@
 
 	stream_tag = azx_dev->stream_tag;
 	/* CA-IBG chips need the playback stream starting from 1 */
-	if (chip->driver_type == AZX_DRIVER_CTX &&
+	if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
 	    stream_tag > chip->capture_streams)
 		stream_tag -= chip->capture_streams;
 	return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
@@ -2365,20 +2393,14 @@
 	}
 
 	/* Check VIA/ATI HD Audio Controller exist */
-	switch (chip->driver_type) {
-	case AZX_DRIVER_VIA:
-		/* Use link position directly, avoid any transfer problem. */
+	if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) {
+		snd_printd(SFX "Using VIACOMBO position fix\n");
 		return POS_FIX_VIACOMBO;
-	case AZX_DRIVER_ATI:
-		/* ATI chipsets don't work well with position-buffer */
-		return POS_FIX_LPIB;
-	case AZX_DRIVER_GENERIC:
-		/* AMD chipsets also don't work with position-buffer */
-		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
-			return POS_FIX_LPIB;
-		break;
 	}
-
+	if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) {
+		snd_printd(SFX "Using LPIB position fix\n");
+		return POS_FIX_LPIB;
+	}
 	return POS_FIX_AUTO;
 }
 
@@ -2460,8 +2482,8 @@
 	}
 
 	/* NVidia chipsets seem to cause troubles with MSI */
-	if (chip->driver_type == AZX_DRIVER_NVIDIA) {
-		printk(KERN_INFO "hda_intel: Disable MSI for Nvidia chipset\n");
+	if (chip->driver_caps & AZX_DCAPS_NO_MSI) {
+		printk(KERN_INFO "hda_intel: Disabling MSI\n");
 		chip->msi = 0;
 	}
 }
@@ -2471,7 +2493,7 @@
  * constructor
  */
 static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
-				int dev, int driver_type,
+				int dev, unsigned int driver_caps,
 				struct azx **rchip)
 {
 	struct azx *chip;
@@ -2499,7 +2521,8 @@
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
-	chip->driver_type = driver_type;
+	chip->driver_caps = driver_caps;
+	chip->driver_type = driver_caps & 0xff;
 	check_msi(chip);
 	chip->dev_index = dev;
 	INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
@@ -2563,8 +2586,7 @@
 	snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap);
 
 	/* disable SB600 64bit support for safety */
-	if ((chip->driver_type == AZX_DRIVER_ATI) ||
-	    (chip->driver_type == AZX_DRIVER_ATIHDMI)) {
+	if (chip->pci->vendor == PCI_VENDOR_ID_ATI) {
 		struct pci_dev *p_smbus;
 		p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
 					 PCI_DEVICE_ID_ATI_SBX00_SMBUS,
@@ -2574,19 +2596,13 @@
 				gcap &= ~ICH6_GCAP_64OK;
 			pci_dev_put(p_smbus);
 		}
-	} else {
-		/* FIXME: not sure whether this is really needed, but
-		 * Hudson isn't stable enough for allowing everything...
-		 * let's check later again.
-		 */
-		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
-			gcap &= ~ICH6_GCAP_64OK;
 	}
 
-	/* disable 64bit DMA address for Teradici */
-	/* it does not work with device 6549:1200 subsys e4a2:040b */
-	if (chip->driver_type == AZX_DRIVER_TERA)
+	/* disable 64bit DMA address on some devices */
+	if (chip->driver_caps & AZX_DCAPS_NO_64BIT) {
+		snd_printd(SFX "Disabling 64bit DMA\n");
 		gcap &= ~ICH6_GCAP_64OK;
+	}
 
 	/* allow 64bit DMA address if supported by H/W */
 	if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
@@ -2788,38 +2804,62 @@
 /* PCI IDs */
 static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
 	/* CPT */
-	{ PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
+	{ PCI_DEVICE(0x8086, 0x1c20),
+	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
 	/* PBG */
-	{ PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
+	{ PCI_DEVICE(0x8086, 0x1d20),
+	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
 	/* Panther Point */
-	{ PCI_DEVICE(0x8086, 0x1e20), .driver_data = AZX_DRIVER_PCH },
+	{ PCI_DEVICE(0x8086, 0x1e20),
+	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
 	/* SCH */
-	{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
+	{ PCI_DEVICE(0x8086, 0x811b),
+	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP },
 	/* Generic Intel */
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
 	  .class_mask = 0xffffff,
 	  .driver_data = AZX_DRIVER_ICH },
-	/* ATI SB 450/600 */
-	{ PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
-	{ PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
+	/* ATI SB 450/600/700/800/900 */
+	{ PCI_DEVICE(0x1002, 0x437b),
+	  .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
+	{ PCI_DEVICE(0x1002, 0x4383),
+	  .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
+	/* AMD Hudson */
+	{ PCI_DEVICE(0x1022, 0x780d),
+	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
 	/* ATI HDMI */
-	{ PCI_DEVICE(0x1002, 0x793b), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0x7919), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0x960f), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0x970f), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0xaa00), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0xaa08), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0xaa10), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0xaa18), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0xaa20), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0xaa28), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0xaa30), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0xaa38), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0xaa40), .driver_data = AZX_DRIVER_ATIHDMI },
-	{ PCI_DEVICE(0x1002, 0xaa48), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0x793b),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0x7919),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0x960f),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0x970f),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0xaa00),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0xaa08),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0xaa10),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0xaa18),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0xaa20),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0xaa28),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0xaa30),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0xaa38),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0xaa40),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+	{ PCI_DEVICE(0x1002, 0xaa48),
+	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
 	/* VIA VT8251/VT8237A */
-	{ PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
+	{ PCI_DEVICE(0x1106, 0x3288),
+	  .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
 	/* SIS966 */
 	{ PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS },
 	/* ULI M5461 */
@@ -2828,9 +2868,10 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
 	  .class_mask = 0xffffff,
-	  .driver_data = AZX_DRIVER_NVIDIA },
+	  .driver_data = AZX_DRIVER_NVIDIA | AZX_DCAPS_PRESET_NVIDIA },
 	/* Teradici */
-	{ PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
+	{ PCI_DEVICE(0x6549, 0x1200),
+	  .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
 	/* Creative X-Fi (CA0110-IBG) */
 #if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE)
 	/* the following entry conflicts with snd-ctxfi driver,
@@ -2840,10 +2881,13 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
 	  .class_mask = 0xffffff,
-	  .driver_data = AZX_DRIVER_CTX },
+	  .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
+	  AZX_DCAPS_RIRB_PRE_DELAY },
 #else
 	/* this entry seems still valid -- i.e. without emu20kx chip */
-	{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX },
+	{ PCI_DEVICE(0x1102, 0x0009),
+	  .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
+	  AZX_DCAPS_RIRB_PRE_DELAY },
 #endif
 	/* Vortex86MX */
 	{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
@@ -2853,11 +2897,11 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
 	  .class_mask = 0xffffff,
-	  .driver_data = AZX_DRIVER_GENERIC },
+	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_ANY_ID),
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
 	  .class_mask = 0xffffff,
-	  .driver_data = AZX_DRIVER_GENERIC },
+	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index f1b3875..696ac25 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -3159,6 +3159,7 @@
 	SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
+	SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
 	{}
 };
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index e8725d2..3e6b9a8 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -3100,6 +3100,7 @@
 	SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
 	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
 	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
+	SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO),
 	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */
 	{}
 };
@@ -3434,7 +3435,9 @@
 			break;
 		}
 	}
-	if (spec->auto_mute && cfg->line_out_pins[0] &&
+	if (spec->auto_mute &&
+	    cfg->line_out_pins[0] &&
+	    cfg->line_out_type != AUTO_PIN_SPEAKER_OUT &&
 	    cfg->line_out_pins[0] != cfg->hp_pins[0] &&
 	    cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
 		for (i = 0; i < cfg->line_outs; i++) {
@@ -3482,25 +3485,32 @@
 {
 	struct conexant_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	int on;
+	int on = 1;
 
-	if (!spec->auto_mute)
-		on = 0;
-	else
-		on = spec->hp_present | spec->line_present;
+	/* turn on HP EAPD when HP jacks are present */
+	if (spec->auto_mute)
+		on = spec->hp_present;
 	cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
-	do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, !on);
+	/* mute speakers in auto-mode if HP or LO jacks are plugged */
+	if (spec->auto_mute)
+		on = !(spec->hp_present ||
+		       (spec->detect_line && spec->line_present));
+	do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, on);
 
 	/* toggle line-out mutes if needed, too */
 	/* if LO is a copy of either HP or Speaker, don't need to handle it */
 	if (cfg->line_out_pins[0] == cfg->hp_pins[0] ||
 	    cfg->line_out_pins[0] == cfg->speaker_pins[0])
 		return;
-	if (!spec->automute_lines || !spec->auto_mute)
-		on = 0;
-	else
-		on = spec->hp_present;
-	do_automute(codec, cfg->line_outs, cfg->line_out_pins, !on);
+	if (spec->auto_mute) {
+		/* mute LO in auto-mode when HP jack is present */
+		if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ||
+		    spec->automute_lines)
+			on = !spec->hp_present;
+		else
+			on = 1;
+	}
+	do_automute(codec, cfg->line_outs, cfg->line_out_pins, on);
 }
 
 static void cx_auto_hp_automute(struct hda_codec *codec)
@@ -3697,13 +3707,14 @@
 {
 	struct conexant_spec *spec = codec->spec;
 	hda_nid_t adc;
+	int changed = 1;
 
 	if (!imux->num_items)
 		return 0;
 	if (idx >= imux->num_items)
 		idx = imux->num_items - 1;
 	if (spec->cur_mux[0] == idx)
-		return 0;
+		changed = 0;
 	adc = spec->imux_info[idx].adc;
 	select_input_connection(codec, spec->imux_info[idx].adc,
 				spec->imux_info[idx].pin);
@@ -3716,7 +3727,7 @@
 					   spec->cur_adc_format);
 	}
 	spec->cur_mux[0] = idx;
-	return 1;
+	return changed;
 }
 
 static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol,
@@ -3790,7 +3801,7 @@
 	int pset[INPUT_PIN_ATTR_NORMAL + 1];
 	int i;
 
-	for (i = 0; i < INPUT_PIN_ATTR_NORMAL; i++)
+	for (i = 0; i < ARRAY_SIZE(pset); i++)
 		pset[i] = -1;
 	for (i = 0; i < spec->private_imux.num_items; i++) {
 		hda_nid_t pin = spec->imux_info[i].pin;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 3229018..bd0ae69 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -48,8 +48,8 @@
  *
  * The HDA correspondence of pipes/ports are converter/pin nodes.
  */
-#define MAX_HDMI_CVTS	3
-#define MAX_HDMI_PINS	3
+#define MAX_HDMI_CVTS	4
+#define MAX_HDMI_PINS	4
 
 struct hdmi_spec {
 	int num_cvts;
@@ -78,10 +78,6 @@
 	 */
 	struct hda_multi_out multiout;
 	const struct hda_pcm_stream *pcm_playback;
-
-	/* misc flags */
-	/* PD bit indicates only the update, not the current state */
-	unsigned int old_pin_detect:1;
 };
 
 
@@ -300,13 +296,6 @@
 	return -EINVAL;
 }
 
-static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid,
-			      struct hdmi_eld *eld)
-{
-	if (!snd_hdmi_get_eld(eld, codec, pin_nid))
-		snd_hdmi_show_eld(eld);
-}
-
 #ifdef BE_PARANOID
 static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
 				int *packet_index, int *byte_index)
@@ -694,35 +683,20 @@
 static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 {
 	struct hdmi_spec *spec = codec->spec;
-	int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
-	int pind = !!(res & AC_UNSOL_RES_PD);
+	int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT;
+	int pd = !!(res & AC_UNSOL_RES_PD);
 	int eldv = !!(res & AC_UNSOL_RES_ELDV);
 	int index;
 
 	printk(KERN_INFO
 		"HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
-		tag, pind, eldv);
+		pin_nid, pd, eldv);
 
-	index = hda_node_index(spec->pin, tag);
+	index = hda_node_index(spec->pin, pin_nid);
 	if (index < 0)
 		return;
 
-	if (spec->old_pin_detect) {
-		if (pind)
-			hdmi_present_sense(codec, tag, &spec->sink_eld[index]);
-		pind = spec->sink_eld[index].monitor_present;
-	}
-
-	spec->sink_eld[index].monitor_present = pind;
-	spec->sink_eld[index].eld_valid = eldv;
-
-	if (pind && eldv) {
-		hdmi_get_show_eld(codec, spec->pin[index],
-				  &spec->sink_eld[index]);
-		/* TODO: do real things about ELD */
-	}
-
-	snd_hda_input_jack_report(codec, tag);
+	hdmi_present_sense(codec, pin_nid, &spec->sink_eld[index]);
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -903,13 +877,33 @@
 static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
 			       struct hdmi_eld *eld)
 {
+	/*
+	 * Always execute a GetPinSense verb here, even when called from
+	 * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
+	 * response's PD bit is not the real PD value, but indicates that
+	 * the real PD value changed. An older version of the HD-audio
+	 * specification worked this way. Hence, we just ignore the data in
+	 * the unsolicited response to avoid custom WARs.
+	 */
 	int present = snd_hda_pin_sense(codec, pin_nid);
 
-	eld->monitor_present	= !!(present & AC_PINSENSE_PRESENCE);
-	eld->eld_valid		= !!(present & AC_PINSENSE_ELDV);
+	memset(eld, 0, sizeof(*eld));
 
-	if (present & AC_PINSENSE_ELDV)
-		hdmi_get_show_eld(codec, pin_nid, eld);
+	eld->monitor_present	= !!(present & AC_PINSENSE_PRESENCE);
+	if (eld->monitor_present)
+		eld->eld_valid	= !!(present & AC_PINSENSE_ELDV);
+	else
+		eld->eld_valid	= 0;
+
+	printk(KERN_INFO
+		"HDMI status: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
+		pin_nid, eld->monitor_present, eld->eld_valid);
+
+	if (eld->eld_valid)
+		if (!snd_hdmi_get_eld(eld, codec, pin_nid))
+			snd_hdmi_show_eld(eld);
+
+	snd_hda_input_jack_report(codec, pin_nid);
 }
 
 static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
@@ -927,7 +921,6 @@
 				     SND_JACK_VIDEOOUT, NULL);
 	if (err < 0)
 		return err;
-	snd_hda_input_jack_report(codec, pin_nid);
 
 	hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
 
@@ -1034,6 +1027,7 @@
 	"HDMI 0",
 	"HDMI 1",
 	"HDMI 2",
+	"HDMI 3",
 };
 
 /*
@@ -1490,18 +1484,6 @@
 	.free = generic_hdmi_free,
 };
 
-static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec;
-	int err = patch_generic_hdmi(codec);
-
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-	spec->old_pin_detect = 1;
-	return 0;
-}
-
 static int patch_nvhdmi_2ch(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec;
@@ -1515,7 +1497,6 @@
 	spec->multiout.num_dacs = 0;  /* no analog */
 	spec->multiout.max_channels = 2;
 	spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
-	spec->old_pin_detect = 1;
 	spec->num_cvts = 1;
 	spec->cvt[0] = nvhdmi_master_con_nid_7x;
 	spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
@@ -1658,28 +1639,28 @@
 { .id = 0x10de0005, .name = "MCP77/78 HDMI",	.patch = patch_nvhdmi_8ch_7x },
 { .id = 0x10de0006, .name = "MCP77/78 HDMI",	.patch = patch_nvhdmi_8ch_7x },
 { .id = 0x10de0007, .name = "MCP79/7A HDMI",	.patch = patch_nvhdmi_8ch_7x },
-{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de000c, .name = "MCP89 HDMI",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de000c, .name = "MCP89 HDMI",	.patch = patch_generic_hdmi },
+{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP",	.patch = patch_generic_hdmi },
 /* 17 is known to be absent */
-{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP",	.patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP",	.patch = patch_generic_hdmi },
+{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP",	.patch = patch_generic_hdmi },
 { .id = 0x10de0067, .name = "MCP67 HDMI",	.patch = patch_nvhdmi_2ch },
 { .id = 0x10de8001, .name = "MCP73 HDMI",	.patch = patch_nvhdmi_2ch },
 { .id = 0x80860054, .name = "IbexPeak HDMI",	.patch = patch_generic_hdmi },