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 */