Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 146

kernel-2.6.18-238.el5.src.rpm

From: Jaroslav Kysela <jkysela@redhat.com>
Date: Wed, 22 Jul 2009 15:10:09 -0400
Subject: [alsa] IbexPeak related patches for codec auto-config
Message-id: 200907221910.n6MJA951006185@ns3.rdu.redhat.com
O-Subject: [RHEL 5.4 PATCH] [1/2] ALSA: IbexPeak related patches for codec auto-config
Bugzilla: 509526
RH-Acked-by: David Miller <davem@redhat.com>
RH-Acked-by: John Feeney <jfeeney@redhat.com>

Bugzilla
========
BZ#503791
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=503791

Description
===========
Change #1: hda_codec: Check for invalid zero connections

To prevent "Too many connections" message and the error path for some HDMI
codecs (which makes onboard audio unusable), check for invalid zero
connections for CONNECT_LIST verb.

Change #2: hda_generic: do not read connections for widged with an unknown type

Reading node connections for an unknown widget can confuse HDA codec bus.

Change #3: hda_generic: use AC_WCAP_CONN_LIST check for widget connections

Previous patch used widget type, but the presence flag of the connection
list is in the widget capabilities.

Change #4: hda-intel: Cleanups for widget connection list handling

This patch adds a check to snd_hda_get_connections() routine for
presence of AC_WCAP_CONN_LIST. Also, make sure that negative error
codes from noted route are handled on all places as errors.

diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 7d2f142..7103321 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -279,6 +279,12 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 	if (snd_BUG_ON(!conn_list || max_conns <= 0))
 		return -EINVAL;
 
+	if ((get_wcaps(codec, nid) & AC_WCAP_CONN_LIST) == 0) {
+		snd_printk(KERN_WARNING "hda_codec: "
+			   "connection list not available for 0x%x\n", nid);
+		return -EINVAL;
+	}
+
 	parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
 	if (parm & AC_CLIST_LONG) {
 		/* long form */
@@ -315,6 +321,12 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 						  AC_VERB_GET_CONNECT_LIST, i);
 		range_val = !!(parm & (1 << (shift-1))); /* ranges */
 		val = parm & mask;
+		if (val == 0) {
+			snd_printk(KERN_WARNING "hda_codec: "
+				   "invalid CONNECT_LIST verb %x[%i]:%x\n",
+				    nid, i, parm);
+			return 0;
+		}
 		parm >>= shift;
 		if (range_val) {
 			/* ranges between the previous and this one */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 02b248e..f16ce35 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -122,11 +122,17 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid
 	if (node == NULL)
 		return -ENOMEM;
 	node->nid = nid;
-	nconns = snd_hda_get_connections(codec, nid, conn_list,
-					 HDA_MAX_CONNECTIONS);
-	if (nconns < 0) {
-		kfree(node);
-		return nconns;
+	node->wid_caps = get_wcaps(codec, nid);
+	node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+	if (node->wid_caps & AC_WCAP_CONN_LIST) {
+		nconns = snd_hda_get_connections(codec, nid, conn_list,
+						 HDA_MAX_CONNECTIONS);
+		if (nconns < 0) {
+			kfree(node);
+			return nconns;
+		}
+	} else {
+		nconns = 0;
 	}
 	if (nconns <= ARRAY_SIZE(node->slist))
 		node->conn_list = node->slist;
@@ -141,8 +147,6 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid
 	}
 	memcpy(node->conn_list, conn_list, nconns * sizeof(hda_nid_t));
 	node->nconns = nconns;
-	node->wid_caps = get_wcaps(codec, nid);
-	node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
 
 	if (node->type == AC_WID_PIN) {
 		node->pin_caps = snd_hda_param_read(codec, node->nid, AC_PAR_PIN_CAP);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 9781c1b..981d5cc 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -3194,7 +3194,7 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
 				spec->mono_nid,
 				con_lst,
 				HDA_MAX_NUM_INPUTS);
-	if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
+	if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
 		return -EINVAL;
 
 	for (i = 0; i < num_cons; i++) {
@@ -3340,7 +3340,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
 				spec->smux_nids[0],
 				con_lst,
 				HDA_MAX_NUM_INPUTS);
-	if (!num_cons)
+	if (num_cons <= 0)
 		return -EINVAL;
 
 	if (!labels)
@@ -3545,7 +3545,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
 		if (snd_hda_get_connections(codec,
 				spec->autocfg.mono_out_pin, conn_list, 1) &&
 				snd_hda_get_connections(codec, conn_list[0],
-				conn_list, 1)) {
+				conn_list, 1) > 0) {
 
 				int wcaps = get_wcaps(codec, conn_list[0]);
 				int wid_type = (wcaps & AC_WCAP_TYPE)
@@ -4875,6 +4875,8 @@ again:
 
 	num_dacs = snd_hda_get_connections(codec, nid,
 				conn, STAC92HD83_DAC_COUNT + 1) - 1;
+	if (num_dacs < 0)
+		num_dacs = STAC92HD83_DAC_COUNT;
 
 	/* set port X to select the last DAC
 	 */