ALSA: hda - Fix snd_hda_get_num_raw_conns() to return a correct value
authorTakashi Iwai <tiwai@suse.de>
Tue, 12 Mar 2013 15:47:30 +0000 (16:47 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 12 Mar 2013 15:47:30 +0000 (16:47 +0100)
In the connection list expansion in hda_codec.c and hda_proc.c, the
value returned from snd_hda_get_num_raw_conns() is used as the array
size to store the connection list.  However, the function returns
simply a raw value of the AC_PAR_CONNLIST_LEN parameter, and the
widget list with ranges isn't considered there.  Thus it may return a
smaller size than the actual list, which results in -ENOSPC in
snd_hda_get_raw_conections().

This patch fixes the bug by parsing the connection list correctly also
for snd_hda_get_num_raw_conns().

Reported-and-tested-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_codec.c

index 97c68dd24ef5dfed33d340730371e4a40e34347d..a9ebcf9e3710ece320bd656bd45e8ff615b0eb75 100644 (file)
@@ -494,7 +494,7 @@ static unsigned int get_num_conns(struct hda_codec *codec, hda_nid_t nid)
 
 int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid)
 {
-       return get_num_conns(codec, nid) & AC_CLIST_LENGTH;
+       return snd_hda_get_raw_connections(codec, nid, NULL, 0);
 }
 
 /**
@@ -517,9 +517,6 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
        hda_nid_t prev_nid;
        int null_count = 0;
 
-       if (snd_BUG_ON(!conn_list || max_conns <= 0))
-               return -EINVAL;
-
        parm = get_num_conns(codec, nid);
        if (!parm)
                return 0;
@@ -545,7 +542,8 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
                                          AC_VERB_GET_CONNECT_LIST, 0);
                if (parm == -1 && codec->bus->rirb_error)
                        return -EIO;
-               conn_list[0] = parm & mask;
+               if (conn_list)
+                       conn_list[0] = parm & mask;
                return 1;
        }
 
@@ -580,14 +578,20 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
                                continue;
                        }
                        for (n = prev_nid + 1; n <= val; n++) {
+                               if (conn_list) {
+                                       if (conns >= max_conns)
+                                               return -ENOSPC;
+                                       conn_list[conns] = n;
+                               }
+                               conns++;
+                       }
+               } else {
+                       if (conn_list) {
                                if (conns >= max_conns)
                                        return -ENOSPC;
-                               conn_list[conns++] = n;
+                               conn_list[conns] = val;
                        }
-               } else {
-                       if (conns >= max_conns)
-                               return -ENOSPC;
-                       conn_list[conns++] = val;
+                       conns++;
                }
                prev_nid = val;
        }