From b5f82b1044daef74059f454353a2ee97acbbe620 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Mar 2013 16:47:30 +0100 Subject: 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 Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'sound/pci/hda') 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) 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; } -- cgit v1.2.3 From 303985f81019571db0b3a6f01fc7f03eb350657e Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 14 Mar 2013 15:28:29 +0100 Subject: ALSA: hda - Disable IDT eapd_switch if there are no internal speakers If there are no internal speakers, we should not turn the eapd switch off, because it might be necessary to keep high for Headphone. BugLink: https://bugs.launchpad.net/bugs/1155016 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 83d5335ac348..dafe04ae8c72 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -815,6 +815,29 @@ static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity) return 0; } +/* check whether a built-in speaker is included in parsed pins */ +static bool has_builtin_speaker(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + hda_nid_t *nid_pin; + int nids, i; + + if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) { + nid_pin = spec->gen.autocfg.line_out_pins; + nids = spec->gen.autocfg.line_outs; + } else { + nid_pin = spec->gen.autocfg.speaker_pins; + nids = spec->gen.autocfg.speaker_outs; + } + + for (i = 0; i < nids; i++) { + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid_pin[i]); + if (snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT) + return true; + } + return false; +} + /* * PC beep controls */ @@ -3890,6 +3913,12 @@ static int patch_stac92hd73xx(struct hda_codec *codec) return err; } + /* Don't GPIO-mute speakers if there are no internal speakers, because + * the GPIO might be necessary for Headphone + */ + if (spec->eapd_switch && !has_builtin_speaker(codec)) + spec->eapd_switch = 0; + codec->proc_widget_hook = stac92hd7x_proc_hook; snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); -- cgit v1.2.3 From d1d28500cccc269fdbf81ba33d7328d1d2c04b2f Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Thu, 14 Mar 2013 17:27:44 -0700 Subject: ALSA: hda/ca0132 - Check if dspload_image succeeded. If dspload_image() fails, it was ignored and dspload_wait_loaded() was still called. dsp_loaded should never be set to true in this case, skip it. The check in dspload_wait_loaded() return true if the DSP is loaded or if it never started. Signed-off-by: Dylan Reid Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index eefc4563b2f9..cf24b75108d9 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4351,12 +4351,16 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec) return false; dsp_os_image = (struct dsp_image_seg *)(fw_entry->data); - dspload_image(codec, dsp_os_image, 0, 0, true, 0); + if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) { + pr_err("ca0132 dspload_image failed.\n"); + goto exit_download; + } + dsp_loaded = dspload_wait_loaded(codec); +exit_download: release_firmware(fw_entry); - return dsp_loaded; } -- cgit v1.2.3 From e8f1bd5d77484a1088797fd5689b1a37148a170e Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Thu, 14 Mar 2013 17:27:45 -0700 Subject: ALSA: hda/ca0132 - Check download state of DSP. Instead of using the dspload_is_loaded() function, check the dsp_state that is kept in the spec. The dspload_is_loaded() function returns true if the DSP transfer was never started. This false-positive leads to multiple second delays when ca0132_setup_efaults() times out on each write. Signed-off-by: Dylan Reid Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index cf24b75108d9..225d1d52abad 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -3239,7 +3239,7 @@ static int ca0132_set_vipsource(struct hda_codec *codec, int val) struct ca0132_spec *spec = codec->spec; unsigned int tmp; - if (!dspload_is_loaded(codec)) + if (spec->dsp_state != DSP_DOWNLOADED) return 0; /* if CrystalVoice if off, vipsource should be 0 */ @@ -4267,11 +4267,12 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec) */ static void ca0132_setup_defaults(struct hda_codec *codec) { + struct ca0132_spec *spec = codec->spec; unsigned int tmp; int num_fx; int idx, i; - if (!dspload_is_loaded(codec)) + if (spec->dsp_state != DSP_DOWNLOADED) return; /* out, in effects + voicefx */ -- cgit v1.2.3 From b714a7106ba5423c418c25e6231116560f8a9ef8 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Thu, 14 Mar 2013 17:27:46 -0700 Subject: ALSA: hda/ca0132 - Remove extra setting of dsp_state. spec->dsp_state is initialized to DSP_DOWNLOAD_INIT, no need to reset and check it in ca0132_download_dsp(). Signed-off-by: Dylan Reid Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 225d1d52abad..0792b5725f9c 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4372,16 +4372,13 @@ static void ca0132_download_dsp(struct hda_codec *codec) #ifndef CONFIG_SND_HDA_CODEC_CA0132_DSP return; /* NOP */ #endif - spec->dsp_state = DSP_DOWNLOAD_INIT; - if (spec->dsp_state == DSP_DOWNLOAD_INIT) { - chipio_enable_clocks(codec); - spec->dsp_state = DSP_DOWNLOADING; - if (!ca0132_download_dsp_images(codec)) - spec->dsp_state = DSP_DOWNLOAD_FAILED; - else - spec->dsp_state = DSP_DOWNLOADED; - } + chipio_enable_clocks(codec); + spec->dsp_state = DSP_DOWNLOADING; + if (!ca0132_download_dsp_images(codec)) + spec->dsp_state = DSP_DOWNLOAD_FAILED; + else + spec->dsp_state = DSP_DOWNLOADED; if (spec->dsp_state == DSP_DOWNLOADED) ca0132_set_dsp_msr(codec, true); -- cgit v1.2.3 From 6d3073e124e1a6138b929479301d3a7ecde00f27 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 15 Mar 2013 14:23:32 +0100 Subject: ALSA: hda - Fix missing EAPD/GPIO setup for Cirrus codecs During the transition to the generic parser, the hook to the codec specific automute function was forgotten. This resulted in the silent output on some MacBooks. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 72ebb8a36b13..60d08f669f0c 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -506,6 +506,8 @@ static int patch_cs420x(struct hda_codec *codec) if (!spec) return -ENOMEM; + spec->gen.automute_hook = cs_automute; + snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl, cs420x_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -893,6 +895,8 @@ static int patch_cs4210(struct hda_codec *codec) if (!spec) return -ENOMEM; + spec->gen.automute_hook = cs_automute; + snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl, cs421x_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); -- cgit v1.2.3