[alsa-devel] [PATCH] Revert "ALSA: hda - Remove limit of widget connections"
This reverts commit 4eea30914facd2c99061cd70e5b05d3c76c743a2.
The commit causes an error with node ranges: In my case, connection list length is 3, with a connection list read of 0x1e9915: a total of 6 nids (0x15, 0x16, 0x17, 0x18, 0x19, 0x1e). Since the new code makes us allocate only 3 nids to the array sent to get_raw_connections, the function fails. --- sound/pci/hda/hda_codec.c | 62 +++++++++++++++----------------------------- sound/pci/hda/hda_codec.h | 4 ++- sound/pci/hda/hda_proc.c | 20 +++----------- sound/pci/hda/patch_hdmi.c | 3 --- 4 files changed, 28 insertions(+), 61 deletions(-)
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 97c68dd..e5e8549 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -382,23 +382,13 @@ 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[32]; - hda_nid_t *result = list; + hda_nid_t list[HDA_MAX_CONNECTIONS]; int len;
len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(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; + if (len < 0) + return len; + return snd_hda_override_conn_list(codec, nid, len, list); }
/** @@ -476,27 +466,6 @@ 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 @@ -514,16 +483,19 @@ 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;
- parm = get_num_conns(codec, nid); - if (!parm) + wcaps = get_wcaps(codec, nid); + 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 & AC_CLIST_LONG) { /* long form */ shift = 16; @@ -580,13 +552,21 @@ 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) - return -ENOSPC; + if (conns >= max_conns) { + snd_printk(KERN_ERR "hda_codec: " + "Too many connections %d for NID 0x%x\n", + conns, nid); + return -EINVAL; + } conn_list[conns++] = n; } } else { - if (conns >= max_conns) - return -ENOSPC; + if (conns >= max_conns) { + snd_printk(KERN_ERR "hda_codec: " + "Too many connections %d for NID 0x%x\n", + conns, nid); + return -EINVAL; + } conn_list[conns++] = val; } prev_nid = val; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 23ca172..246ed53 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -551,6 +551,9 @@ enum { AC_JACK_PORT_BOTH, };
+/* max. connections to a widget */ +#define HDA_MAX_CONNECTIONS 32 + /* max. codec address */ #define HDA_MAX_CODEC_ADDRESS 0x0f
@@ -957,7 +960,6 @@ 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 0fee8fa..5e02f26 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -22,7 +22,6 @@ */
#include <linux/init.h> -#include <linux/slab.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" @@ -624,7 +623,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 = NULL; + hda_nid_t conn[HDA_MAX_CONNECTIONS]; int conn_len = 0;
snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, @@ -661,18 +660,9 @@ 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_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_CONN_LIST) + conn_len = snd_hda_get_raw_connections(codec, nid, conn, + HDA_MAX_CONNECTIONS);
if (wid_caps & AC_WCAP_IN_AMP) { snd_iprintf(buffer, " Amp-In caps: "); @@ -745,8 +735,6 @@ 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 78e1827..d24af4a 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -64,9 +64,6 @@ 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;
At Tue, 12 Mar 2013 15:05:02 +0100, David Henningsson wrote:
This reverts commit 4eea30914facd2c99061cd70e5b05d3c76c743a2.
The commit causes an error with node ranges: In my case, connection list length is 3, with a connection list read of 0x1e9915: a total of 6 nids (0x15, 0x16, 0x17, 0x18, 0x19, 0x1e). Since the new code makes us allocate only 3 nids to the array sent to get_raw_connections, the function fails.
Please give more information. Need to know which codec exactly you hit, and which values are returned for which verbs.
thanks,
Takashi
sound/pci/hda/hda_codec.c | 62 +++++++++++++++----------------------------- sound/pci/hda/hda_codec.h | 4 ++- sound/pci/hda/hda_proc.c | 20 +++----------- sound/pci/hda/patch_hdmi.c | 3 --- 4 files changed, 28 insertions(+), 61 deletions(-)
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 97c68dd..e5e8549 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -382,23 +382,13 @@ 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[32];
- hda_nid_t *result = list;
hda_nid_t list[HDA_MAX_CONNECTIONS]; int len;
len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(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;
- if (len < 0)
return len;
- return snd_hda_override_conn_list(codec, nid, len, list);
}
/** @@ -476,27 +466,6 @@ 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
@@ -514,16 +483,19 @@ 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;
- parm = get_num_conns(codec, nid);
- if (!parm)
wcaps = get_wcaps(codec, nid);
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 & AC_CLIST_LONG) { /* long form */ shift = 16;
@@ -580,13 +552,21 @@ 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)
return -ENOSPC;
if (conns >= max_conns) {
snd_printk(KERN_ERR "hda_codec: "
"Too many connections %d for NID 0x%x\n",
conns, nid);
return -EINVAL;
} else {} conn_list[conns++] = n; }
if (conns >= max_conns)
return -ENOSPC;
if (conns >= max_conns) {
snd_printk(KERN_ERR "hda_codec: "
"Too many connections %d for NID 0x%x\n",
conns, nid);
return -EINVAL;
} prev_nid = val;} conn_list[conns++] = val;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 23ca172..246ed53 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -551,6 +551,9 @@ enum { AC_JACK_PORT_BOTH, };
+/* max. connections to a widget */ +#define HDA_MAX_CONNECTIONS 32
/* max. codec address */ #define HDA_MAX_CODEC_ADDRESS 0x0f
@@ -957,7 +960,6 @@ 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 0fee8fa..5e02f26 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -22,7 +22,6 @@ */
#include <linux/init.h> -#include <linux/slab.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" @@ -624,7 +623,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 = NULL;
hda_nid_t conn[HDA_MAX_CONNECTIONS];
int conn_len = 0;
snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
@@ -661,18 +660,9 @@ 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_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_CONN_LIST)
conn_len = snd_hda_get_raw_connections(codec, nid, conn,
HDA_MAX_CONNECTIONS);
if (wid_caps & AC_WCAP_IN_AMP) { snd_iprintf(buffer, " Amp-In caps: ");
@@ -745,8 +735,6 @@ static void print_codec_info(struct snd_info_entry *entry,
if (codec->proc_widget_hook) codec->proc_widget_hook(buffer, codec, nid);
} snd_hda_power_down(codec);kfree(conn);
} diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 78e1827..d24af4a 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -64,9 +64,6 @@ 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; -- 1.7.9.5
participants (2)
-
David Henningsson
-
Takashi Iwai