aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/hda_codec.c62
-rw-r--r--sound/pci/hda/hda_codec.h4
-rw-r--r--sound/pci/hda/hda_proc.c20
-rw-r--r--sound/pci/hda/patch_hdmi.c3
4 files changed, 61 insertions, 28 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index f82a64da2f1b..3c925145c119 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -382,13 +382,23 @@ static void remove_conn_list(struct hda_codec *codec)
/* read the connection and add to the cache */
static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
{
- hda_nid_t list[HDA_MAX_CONNECTIONS];
+ hda_nid_t list[32];
+ hda_nid_t *result = list;
int len;
len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(list));
- if (len < 0)
- return len;
- return snd_hda_override_conn_list(codec, nid, len, list);
+ if (len == -ENOSPC) {
+ len = snd_hda_get_num_raw_conns(codec, nid);
+ result = kmalloc(sizeof(hda_nid_t) * len, GFP_KERNEL);
+ if (!result)
+ return -ENOMEM;
+ len = snd_hda_get_raw_connections(codec, nid, result, len);
+ }
+ if (len >= 0)
+ len = snd_hda_override_conn_list(codec, nid, len, result);
+ if (result != list)
+ kfree(result);
+ return len;
}
/**
@@ -466,6 +476,27 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_HDA(snd_hda_get_connections);
+/* return CONNLIST_LEN parameter of the given widget */
+static unsigned int get_num_conns(struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int wcaps = get_wcaps(codec, nid);
+ unsigned int parm;
+
+ if (!(wcaps & AC_WCAP_CONN_LIST) &&
+ get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
+ return 0;
+
+ parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
+ if (parm == -1)
+ parm = 0;
+ return parm;
+}
+
+int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid)
+{
+ return get_num_conns(codec, nid) & AC_CLIST_LENGTH;
+}
+
/**
* snd_hda_get_raw_connections - copy connection list without cache
* @codec: the HDA codec
@@ -483,19 +514,16 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
unsigned int parm;
int i, conn_len, conns;
unsigned int shift, num_elems, mask;
- unsigned int wcaps;
hda_nid_t prev_nid;
int null_count = 0;
if (snd_BUG_ON(!conn_list || max_conns <= 0))
return -EINVAL;
- wcaps = get_wcaps(codec, nid);
- if (!(wcaps & AC_WCAP_CONN_LIST) &&
- get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
+ parm = get_num_conns(codec, nid);
+ if (!parm)
return 0;
- parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
if (parm & AC_CLIST_LONG) {
/* long form */
shift = 16;
@@ -552,21 +580,13 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
continue;
}
for (n = prev_nid + 1; n <= val; n++) {
- if (conns >= max_conns) {
- snd_printk(KERN_ERR "hda_codec: "
- "Too many connections %d for NID 0x%x\n",
- conns, nid);
- return -EINVAL;
- }
+ if (conns >= max_conns)
+ return -ENOSPC;
conn_list[conns++] = n;
}
} else {
- if (conns >= max_conns) {
- snd_printk(KERN_ERR "hda_codec: "
- "Too many connections %d for NID 0x%x\n",
- conns, nid);
- return -EINVAL;
- }
+ if (conns >= max_conns)
+ return -ENOSPC;
conn_list[conns++] = val;
}
prev_nid = val;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 6c592722efcd..0be18263801b 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -551,9 +551,6 @@ enum {
AC_JACK_PORT_BOTH,
};
-/* max. connections to a widget */
-#define HDA_MAX_CONNECTIONS 32
-
/* max. codec address */
#define HDA_MAX_CODEC_ADDRESS 0x0f
@@ -958,6 +955,7 @@ snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
{
return snd_hda_get_connections(codec, nid, NULL, 0);
}
+int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t *conn_list, int max_conns);
int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 5e02f26606b6..0fee8fae590a 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -22,6 +22,7 @@
*/
#include <linux/init.h>
+#include <linux/slab.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
@@ -623,7 +624,7 @@ static void print_codec_info(struct snd_info_entry *entry,
snd_hda_param_read(codec, nid,
AC_PAR_AUDIO_WIDGET_CAP);
unsigned int wid_type = get_wcaps_type(wid_caps);
- hda_nid_t conn[HDA_MAX_CONNECTIONS];
+ hda_nid_t *conn = NULL;
int conn_len = 0;
snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
@@ -660,9 +661,18 @@ static void print_codec_info(struct snd_info_entry *entry,
if (wid_type == AC_WID_VOL_KNB)
wid_caps |= AC_WCAP_CONN_LIST;
- if (wid_caps & AC_WCAP_CONN_LIST)
- conn_len = snd_hda_get_raw_connections(codec, nid, conn,
- HDA_MAX_CONNECTIONS);
+ if (wid_caps & AC_WCAP_CONN_LIST) {
+ conn_len = snd_hda_get_num_raw_conns(codec, nid);
+ if (conn_len > 0) {
+ conn = kmalloc(sizeof(hda_nid_t) * conn_len,
+ GFP_KERNEL);
+ if (!conn)
+ return;
+ if (snd_hda_get_raw_connections(codec, nid, conn,
+ conn_len) < 0)
+ conn_len = 0;
+ }
+ }
if (wid_caps & AC_WCAP_IN_AMP) {
snd_iprintf(buffer, " Amp-In caps: ");
@@ -735,6 +745,8 @@ static void print_codec_info(struct snd_info_entry *entry,
if (codec->proc_widget_hook)
codec->proc_widget_hook(buffer, codec, nid);
+
+ kfree(conn);
}
snd_hda_power_down(codec);
}
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 85236da79046..899c4fbbfd83 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -64,6 +64,9 @@ struct hdmi_spec_per_cvt {
unsigned int maxbps;
};
+/* max. connections to a widget */
+#define HDA_MAX_CONNECTIONS 32
+
struct hdmi_spec_per_pin {
hda_nid_t pin_nid;
int num_mux_nids;