diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index c63a06703de319d43302a77e12e7de9b5944b45b..ce418c805a1a0b0591d92cabdfbe21fbcb401f4e 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -3412,7 +3412,7 @@ static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
  *
  * Returns 0 if successful, otherwise a negative error code.
  */
-static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
 				u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
 {
 	unsigned int i, val, wcaps;
@@ -3504,6 +3504,7 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
 
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_query_supported_pcm);
 
 /**
  * snd_hda_is_supported_format - Check the validity of the format
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 96c35cab57bf3de6cfd3241632f9bfc44084eca8..070efac7e20710fb94a2424b277538ff1c04eb2e 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -903,6 +903,8 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
 			  hda_nid_t *start_id);
 int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 			    hda_nid_t *conn_list, int max_conns);
+int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+				u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
 
 struct hda_verb {
 	hda_nid_t nid;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 338546531c1783bc79d85be18c388dfc0dce7d6b..19cb72db9c38df1261f3ded1fe1c0471bd906aef 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 
 /*
  * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
- * could support two independent pipes, each of them can be connected to one or
+ * could support N independent pipes, each of them can be connected to one or
  * more ports (DVI, HDMI or DisplayPort).
  *
  * The HDA correspondence of pipes/ports are converter/pin nodes.
@@ -51,30 +51,33 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 #define MAX_HDMI_CVTS	4
 #define MAX_HDMI_PINS	4
 
-struct hdmi_spec {
-	int num_cvts;
-	int num_pins;
-	hda_nid_t cvt[MAX_HDMI_CVTS+1];  /* audio sources */
-	hda_nid_t pin[MAX_HDMI_PINS+1];  /* audio sinks */
+struct hdmi_spec_per_cvt {
+	hda_nid_t cvt_nid;
+	int assigned;
+	unsigned int channels_min;
+	unsigned int channels_max;
+	u32 rates;
+	u64 formats;
+	unsigned int maxbps;
+};
 
-	/*
-	 * source connection for each pin
-	 */
-	hda_nid_t pin_cvt[MAX_HDMI_PINS+1];
+struct hdmi_spec_per_pin {
+	hda_nid_t pin_nid;
+	int num_mux_nids;
+	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+	struct hdmi_eld sink_eld;
+};
 
-	/*
-	 * HDMI sink attached to each pin
-	 */
-	struct hdmi_eld sink_eld[MAX_HDMI_PINS];
+struct hdmi_spec {
+	int num_cvts;
+	struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS];
 
-	/*
-	 * export one pcm per pipe
-	 */
-	struct hda_pcm	pcm_rec[MAX_HDMI_CVTS];
-	struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS];
+	int num_pins;
+	struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];
+	struct hda_pcm pcm_rec[MAX_HDMI_PINS];
 
 	/*
-	 * ati/nvhdmi specific
+	 * Non-generic ATI/NVIDIA specific
 	 */
 	struct hda_multi_out multiout;
 	const struct hda_pcm_stream *pcm_playback;
@@ -284,15 +287,40 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
  * HDMI routines
  */
 
-static int hda_node_index(hda_nid_t *nids, hda_nid_t nid)
+static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid)
 {
-	int i;
+	int pin_idx;
 
-	for (i = 0; nids[i]; i++)
-		if (nids[i] == nid)
-			return i;
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
+		if (spec->pins[pin_idx].pin_nid == pin_nid)
+			return pin_idx;
 
-	snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid);
+	snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid);
+	return -EINVAL;
+}
+
+static int hinfo_to_pin_index(struct hdmi_spec *spec,
+			      struct hda_pcm_stream *hinfo)
+{
+	int pin_idx;
+
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
+		if (&spec->pcm_rec[pin_idx].stream[0] == hinfo)
+			return pin_idx;
+
+	snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo);
+	return -EINVAL;
+}
+
+static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid)
+{
+	int cvt_idx;
+
+	for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
+		if (spec->cvts[cvt_idx].cvt_nid == cvt_nid)
+			return cvt_idx;
+
+	snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid);
 	return -EINVAL;
 }
 
@@ -326,28 +354,28 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
 	snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
 }
 
-static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid)
+static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 {
 	/* Unmute */
 	if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
 		snd_hda_codec_write(codec, pin_nid, 0,
 				AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-	/* Enable pin out */
+	/* Disable pin out until stream is active*/
 	snd_hda_codec_write(codec, pin_nid, 0,
-			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+			    AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
 }
 
-static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid)
+static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid)
 {
-	return 1 + snd_hda_codec_read(codec, nid, 0,
+	return 1 + snd_hda_codec_read(codec, cvt_nid, 0,
 					AC_VERB_GET_CVT_CHAN_COUNT, 0);
 }
 
 static void hdmi_set_channel_count(struct hda_codec *codec,
-				   hda_nid_t nid, int chs)
+				   hda_nid_t cvt_nid, int chs)
 {
-	if (chs != hdmi_get_channel_count(codec, nid))
-		snd_hda_codec_write(codec, nid, 0,
+	if (chs != hdmi_get_channel_count(codec, cvt_nid))
+		snd_hda_codec_write(codec, cvt_nid, 0,
 				    AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
 }
 
@@ -384,11 +412,8 @@ static void init_channel_allocations(void)
  *
  * TODO: it could select the wrong CA from multiple candidates.
 */
-static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
-				   int channels)
+static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels)
 {
-	struct hdmi_spec *spec = codec->spec;
-	struct hdmi_eld *eld;
 	int i;
 	int ca = 0;
 	int spk_mask = 0;
@@ -400,19 +425,6 @@ static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
 	if (channels <= 2)
 		return 0;
 
-	i = hda_node_index(spec->pin_cvt, nid);
-	if (i < 0)
-		return 0;
-	eld = &spec->sink_eld[i];
-
-	/*
-	 * HDMI sink's ELD info cannot always be retrieved for now, e.g.
-	 * in console or for audio devices. Assume the highest speakers
-	 * configuration, to _not_ prohibit multi-channel audio playback.
-	 */
-	if (!eld->spk_alloc)
-		eld->spk_alloc = 0xffff;
-
 	/*
 	 * expand ELD's speaker allocation mask
 	 *
@@ -608,67 +620,63 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
 	return true;
 }
 
-static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
 					struct snd_pcm_substream *substream)
 {
 	struct hdmi_spec *spec = codec->spec;
-	hda_nid_t pin_nid;
+	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+	hda_nid_t pin_nid = per_pin->pin_nid;
 	int channels = substream->runtime->channels;
+	struct hdmi_eld *eld;
 	int ca;
-	int i;
 	union audio_infoframe ai;
 
-	ca = hdmi_channel_allocation(codec, nid, channels);
-
-	for (i = 0; i < spec->num_pins; i++) {
-		if (spec->pin_cvt[i] != nid)
-			continue;
-		if (!spec->sink_eld[i].monitor_present)
-			continue;
+	eld = &spec->pins[pin_idx].sink_eld;
+	if (!eld->monitor_present)
+		return;
 
-		pin_nid = spec->pin[i];
-
-		memset(&ai, 0, sizeof(ai));
-		if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
-			struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
-
-			hdmi_ai->type		= 0x84;
-			hdmi_ai->ver		= 0x01;
-			hdmi_ai->len		= 0x0a;
-			hdmi_ai->CC02_CT47	= channels - 1;
-			hdmi_ai->CA		= ca;
-			hdmi_checksum_audio_infoframe(hdmi_ai);
-		} else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
-			struct dp_audio_infoframe *dp_ai = &ai.dp;
-
-			dp_ai->type		= 0x84;
-			dp_ai->len		= 0x1b;
-			dp_ai->ver		= 0x11 << 2;
-			dp_ai->CC02_CT47	= channels - 1;
-			dp_ai->CA		= ca;
-		} else {
-			snd_printd("HDMI: unknown connection type at pin %d\n",
-				   pin_nid);
-			continue;
-		}
+	ca = hdmi_channel_allocation(eld, channels);
+
+	memset(&ai, 0, sizeof(ai));
+	if (eld->conn_type == 0) { /* HDMI */
+		struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
+
+		hdmi_ai->type		= 0x84;
+		hdmi_ai->ver		= 0x01;
+		hdmi_ai->len		= 0x0a;
+		hdmi_ai->CC02_CT47	= channels - 1;
+		hdmi_ai->CA		= ca;
+		hdmi_checksum_audio_infoframe(hdmi_ai);
+	} else if (eld->conn_type == 1) { /* DisplayPort */
+		struct dp_audio_infoframe *dp_ai = &ai.dp;
+
+		dp_ai->type		= 0x84;
+		dp_ai->len		= 0x1b;
+		dp_ai->ver		= 0x11 << 2;
+		dp_ai->CC02_CT47	= channels - 1;
+		dp_ai->CA		= ca;
+	} else {
+		snd_printd("HDMI: unknown connection type at pin %d\n",
+			    pin_nid);
+		return;
+	}
 
-		/*
-		 * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
-		 * sizeof(*dp_ai) to avoid partial match/update problems when
-		 * the user switches between HDMI/DP monitors.
-		 */
-		if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
-					     sizeof(ai))) {
-			snd_printdd("hdmi_setup_audio_infoframe: "
-				    "cvt=%d pin=%d channels=%d\n",
-				    nid, pin_nid,
-				    channels);
-			hdmi_setup_channel_mapping(codec, pin_nid, ca);
-			hdmi_stop_infoframe_trans(codec, pin_nid);
-			hdmi_fill_audio_infoframe(codec, pin_nid,
-						  ai.bytes, sizeof(ai));
-			hdmi_start_infoframe_trans(codec, pin_nid);
-		}
+	/*
+	 * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
+	 * sizeof(*dp_ai) to avoid partial match/update problems when
+	 * the user switches between HDMI/DP monitors.
+	 */
+	if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
+					sizeof(ai))) {
+		snd_printdd("hdmi_setup_audio_infoframe: "
+			    "pin=%d channels=%d\n",
+			    pin_nid,
+			    channels);
+		hdmi_setup_channel_mapping(codec, pin_nid, ca);
+		hdmi_stop_infoframe_trans(codec, pin_nid);
+		hdmi_fill_audio_infoframe(codec, pin_nid,
+					    ai.bytes, sizeof(ai));
+		hdmi_start_infoframe_trans(codec, pin_nid);
 	}
 }
 
@@ -686,17 +694,27 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 	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;
+	int pin_idx;
+	struct hdmi_eld *eld;
 
 	printk(KERN_INFO
-		"HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
-		pin_nid, pd, eldv);
+		"HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
+		codec->addr, pin_nid, pd, eldv);
 
-	index = hda_node_index(spec->pin, pin_nid);
-	if (index < 0)
+	pin_idx = pin_nid_to_pin_index(spec, pin_nid);
+	if (pin_idx < 0)
 		return;
+	eld = &spec->pins[pin_idx].sink_eld;
 
-	hdmi_present_sense(codec, pin_nid, &spec->sink_eld[index]);
+	hdmi_present_sense(codec, pin_nid, eld);
+
+	/*
+	 * HDMI sink's ELD info cannot always be retrieved for now, e.g.
+	 * in console or for audio devices. Assume the highest speakers
+	 * configuration, to _not_ prohibit multi-channel audio playback.
+	 */
+	if (!eld->spk_alloc)
+		eld->spk_alloc = 0xffff;
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -707,7 +725,8 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
 	int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
 
 	printk(KERN_INFO
-		"HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+		"HDMI CP event: CODEC=%d PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+		codec->addr,
 		tag,
 		subtag,
 		cp_state,
@@ -727,7 +746,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
 	int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
 	int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
 
-	if (hda_node_index(spec->pin, tag) < 0) {
+	if (pin_nid_to_pin_index(spec, tag) < 0) {
 		snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
 		return;
 	}
@@ -746,21 +765,14 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
 #define is_hbr_format(format) \
 	((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
 
-static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
-			      u32 stream_tag, int format)
+static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+			      hda_nid_t pin_nid, u32 stream_tag, int format)
 {
-	struct hdmi_spec *spec = codec->spec;
 	int pinctl;
 	int new_pinctl = 0;
-	int i;
 
-	for (i = 0; i < spec->num_pins; i++) {
-		if (spec->pin_cvt[i] != nid)
-			continue;
-		if (!(snd_hda_query_pin_caps(codec, spec->pin[i]) & AC_PINCAP_HBR))
-			continue;
-
-		pinctl = snd_hda_codec_read(codec, spec->pin[i], 0,
+	if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
+		pinctl = snd_hda_codec_read(codec, pin_nid, 0,
 					    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 
 		new_pinctl = pinctl & ~AC_PINCTL_EPT;
@@ -771,22 +783,22 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 
 		snd_printdd("hdmi_setup_stream: "
 			    "NID=0x%x, %spinctl=0x%x\n",
-			    spec->pin[i],
+			    pin_nid,
 			    pinctl == new_pinctl ? "" : "new-",
 			    new_pinctl);
 
 		if (pinctl != new_pinctl)
-			snd_hda_codec_write(codec, spec->pin[i], 0,
+			snd_hda_codec_write(codec, pin_nid, 0,
 					    AC_VERB_SET_PIN_WIDGET_CONTROL,
 					    new_pinctl);
-	}
 
+	}
 	if (is_hbr_format(format) && !new_pinctl) {
 		snd_printdd("hdmi_setup_stream: HBR is not supported\n");
 		return -EINVAL;
 	}
 
-	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
+	snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format);
 	return 0;
 }
 
@@ -798,31 +810,62 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 			 struct snd_pcm_substream *substream)
 {
 	struct hdmi_spec *spec = codec->spec;
-	struct hdmi_eld *eld;
-	struct hda_pcm_stream *codec_pars;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	unsigned int idx;
+	int pin_idx, cvt_idx, mux_idx = 0;
+	struct hdmi_spec_per_pin *per_pin;
+	struct hdmi_eld *eld;
+	struct hdmi_spec_per_cvt *per_cvt = NULL;
+	int pinctl;
 
-	for (idx = 0; idx < spec->num_cvts; idx++)
-		if (hinfo->nid == spec->cvt[idx])
-			break;
-	if (snd_BUG_ON(idx >= spec->num_cvts) ||
-	    snd_BUG_ON(idx >= spec->num_pins))
+	/* Validate hinfo */
+	pin_idx = hinfo_to_pin_index(spec, hinfo);
+	if (snd_BUG_ON(pin_idx < 0))
 		return -EINVAL;
+	per_pin = &spec->pins[pin_idx];
+	eld = &per_pin->sink_eld;
+
+	/* Dynamically assign converter to stream */
+	for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+		per_cvt = &spec->cvts[cvt_idx];
 
-	/* save the PCM info the codec provides */
-	codec_pars = &spec->codec_pcm_pars[idx];
-	if (!codec_pars->rates)
-		*codec_pars = *hinfo;
+		/* Must not already be assigned */
+		if (per_cvt->assigned)
+			continue;
+		/* Must be in pin's mux's list of converters */
+		for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
+			if (per_pin->mux_nids[mux_idx] == per_cvt->cvt_nid)
+				break;
+		/* Not in mux list */
+		if (mux_idx == per_pin->num_mux_nids)
+			continue;
+		break;
+	}
+	/* No free converters */
+	if (cvt_idx == spec->num_cvts)
+		return -ENODEV;
+
+	/* Claim converter */
+	per_cvt->assigned = 1;
+	hinfo->nid = per_cvt->cvt_nid;
+
+	snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+			    AC_VERB_SET_CONNECT_SEL,
+			    mux_idx);
+	pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+				    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+	snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+			    AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    pinctl | PIN_OUT);
+	snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
 
 	/* Initially set the converter's capabilities */
-	hinfo->channels_min = codec_pars->channels_min;
-	hinfo->channels_max = codec_pars->channels_max;
-	hinfo->rates = codec_pars->rates;
-	hinfo->formats = codec_pars->formats;
-	hinfo->maxbps = codec_pars->maxbps;
+	hinfo->channels_min = per_cvt->channels_min;
+	hinfo->channels_max = per_cvt->channels_max;
+	hinfo->rates = per_cvt->rates;
+	hinfo->formats = per_cvt->formats;
+	hinfo->maxbps = per_cvt->maxbps;
 
-	eld = &spec->sink_eld[idx];
+	/* Restrict capabilities by ELD if this isn't disabled */
 	if (!static_hdmi_pcm && eld->eld_valid) {
 		snd_hdmi_eld_update_pcm_info(eld, hinfo);
 		if (hinfo->channels_min > hinfo->channels_max ||
@@ -844,12 +887,11 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 /*
  * HDA/HDMI auto parsing
  */
-static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
+static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
 {
 	struct hdmi_spec *spec = codec->spec;
-	hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
-	int conn_len, curr;
-	int index;
+	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+	hda_nid_t pin_nid = per_pin->pin_nid;
 
 	if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
 		snd_printk(KERN_WARNING
@@ -859,19 +901,9 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
 		return -EINVAL;
 	}
 
-	conn_len = snd_hda_get_connections(codec, pin_nid, conn_list,
-					   HDA_MAX_CONNECTIONS);
-	if (conn_len > 1)
-		curr = snd_hda_codec_read(codec, pin_nid, 0,
-					  AC_VERB_GET_CONNECT_SEL, 0);
-	else
-		curr = 0;
-
-	index = hda_node_index(spec->pin, pin_nid);
-	if (index < 0)
-		return -EINVAL;
-
-	spec->pin_cvt[index] = conn_list[curr];
+	per_pin->num_mux_nids = snd_hda_get_connections(codec, pin_nid,
+							per_pin->mux_nids,
+							HDA_MAX_CONNECTIONS);
 
 	return 0;
 }
@@ -898,8 +930,8 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
 		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);
+		"HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
+		codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
 
 	if (eld->eld_valid)
 		if (!snd_hdmi_get_eld(eld, codec, pin_nid))
@@ -911,47 +943,75 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
 static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 {
 	struct hdmi_spec *spec = codec->spec;
+	unsigned int caps, config;
+	int pin_idx;
+	struct hdmi_spec_per_pin *per_pin;
+	struct hdmi_eld *eld;
 	int err;
 
-	if (spec->num_pins >= MAX_HDMI_PINS) {
-		snd_printk(KERN_WARNING
-			   "HDMI: no space for pin %d\n", pin_nid);
+	caps = snd_hda_param_read(codec, pin_nid, AC_PAR_PIN_CAP);
+	if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
+		return 0;
+
+	config = snd_hda_codec_read(codec, pin_nid, 0,
+				AC_VERB_GET_CONFIG_DEFAULT, 0);
+	if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
+		return 0;
+
+	if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS))
 		return -E2BIG;
-	}
+
+	pin_idx = spec->num_pins;
+	per_pin = &spec->pins[pin_idx];
+	eld = &per_pin->sink_eld;
+
+	per_pin->pin_nid = pin_nid;
 
 	err = snd_hda_input_jack_add(codec, pin_nid,
 				     SND_JACK_VIDEOOUT, NULL);
 	if (err < 0)
 		return err;
 
-	hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
+	err = hdmi_read_pin_conn(codec, pin_idx);
+	if (err < 0)
+		return err;
 
-	spec->pin[spec->num_pins] = pin_nid;
 	spec->num_pins++;
 
-	return hdmi_read_pin_conn(codec, pin_nid);
+	hdmi_present_sense(codec, pin_nid, eld);
+
+	return 0;
 }
 
-static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
+static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
 {
-	int i, found_pin = 0;
 	struct hdmi_spec *spec = codec->spec;
-
-	for (i = 0; i < spec->num_pins; i++)
-		if (nid == spec->pin_cvt[i]) {
-			found_pin = 1;
-			break;
-		}
-
-	if (!found_pin) {
-		snd_printdd("HDMI: Skipping node %d (no connection)\n", nid);
-		return -EINVAL;
-	}
+	int cvt_idx;
+	struct hdmi_spec_per_cvt *per_cvt;
+	unsigned int chans;
+	int err;
 
 	if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS))
 		return -E2BIG;
 
-	spec->cvt[spec->num_cvts] = nid;
+	chans = get_wcaps(codec, cvt_nid);
+	chans = get_wcaps_channels(chans);
+
+	cvt_idx = spec->num_cvts;
+	per_cvt = &spec->cvts[cvt_idx];
+
+	per_cvt->cvt_nid = cvt_nid;
+	per_cvt->channels_min = 2;
+	if (chans <= 16)
+		per_cvt->channels_max = chans;
+
+	err = snd_hda_query_supported_pcm(codec, cvt_nid,
+					  &per_cvt->rates,
+					  &per_cvt->formats,
+					  &per_cvt->maxbps);
+	if (err < 0)
+		return err;
+
 	spec->num_cvts++;
 
 	return 0;
@@ -961,8 +1021,6 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 {
 	hda_nid_t nid;
 	int i, nodes;
-	int num_tmp_cvts = 0;
-	hda_nid_t tmp_cvt[MAX_HDMI_CVTS];
 
 	nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
 	if (!nid || nodes < 0) {
@@ -973,7 +1031,6 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 	for (i = 0; i < nodes; i++, nid++) {
 		unsigned int caps;
 		unsigned int type;
-		unsigned int config;
 
 		caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
 		type = get_wcaps_type(caps);
@@ -983,32 +1040,14 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
 		switch (type) {
 		case AC_WID_AUD_OUT:
-			if (num_tmp_cvts >= MAX_HDMI_CVTS) {
-				snd_printk(KERN_WARNING
-					   "HDMI: no space for converter %d\n", nid);
-				continue;
-			}
-			tmp_cvt[num_tmp_cvts] = nid;
-			num_tmp_cvts++;
+			hdmi_add_cvt(codec, nid);
 			break;
 		case AC_WID_PIN:
-			caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
-			if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
-				continue;
-
-			config = snd_hda_codec_read(codec, nid, 0,
-					     AC_VERB_GET_CONFIG_DEFAULT, 0);
-			if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
-				continue;
-
 			hdmi_add_pin(codec, nid);
 			break;
 		}
 	}
 
-	for (i = 0; i < num_tmp_cvts; i++)
-		hdmi_add_cvt(codec, tmp_cvt[i]);
-
 	/*
 	 * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
 	 * can be lost and presence sense verb will become inaccurate if the
@@ -1025,7 +1064,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
 /*
  */
-static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = {
+static char *generic_hdmi_pcm_names[MAX_HDMI_PINS] = {
 	"HDMI 0",
 	"HDMI 1",
 	"HDMI 2",
@@ -1042,51 +1081,84 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 					   unsigned int format,
 					   struct snd_pcm_substream *substream)
 {
-	hdmi_set_channel_count(codec, hinfo->nid,
-			       substream->runtime->channels);
+	hda_nid_t cvt_nid = hinfo->nid;
+	struct hdmi_spec *spec = codec->spec;
+	int pin_idx = hinfo_to_pin_index(spec, hinfo);
+	hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
+
+	hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
 
-	hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
+	hdmi_setup_audio_infoframe(codec, pin_idx, substream);
 
-	return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
+	return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
 }
 
-static const struct hda_pcm_stream generic_hdmi_pcm_playback = {
-	.substreams = 1,
-	.channels_min = 2,
-	.ops = {
-		.open = hdmi_pcm_open,
-		.prepare = generic_hdmi_playback_pcm_prepare,
-	},
+static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+					     struct hda_codec *codec,
+					     struct snd_pcm_substream *substream)
+{
+	struct hdmi_spec *spec = codec->spec;
+	int cvt_idx, pin_idx;
+	struct hdmi_spec_per_cvt *per_cvt;
+	struct hdmi_spec_per_pin *per_pin;
+	int pinctl;
+
+	snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+
+	if (hinfo->nid) {
+		cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
+		if (snd_BUG_ON(cvt_idx < 0))
+			return -EINVAL;
+		per_cvt = &spec->cvts[cvt_idx];
+
+		snd_BUG_ON(!per_cvt->assigned);
+		per_cvt->assigned = 0;
+		hinfo->nid = 0;
+
+		pin_idx = hinfo_to_pin_index(spec, hinfo);
+		if (snd_BUG_ON(pin_idx < 0))
+			return -EINVAL;
+		per_pin = &spec->pins[pin_idx];
+
+		pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+					    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+		snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL,
+				    pinctl & ~PIN_OUT);
+		snd_hda_spdif_ctls_unassign(codec, pin_idx);
+	}
+
+	return 0;
+}
+
+static const struct hda_pcm_ops generic_ops = {
+	.open = hdmi_pcm_open,
+	.prepare = generic_hdmi_playback_pcm_prepare,
+	.cleanup = generic_hdmi_playback_pcm_cleanup,
 };
 
 static int generic_hdmi_build_pcms(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
-	struct hda_pcm *info = spec->pcm_rec;
-	int i;
+	int pin_idx;
 
-	codec->num_pcms = spec->num_cvts;
-	codec->pcm_info = info;
-
-	for (i = 0; i < codec->num_pcms; i++, info++) {
-		unsigned int chans;
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+		struct hda_pcm *info;
 		struct hda_pcm_stream *pstr;
 
-		chans = get_wcaps(codec, spec->cvt[i]);
-		chans = get_wcaps_channels(chans);
-
-		info->name = generic_hdmi_pcm_names[i];
+		info = &spec->pcm_rec[pin_idx];
+		info->name = generic_hdmi_pcm_names[pin_idx];
 		info->pcm_type = HDA_PCM_TYPE_HDMI;
+
 		pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
-		if (spec->pcm_playback)
-			*pstr = *spec->pcm_playback;
-		else
-			*pstr = generic_hdmi_pcm_playback;
-		pstr->nid = spec->cvt[i];
-		if (pstr->channels_max <= 2 && chans && chans <= 16)
-			pstr->channels_max = chans;
+		pstr->substreams = 1;
+		pstr->ops = generic_ops;
+		/* other pstr fields are set in open */
 	}
 
+	codec->num_pcms = spec->num_pins;
+	codec->pcm_info = spec->pcm_rec;
+
 	return 0;
 }
 
@@ -1094,13 +1166,16 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int err;
-	int i;
+	int pin_idx;
 
-	for (i = 0; i < codec->num_pcms; i++) {
-		err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i],
-						    spec->cvt[i]);
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+		struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+		err = snd_hda_create_spdif_out_ctls(codec,
+						    per_pin->pin_nid,
+						    per_pin->mux_nids[0]);
 		if (err < 0)
 			return err;
+		snd_hda_spdif_ctls_unassign(codec, pin_idx);
 	}
 
 	return 0;
@@ -1109,13 +1184,19 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
 static int generic_hdmi_init(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
-	int i;
+	int pin_idx;
+
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+		struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+		hda_nid_t pin_nid = per_pin->pin_nid;
+		struct hdmi_eld *eld = &per_pin->sink_eld;
 
-	for (i = 0; spec->pin[i]; i++) {
-		hdmi_enable_output(codec, spec->pin[i]);
-		snd_hda_codec_write(codec, spec->pin[i], 0,
+		hdmi_init_pin(codec, pin_nid);
+		snd_hda_codec_write(codec, pin_nid, 0,
 				    AC_VERB_SET_UNSOLICITED_ENABLE,
-				    AC_USRSP_EN | spec->pin[i]);
+				    AC_USRSP_EN | pin_nid);
+
+		snd_hda_eld_proc_new(codec, eld, pin_idx);
 	}
 	return 0;
 }
@@ -1123,10 +1204,14 @@ static int generic_hdmi_init(struct hda_codec *codec)
 static void generic_hdmi_free(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
-	int i;
+	int pin_idx;
+
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+		struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+		struct hdmi_eld *eld = &per_pin->sink_eld;
 
-	for (i = 0; i < spec->num_pins; i++)
-		snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
+		snd_hda_eld_proc_free(codec, eld);
+	}
 	snd_hda_input_jack_free(codec);
 
 	kfree(spec);
@@ -1143,7 +1228,6 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
 static int patch_generic_hdmi(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec;
-	int i;
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
@@ -1157,9 +1241,6 @@ static int patch_generic_hdmi(struct hda_codec *codec)
 	}
 	codec->patch_ops = generic_hdmi_patch_ops;
 
-	for (i = 0; i < spec->num_pins; i++)
-		snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
-
 	init_channel_allocations();
 
 	return 0;
@@ -1182,7 +1263,7 @@ static int simple_playback_build_pcms(struct hda_codec *codec)
 		unsigned int chans;
 		struct hda_pcm_stream *pstr;
 
-		chans = get_wcaps(codec, spec->cvt[i]);
+		chans = get_wcaps(codec, spec->cvts[i].cvt_nid);
 		chans = get_wcaps_channels(chans);
 
 		info->name = generic_hdmi_pcm_names[i];
@@ -1190,7 +1271,7 @@ static int simple_playback_build_pcms(struct hda_codec *codec)
 		pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
 		snd_BUG_ON(!spec->pcm_playback);
 		*pstr = *spec->pcm_playback;
-		pstr->nid = spec->cvt[i];
+		pstr->nid = spec->cvts[i].cvt_nid;
 		if (pstr->channels_max <= 2 && chans && chans <= 16)
 			pstr->channels_max = chans;
 	}
@@ -1206,8 +1287,8 @@ static int simple_playback_build_controls(struct hda_codec *codec)
 
 	for (i = 0; i < codec->num_pcms; i++) {
 		err = snd_hda_create_spdif_out_ctls(codec,
-						    spec->cvt[i],
-						    spec->cvt[i]);
+						    spec->cvts[i].cvt_nid,
+						    spec->cvts[i].cvt_nid);
 		if (err < 0)
 			return err;
 	}
@@ -1414,7 +1495,7 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
 	int i;
 	struct hdmi_spec *spec = codec->spec;
 	struct hda_spdif_out *spdif =
-		snd_hda_spdif_out_of_nid(codec, spec->cvt[0]);
+		snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
 
 	mutex_lock(&codec->spdif_mutex);
 
@@ -1561,7 +1642,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
 	spec->multiout.max_channels = 2;
 	spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
 	spec->num_cvts = 1;
-	spec->cvt[0] = nvhdmi_master_con_nid_7x;
+	spec->cvts[0].cvt_nid = nvhdmi_master_con_nid_7x;
 	spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
 
 	codec->patch_ops = nvhdmi_patch_ops_2ch;
@@ -1612,11 +1693,11 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 					  substream);
 	if (err < 0)
 		return err;
-	snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_CVT_CHAN_COUNT,
-			    chans - 1);
+	snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0,
+			    AC_VERB_SET_CVT_CHAN_COUNT, chans - 1);
 	/* FIXME: XXX */
 	for (i = 0; i < chans; i++) {
-		snd_hda_codec_write(codec, spec->cvt[0], 0,
+		snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0,
 				    AC_VERB_SET_HDMI_CHAN_SLOT,
 				    (i << 4) | i);
 	}
@@ -1647,8 +1728,8 @@ static int atihdmi_init(struct hda_codec *codec)
 
 	snd_hda_sequence_write(codec, atihdmi_basic_init);
 	/* SI codec requires to unmute the pin */
-	if (get_wcaps(codec, spec->pin[0]) & AC_WCAP_OUT_AMP)
-		snd_hda_codec_write(codec, spec->pin[0], 0,
+	if (get_wcaps(codec, spec->pins[0].pin_nid) & AC_WCAP_OUT_AMP)
+		snd_hda_codec_write(codec, spec->pins[0].pin_nid, 0,
 				    AC_VERB_SET_AMP_GAIN_MUTE,
 				    AMP_OUT_UNMUTE);
 	return 0;
@@ -1676,8 +1757,8 @@ static int patch_atihdmi(struct hda_codec *codec)
 	spec->multiout.max_channels = 2;
 	spec->multiout.dig_out_nid = ATIHDMI_CVT_NID;
 	spec->num_cvts = 1;
-	spec->cvt[0] = ATIHDMI_CVT_NID;
-	spec->pin[0] = ATIHDMI_PIN_NID;
+	spec->cvts[0].cvt_nid = ATIHDMI_CVT_NID;
+	spec->pins[0].pin_nid = ATIHDMI_PIN_NID;
 	spec->pcm_playback = &atihdmi_pcm_digital_playback;
 
 	codec->patch_ops = atihdmi_patch_ops;