aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-02-07 12:18:19 -0500
committerTakashi Iwai <tiwai@suse.de>2013-02-07 14:01:08 -0500
commit4eea30914facd2c99061cd70e5b05d3c76c743a2 (patch)
treeb65f4322f33b80f20211962fe337d4eb2b50b630 /sound/pci/hda
parentc1279f8787f9cddd2f4a7d6abc15375b30b80501 (diff)
ALSA: hda - Remove limit of widget connections
Currently we set the max number of connections to be 32, but there seems codec that gives longer connection lists like AD1988, and we see errors in proc output and else. (Though, in the case of AD1988, it's a list of all codecs connected to a single vendor widget, so this must be something fishy, but it's still valid from the h/w design POV.) This patch tries to remove this restriction. For efficiency, we still use the fixed size array in the parser, but takes a dynamic array when the size is reported to be greater than that. Now the fixed array size is found only in patch_hdmi.c, but it should be fine, as the codec itself can't support so many pins. Reported-by: Raymond Yau <superquad.vortex2@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-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)
382/* read the connection and add to the cache */ 382/* read the connection and add to the cache */
383static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid) 383static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
384{ 384{
385 hda_nid_t list[HDA_MAX_CONNECTIONS]; 385 hda_nid_t list[32];
386 hda_nid_t *result = list;
386 int len; 387 int len;
387 388
388 len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(list)); 389 len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(list));
389 if (len < 0) 390 if (len == -ENOSPC) {
390 return len; 391 len = snd_hda_get_num_raw_conns(codec, nid);
391 return snd_hda_override_conn_list(codec, nid, len, list); 392 result = kmalloc(sizeof(hda_nid_t) * len, GFP_KERNEL);
393 if (!result)
394 return -ENOMEM;
395 len = snd_hda_get_raw_connections(codec, nid, result, len);
396 }
397 if (len >= 0)
398 len = snd_hda_override_conn_list(codec, nid, len, result);
399 if (result != list)
400 kfree(result);
401 return len;
392} 402}
393 403
394/** 404/**
@@ -466,6 +476,27 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
466} 476}
467EXPORT_SYMBOL_HDA(snd_hda_get_connections); 477EXPORT_SYMBOL_HDA(snd_hda_get_connections);
468 478
479/* return CONNLIST_LEN parameter of the given widget */
480static unsigned int get_num_conns(struct hda_codec *codec, hda_nid_t nid)
481{
482 unsigned int wcaps = get_wcaps(codec, nid);
483 unsigned int parm;
484
485 if (!(wcaps & AC_WCAP_CONN_LIST) &&
486 get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
487 return 0;
488
489 parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
490 if (parm == -1)
491 parm = 0;
492 return parm;
493}
494
495int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid)
496{
497 return get_num_conns(codec, nid) & AC_CLIST_LENGTH;
498}
499
469/** 500/**
470 * snd_hda_get_raw_connections - copy connection list without cache 501 * snd_hda_get_raw_connections - copy connection list without cache
471 * @codec: the HDA codec 502 * @codec: the HDA codec
@@ -483,19 +514,16 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
483 unsigned int parm; 514 unsigned int parm;
484 int i, conn_len, conns; 515 int i, conn_len, conns;
485 unsigned int shift, num_elems, mask; 516 unsigned int shift, num_elems, mask;
486 unsigned int wcaps;
487 hda_nid_t prev_nid; 517 hda_nid_t prev_nid;
488 int null_count = 0; 518 int null_count = 0;
489 519
490 if (snd_BUG_ON(!conn_list || max_conns <= 0)) 520 if (snd_BUG_ON(!conn_list || max_conns <= 0))
491 return -EINVAL; 521 return -EINVAL;
492 522
493 wcaps = get_wcaps(codec, nid); 523 parm = get_num_conns(codec, nid);
494 if (!(wcaps & AC_WCAP_CONN_LIST) && 524 if (!parm)
495 get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
496 return 0; 525 return 0;
497 526
498 parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
499 if (parm & AC_CLIST_LONG) { 527 if (parm & AC_CLIST_LONG) {
500 /* long form */ 528 /* long form */
501 shift = 16; 529 shift = 16;
@@ -552,21 +580,13 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
552 continue; 580 continue;
553 } 581 }
554 for (n = prev_nid + 1; n <= val; n++) { 582 for (n = prev_nid + 1; n <= val; n++) {
555 if (conns >= max_conns) { 583 if (conns >= max_conns)
556 snd_printk(KERN_ERR "hda_codec: " 584 return -ENOSPC;
557 "Too many connections %d for NID 0x%x\n",
558 conns, nid);
559 return -EINVAL;
560 }
561 conn_list[conns++] = n; 585 conn_list[conns++] = n;
562 } 586 }
563 } else { 587 } else {
564 if (conns >= max_conns) { 588 if (conns >= max_conns)
565 snd_printk(KERN_ERR "hda_codec: " 589 return -ENOSPC;
566 "Too many connections %d for NID 0x%x\n",
567 conns, nid);
568 return -EINVAL;
569 }
570 conn_list[conns++] = val; 590 conn_list[conns++] = val;
571 } 591 }
572 prev_nid = val; 592 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 {
551 AC_JACK_PORT_BOTH, 551 AC_JACK_PORT_BOTH,
552}; 552};
553 553
554/* max. connections to a widget */
555#define HDA_MAX_CONNECTIONS 32
556
557/* max. codec address */ 554/* max. codec address */
558#define HDA_MAX_CODEC_ADDRESS 0x0f 555#define HDA_MAX_CODEC_ADDRESS 0x0f
559 556
@@ -958,6 +955,7 @@ snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
958{ 955{
959 return snd_hda_get_connections(codec, nid, NULL, 0); 956 return snd_hda_get_connections(codec, nid, NULL, 0);
960} 957}
958int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid);
961int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, 959int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
962 hda_nid_t *conn_list, int max_conns); 960 hda_nid_t *conn_list, int max_conns);
963int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, 961int 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 @@
22 */ 22 */
23 23
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/slab.h>
25#include <sound/core.h> 26#include <sound/core.h>
26#include "hda_codec.h" 27#include "hda_codec.h"
27#include "hda_local.h" 28#include "hda_local.h"
@@ -623,7 +624,7 @@ static void print_codec_info(struct snd_info_entry *entry,
623 snd_hda_param_read(codec, nid, 624 snd_hda_param_read(codec, nid,
624 AC_PAR_AUDIO_WIDGET_CAP); 625 AC_PAR_AUDIO_WIDGET_CAP);
625 unsigned int wid_type = get_wcaps_type(wid_caps); 626 unsigned int wid_type = get_wcaps_type(wid_caps);
626 hda_nid_t conn[HDA_MAX_CONNECTIONS]; 627 hda_nid_t *conn = NULL;
627 int conn_len = 0; 628 int conn_len = 0;
628 629
629 snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, 630 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,
660 if (wid_type == AC_WID_VOL_KNB) 661 if (wid_type == AC_WID_VOL_KNB)
661 wid_caps |= AC_WCAP_CONN_LIST; 662 wid_caps |= AC_WCAP_CONN_LIST;
662 663
663 if (wid_caps & AC_WCAP_CONN_LIST) 664 if (wid_caps & AC_WCAP_CONN_LIST) {
664 conn_len = snd_hda_get_raw_connections(codec, nid, conn, 665 conn_len = snd_hda_get_num_raw_conns(codec, nid);
665 HDA_MAX_CONNECTIONS); 666 if (conn_len > 0) {
667 conn = kmalloc(sizeof(hda_nid_t) * conn_len,
668 GFP_KERNEL);
669 if (!conn)
670 return;
671 if (snd_hda_get_raw_connections(codec, nid, conn,
672 conn_len) < 0)
673 conn_len = 0;
674 }
675 }
666 676
667 if (wid_caps & AC_WCAP_IN_AMP) { 677 if (wid_caps & AC_WCAP_IN_AMP) {
668 snd_iprintf(buffer, " Amp-In caps: "); 678 snd_iprintf(buffer, " Amp-In caps: ");
@@ -735,6 +745,8 @@ static void print_codec_info(struct snd_info_entry *entry,
735 745
736 if (codec->proc_widget_hook) 746 if (codec->proc_widget_hook)
737 codec->proc_widget_hook(buffer, codec, nid); 747 codec->proc_widget_hook(buffer, codec, nid);
748
749 kfree(conn);
738 } 750 }
739 snd_hda_power_down(codec); 751 snd_hda_power_down(codec);
740} 752}
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 {
64 unsigned int maxbps; 64 unsigned int maxbps;
65}; 65};
66 66
67/* max. connections to a widget */
68#define HDA_MAX_CONNECTIONS 32
69
67struct hdmi_spec_per_pin { 70struct hdmi_spec_per_pin {
68 hda_nid_t pin_nid; 71 hda_nid_t pin_nid;
69 int num_mux_nids; 72 int num_mux_nids;