ALSA: hda - Re-define snd_hda_parse_nid_path()

This commit modifies the definition of snd_hda_parse_nid_path()
slightly, now with_aa_mix argument is changed to anchor_nid, so that
it can handle any NID generically as an anchor point to include or
exclude.

The with_aa_mix field in struct nid_path is removed again by this
change.

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 7861c3a..8e7ce7d 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -87,9 +87,25 @@
  * parsing paths
  */
 
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+	int i;
+	for (i = 0; i < nums; i++)
+		if (list[i] == nid)
+			return i;
+	return -1;
+}
+
+/* return true if the given NID is contained in the path */
+static bool is_nid_contained(struct nid_path *path, hda_nid_t nid)
+{
+	return find_idx_in_nid_list(nid, path->path, path->depth) >= 0;
+}
+
 static struct nid_path *get_nid_path(struct hda_codec *codec,
 				     hda_nid_t from_nid, hda_nid_t to_nid,
-				     int with_aa_mix)
+				     int anchor_nid)
 {
 	struct hda_gen_spec *spec = codec->spec;
 	int i;
@@ -100,8 +116,9 @@
 			continue;
 		if ((!from_nid || path->path[0] == from_nid) &&
 		    (!to_nid || path->path[path->depth - 1] == to_nid)) {
-			if (with_aa_mix == HDA_PARSE_ALL ||
-			    path->with_aa_mix == with_aa_mix)
+			if (!anchor_nid ||
+			    (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) ||
+			    (anchor_nid < 0 && !is_nid_contained(path, anchor_nid)))
 				return path;
 		}
 	}
@@ -114,7 +131,7 @@
 struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
 				      hda_nid_t from_nid, hda_nid_t to_nid)
 {
-	return get_nid_path(codec, from_nid, to_nid, HDA_PARSE_ALL);
+	return get_nid_path(codec, from_nid, to_nid, 0);
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_nid_path);
 
@@ -213,17 +230,16 @@
 /* called recursively */
 static bool __parse_nid_path(struct hda_codec *codec,
 			     hda_nid_t from_nid, hda_nid_t to_nid,
-			     int with_aa_mix, struct nid_path *path, int depth)
+			     int anchor_nid, struct nid_path *path,
+			     int depth)
 {
-	struct hda_gen_spec *spec = codec->spec;
 	const hda_nid_t *conn;
 	int i, nums;
 
-	if (to_nid == spec->mixer_nid) {
-		if (with_aa_mix == HDA_PARSE_NO_AAMIX)
-			return false;
-		with_aa_mix = HDA_PARSE_ALL; /* mark aa-mix is included */
-	}
+	if (to_nid == anchor_nid)
+		anchor_nid = 0; /* anchor passed */
+	else if (to_nid == (hda_nid_t)(-anchor_nid))
+		return false; /* hit the exclusive nid */
 
 	nums = snd_hda_get_conn_list(codec, to_nid, &conn);
 	for (i = 0; i < nums; i++) {
@@ -236,8 +252,8 @@
 			    is_dac_already_used(codec, conn[i]))
 				continue;
 		}
-		/* aa-mix is requested but not included? */
-		if (!(spec->mixer_nid && with_aa_mix == HDA_PARSE_ONLY_AAMIX))
+		/* anchor is not requested or already passed? */
+		if (anchor_nid <= 0)
 			goto found;
 	}
 	if (depth >= MAX_NID_PATH_DEPTH)
@@ -249,15 +265,13 @@
 		    type == AC_WID_PIN)
 			continue;
 		if (__parse_nid_path(codec, from_nid, conn[i],
-				     with_aa_mix, path, depth + 1))
+				     anchor_nid, path, depth + 1))
 			goto found;
 	}
 	return false;
 
  found:
 	path->path[path->depth] = conn[i];
-	if (conn[i] == spec->mixer_nid)
-		path->with_aa_mix = true;
 	path->idx[path->depth + 1] = i;
 	if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX)
 		path->multi[path->depth + 1] = 1;
@@ -267,17 +281,17 @@
 
 /* parse the widget path from the given nid to the target nid;
  * when @from_nid is 0, try to find an empty DAC;
- * when @with_aa_mix is HDA_PARSE_NO_AAMIX, paths with spec->mixer_nid are
- * excluded, only the paths that don't go through the mixer will be chosen.
- * when @with_aa_mix is HDA_PARSE_ONLY_AAMIX, only the paths going through
- * spec->mixer_nid will be chosen.
- * when @with_aa_mix is HDA_PARSE_ALL, no special handling about mixer widget.
+ * when @anchor_nid is set to a positive value, only paths through the widget
+ * with the given value are evaluated.
+ * when @anchor_nid is set to a negative value, paths through the widget
+ * with the negative of given value are excluded, only other paths are chosen.
+ * when @anchor_nid is zero, no special handling about path selection.
  */
 bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
-			    hda_nid_t to_nid, int with_aa_mix,
+			    hda_nid_t to_nid, int anchor_nid,
 			    struct nid_path *path)
 {
-	if (__parse_nid_path(codec, from_nid, to_nid, with_aa_mix, path, 1)) {
+	if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) {
 		path->path[path->depth] = to_nid;
 		path->depth++;
 		return true;
@@ -292,7 +306,7 @@
  */
 struct nid_path *
 snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
-		     hda_nid_t to_nid, int with_aa_mix)
+		     hda_nid_t to_nid, int anchor_nid)
 {
 	struct hda_gen_spec *spec = codec->spec;
 	struct nid_path *path;
@@ -301,7 +315,7 @@
 		return NULL;
 
 	/* check whether the path has been already added */
-	path = get_nid_path(codec, from_nid, to_nid, with_aa_mix);
+	path = get_nid_path(codec, from_nid, to_nid, anchor_nid);
 	if (path)
 		return path;
 
@@ -309,7 +323,7 @@
 	if (!path)
 		return NULL;
 	memset(path, 0, sizeof(*path));
-	if (snd_hda_parse_nid_path(codec, from_nid, to_nid, with_aa_mix, path))
+	if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path))
 		return path;
 	/* push back */
 	spec->paths.used--;
@@ -909,10 +923,10 @@
 			else
 				badness += bad->no_dac;
 		}
-		path = snd_hda_add_new_path(codec, dac, pin, HDA_PARSE_NO_AAMIX);
+		path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid);
 		if (!path && !i && spec->mixer_nid) {
 			/* try with aamix */
-			path = snd_hda_add_new_path(codec, dac, pin, HDA_PARSE_ALL);
+			path = snd_hda_add_new_path(codec, dac, pin, 0);
 		}
 		if (!path)
 			dac = dacs[i] = 0;
@@ -1038,7 +1052,8 @@
 				badness++;
 				continue;
 			}
-			path = snd_hda_add_new_path(codec, dac, nid, HDA_PARSE_NO_AAMIX);
+			path = snd_hda_add_new_path(codec, dac, nid,
+						    -spec->mixer_nid);
 			if (!path) {
 				badness++;
 				continue;
@@ -1093,9 +1108,10 @@
 		dac = get_dac_if_single(codec, pins[i]);
 		if (!dac)
 			continue;
-		path = snd_hda_add_new_path(codec, dac, pins[i], HDA_PARSE_NO_AAMIX);
+		path = snd_hda_add_new_path(codec, dac, pins[i],
+					    -spec->mixer_nid);
 		if (!path && !i && spec->mixer_nid)
-			path = snd_hda_add_new_path(codec, dac, pins[i], HDA_PARSE_ALL);
+			path = snd_hda_add_new_path(codec, dac, pins[i], 0);
 		if (path) {
 			dacs[i] = dac;
 			found = true;
@@ -1110,14 +1126,16 @@
 /* create a new path including aamix if available, and return its index */
 static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
 {
+	struct hda_gen_spec *spec = codec->spec;
 	struct nid_path *path;
 
 	path = snd_hda_get_path_from_idx(codec, path_idx);
-	if (!path || !path->depth || path->with_aa_mix)
+	if (!path || !path->depth ||
+	    is_nid_contained(path, spec->mixer_nid))
 		return 0;
 	path = snd_hda_add_new_path(codec, path->path[0],
 				    path->path[path->depth - 1],
-				    HDA_PARSE_ONLY_AAMIX);
+				    spec->mixer_nid);
 	if (!path)
 		return 0;
 	print_nid_path("output-aamix", path);
@@ -1919,7 +1937,7 @@
 	    !nid_has_mute(codec, mix_nid, HDA_INPUT))
 		return 0; /* no need for analog loopback */
 
-	path = snd_hda_add_new_path(codec, pin, mix_nid, HDA_PARSE_ALL);
+	path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
 	if (!path)
 		return -EINVAL;
 	print_nid_path("loopback", path);
@@ -2092,7 +2110,7 @@
 
 			if (!is_reachable_path(codec, pin, adc))
 				continue;
-			path = snd_hda_add_new_path(codec, pin, adc, HDA_PARSE_ALL);
+			path = snd_hda_add_new_path(codec, pin, adc, 0);
 			if (!path) {
 				snd_printd(KERN_ERR
 					   "invalid input path 0x%x -> 0x%x\n",
@@ -2567,7 +2585,7 @@
 		dig_nid = look_for_dac(codec, pin, true);
 		if (!dig_nid)
 			continue;
-		path = snd_hda_add_new_path(codec, dig_nid, pin, HDA_PARSE_ALL);
+		path = snd_hda_add_new_path(codec, dig_nid, pin, 0);
 		if (!path)
 			continue;
 		print_nid_path("digout", path);
@@ -2595,7 +2613,7 @@
 				continue;
 			path = snd_hda_add_new_path(codec,
 						    spec->autocfg.dig_in_pin,
-						    dig_nid, HDA_PARSE_ALL);
+						    dig_nid, 0);
 			if (path) {
 				print_nid_path("digin", path);
 				path->active = true;
@@ -2971,16 +2989,6 @@
 	return 0;
 }
 
-/* return the position of NID in the list, or -1 if not found */
-static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
-	int i;
-	for (i = 0; i < nums; i++)
-		if (list[i] == nid)
-			return i;
-	return -1;
-}
-
 /* check whether all auto-mic pins are valid; setup indices if OK */
 static bool auto_mic_check_imux(struct hda_codec *codec)
 {