ALSA: hda - Fix multi-io channel mode management

The multi-io channels can vary not only from 1 to 6 but also may vary
from 6 to 8 or such.  At the same time, there are more speaker pins
available than the primary output pins.  So, we need three variables
to check: the minimum channel counts for primary outputs, the current
channel counts for primary outputs, and the minimum channel counts for
all outputs.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 1fbc1b3..afa54f8 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -1125,6 +1125,25 @@
 	return snd_hda_get_path_idx(codec, path);
 }
 
+/* fill the empty entries in the dac array for speaker/hp with the
+ * shared dac pointed by the paths
+ */
+static void refill_shared_dacs(struct hda_codec *codec, int num_outs,
+			       hda_nid_t *dacs, int *path_idx)
+{
+	struct nid_path *path;
+	int i;
+
+	for (i = 0; i < num_outs; i++) {
+		if (dacs[i])
+			continue;
+		path = snd_hda_get_path_from_idx(codec, path_idx[i]);
+		if (!path)
+			continue;
+		dacs[i] = path->path[0];
+	}
+}
+
 /* fill in the dac_nids table from the parsed pin configuration */
 static int fill_and_eval_dacs(struct hda_codec *codec,
 			      bool fill_hardwired,
@@ -1183,19 +1202,6 @@
 				   spec->private_dac_nids, spec->out_paths,
 				   &main_out_badness);
 
-	/* re-count num_dacs and squash invalid entries */
-	spec->multiout.num_dacs = 0;
-	for (i = 0; i < cfg->line_outs; i++) {
-		if (spec->private_dac_nids[i])
-			spec->multiout.num_dacs++;
-		else {
-			memmove(spec->private_dac_nids + i,
-				spec->private_dac_nids + i + 1,
-				sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
-			spec->private_dac_nids[cfg->line_outs - 1] = 0;
-		}
-	}
-
 	if (fill_mio_first &&
 	    cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
 		/* try to fill multi-io first */
@@ -1246,16 +1252,41 @@
 		if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
 			spec->multi_ios = 1; /* give badness */
 
+	/* re-count num_dacs and squash invalid entries */
+	spec->multiout.num_dacs = 0;
+	for (i = 0; i < cfg->line_outs; i++) {
+		if (spec->private_dac_nids[i])
+			spec->multiout.num_dacs++;
+		else {
+			memmove(spec->private_dac_nids + i,
+				spec->private_dac_nids + i + 1,
+				sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
+			spec->private_dac_nids[cfg->line_outs - 1] = 0;
+		}
+	}
+
+	spec->ext_channel_count = spec->min_channel_count =
+		spec->multiout.num_dacs;
+
 	if (spec->multi_ios == 2) {
 		for (i = 0; i < 2; i++)
 			spec->private_dac_nids[spec->multiout.num_dacs++] =
 				spec->multi_io[i].dac;
-		spec->ext_channel_count = 2;
 	} else if (spec->multi_ios) {
 		spec->multi_ios = 0;
 		badness += BAD_MULTI_IO;
 	}
 
+	/* re-fill the shared DAC for speaker / headphone */
+	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+		refill_shared_dacs(codec, cfg->hp_outs,
+				   spec->multiout.hp_out_nid,
+				   spec->hp_paths);
+	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+		refill_shared_dacs(codec, cfg->speaker_outs,
+				   spec->multiout.extra_out_nid,
+				   spec->speaker_paths);
+
 	return badness;
 }
 
@@ -1610,14 +1641,15 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_gen_spec *spec = codec->spec;
+	int chs;
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
 	uinfo->value.enumerated.items = spec->multi_ios + 1;
 	if (uinfo->value.enumerated.item > spec->multi_ios)
 		uinfo->value.enumerated.item = spec->multi_ios;
-	sprintf(uinfo->value.enumerated.name, "%dch",
-		(uinfo->value.enumerated.item + 1) * 2);
+	chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count;
+	sprintf(uinfo->value.enumerated.name, "%dch", chs);
 	return 0;
 }
 
@@ -1626,7 +1658,8 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_gen_spec *spec = codec->spec;
-	ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
+	ucontrol->value.enumerated.item[0] =
+		(spec->ext_channel_count - spec->min_channel_count) / 2;
 	return 0;
 }
 
@@ -1674,9 +1707,9 @@
 	ch = ucontrol->value.enumerated.item[0];
 	if (ch < 0 || ch > spec->multi_ios)
 		return -EINVAL;
-	if (ch == (spec->ext_channel_count - 1) / 2)
+	if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2)
 		return 0;
-	spec->ext_channel_count = (ch + 1) * 2;
+	spec->ext_channel_count = ch * 2 + spec->min_channel_count;
 	for (i = 0; i < spec->multi_ios; i++)
 		set_multi_io(codec, i, i < ch);
 	spec->multiout.max_channels = max(spec->ext_channel_count,
@@ -3127,17 +3160,16 @@
 	if (err < 0)
 		return err;
 
-	/* check the multiple speaker pins */
-	if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-		spec->const_channel_count = cfg->line_outs * 2;
-	else
-		spec->const_channel_count = cfg->speaker_outs * 2;
-
-	if (spec->multi_ios > 0)
-		spec->multiout.max_channels = max(spec->ext_channel_count,
-						  spec->const_channel_count);
-	else
-		spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+	spec->const_channel_count = spec->ext_channel_count;
+	/* check the multiple speaker and headphone pins */
+	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+		spec->const_channel_count = max(spec->const_channel_count,
+						cfg->speaker_outs * 2);
+	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+		spec->const_channel_count = max(spec->const_channel_count,
+						cfg->hp_outs * 2);
+	spec->multiout.max_channels = max(spec->ext_channel_count,
+					  spec->const_channel_count);
 
 	err = check_auto_mute_availability(codec);
 	if (err < 0)