diff options
| author | Takashi Iwai <tiwai@suse.de> | 2013-03-12 11:47:30 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2013-03-12 11:47:30 -0400 |
| commit | b5f82b1044daef74059f454353a2ee97acbbe620 (patch) | |
| tree | 8589426f3de6a604c4b0328386cde2d7d4ee6e31 | |
| parent | 281a6ac0f54052c81bbee156914459ba5a08f924 (diff) | |
ALSA: hda - Fix snd_hda_get_num_raw_conns() to return a correct value
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>
| -rw-r--r-- | sound/pci/hda/hda_codec.c | 24 |
1 files changed, 14 insertions, 10 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 97c68dd24ef5..a9ebcf9e3710 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
| @@ -494,7 +494,7 @@ static unsigned int get_num_conns(struct hda_codec *codec, hda_nid_t nid) | |||
| 494 | 494 | ||
| 495 | int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid) | 495 | int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid) |
| 496 | { | 496 | { |
| 497 | return get_num_conns(codec, nid) & AC_CLIST_LENGTH; | 497 | return snd_hda_get_raw_connections(codec, nid, NULL, 0); |
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | /** | 500 | /** |
| @@ -517,9 +517,6 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, | |||
| 517 | hda_nid_t prev_nid; | 517 | hda_nid_t prev_nid; |
| 518 | int null_count = 0; | 518 | int null_count = 0; |
| 519 | 519 | ||
| 520 | if (snd_BUG_ON(!conn_list || max_conns <= 0)) | ||
| 521 | return -EINVAL; | ||
| 522 | |||
| 523 | parm = get_num_conns(codec, nid); | 520 | parm = get_num_conns(codec, nid); |
| 524 | if (!parm) | 521 | if (!parm) |
| 525 | return 0; | 522 | return 0; |
| @@ -545,7 +542,8 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, | |||
| 545 | AC_VERB_GET_CONNECT_LIST, 0); | 542 | AC_VERB_GET_CONNECT_LIST, 0); |
| 546 | if (parm == -1 && codec->bus->rirb_error) | 543 | if (parm == -1 && codec->bus->rirb_error) |
| 547 | return -EIO; | 544 | return -EIO; |
| 548 | conn_list[0] = parm & mask; | 545 | if (conn_list) |
| 546 | conn_list[0] = parm & mask; | ||
| 549 | return 1; | 547 | return 1; |
| 550 | } | 548 | } |
| 551 | 549 | ||
| @@ -580,14 +578,20 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, | |||
| 580 | continue; | 578 | continue; |
| 581 | } | 579 | } |
| 582 | for (n = prev_nid + 1; n <= val; n++) { | 580 | for (n = prev_nid + 1; n <= val; n++) { |
| 581 | if (conn_list) { | ||
| 582 | if (conns >= max_conns) | ||
| 583 | return -ENOSPC; | ||
| 584 | conn_list[conns] = n; | ||
| 585 | } | ||
| 586 | conns++; | ||
| 587 | } | ||
| 588 | } else { | ||
| 589 | if (conn_list) { | ||
| 583 | if (conns >= max_conns) | 590 | if (conns >= max_conns) |
| 584 | return -ENOSPC; | 591 | return -ENOSPC; |
| 585 | conn_list[conns++] = n; | 592 | conn_list[conns] = val; |
| 586 | } | 593 | } |
| 587 | } else { | 594 | conns++; |
| 588 | if (conns >= max_conns) | ||
| 589 | return -ENOSPC; | ||
| 590 | conn_list[conns++] = val; | ||
| 591 | } | 595 | } |
| 592 | prev_nid = val; | 596 | prev_nid = val; |
| 593 | } | 597 | } |
