Re: [alsa-devel] [PATCH REALTEK] Added quirk to enable sound on Toshiba NB200
At Wed, 23 Sep 2009 00:39:45 -0500 (CDT), Manoj Iyer wrote:
From c96629e96fecbe59de7124ec913019ed378d0029 Mon Sep 17 00:00:00 2001
From: Manoj Iyer manoj.iyer@canonical.com Date: Tue, 22 Sep 2009 18:33:29 -0500 Subject: [PATCH] [PATCH REALTEK] Added quirk to enable sound on Toshiba NB200
Patch was tested on Toshiba NB200 and is found to enable sound.
So, it doesn't work without the model quirk? Could you give alsa-info.sh output (run with --no-upload option)?
thanks,
Takashi
Signed-off-by: Manoj Iyer manoj.iyer@canonical.com Cc: stable@kernel.org
sound/pci/hda/patch_realtek.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 30eeb30..713bf69 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -16876,6 +16876,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", ALC662_3ST_6ch_DIG),
- SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB200", ALC663_ASUS_MODE4), SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", ALC662_3ST_6ch_DIG),
-- 1.6.3.3
--- manjo
Takashi,
Please find attached also-info output after the patch was applied. Also, uploaded to:
http://www.alsa-project.org/db/?f=8e97e173ae5364a7e015c173bc2adadb7a20605e
--- manjo
On Wed, 23 Sep 2009, Takashi Iwai wrote:
At Wed, 23 Sep 2009 00:39:45 -0500 (CDT), Manoj Iyer wrote:
From c96629e96fecbe59de7124ec913019ed378d0029 Mon Sep 17 00:00:00 2001
From: Manoj Iyer manoj.iyer@canonical.com Date: Tue, 22 Sep 2009 18:33:29 -0500 Subject: [PATCH] [PATCH REALTEK] Added quirk to enable sound on Toshiba NB200
Patch was tested on Toshiba NB200 and is found to enable sound.
So, it doesn't work without the model quirk? Could you give alsa-info.sh output (run with --no-upload option)?
thanks,
Takashi
Signed-off-by: Manoj Iyer manoj.iyer@canonical.com Cc: stable@kernel.org
sound/pci/hda/patch_realtek.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 30eeb30..713bf69 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -16876,6 +16876,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", ALC662_3ST_6ch_DIG),
- SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB200", ALC663_ASUS_MODE4), SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", ALC662_3ST_6ch_DIG),
-- 1.6.3.3
--- manjo
At Mon, 28 Sep 2009 10:30:22 -0500 (CDT), manoj.iyer@canonical.com wrote:
Takashi,
Please find attached also-info output after the patch was applied. Also, uploaded to:
http://www.alsa-project.org/db/?f=8e97e173ae5364a7e015c173bc2adadb7a20605e
Thanks. And what about my first question? Doesn't the latest driver work without your change? Try alsa-driver-snapshot tarball below if not tested yet. ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/alsa-driver-snapshot.tar.gz
Or sound git tree master / for-next branches if you prefer kernel GIT: git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
Takashi
--- manjo
On Wed, 23 Sep 2009, Takashi Iwai wrote:
At Wed, 23 Sep 2009 00:39:45 -0500 (CDT), Manoj Iyer wrote:
From c96629e96fecbe59de7124ec913019ed378d0029 Mon Sep 17 00:00:00 2001
From: Manoj Iyer manoj.iyer@canonical.com Date: Tue, 22 Sep 2009 18:33:29 -0500 Subject: [PATCH] [PATCH REALTEK] Added quirk to enable sound on Toshiba NB200
Patch was tested on Toshiba NB200 and is found to enable sound.
So, it doesn't work without the model quirk? Could you give alsa-info.sh output (run with --no-upload option)?
thanks,
Takashi
Signed-off-by: Manoj Iyer manoj.iyer@canonical.com Cc: stable@kernel.org
sound/pci/hda/patch_realtek.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 30eeb30..713bf69 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -16876,6 +16876,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", ALC662_3ST_6ch_DIG),
- SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB200", ALC663_ASUS_MODE4), SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", ALC662_3ST_6ch_DIG),
-- 1.6.3.3
--- manjo
Thanks. And what about my first question?
No, without the change sound does not work, and I can confirm this on NB200, NB205, and I hear that NB210 hass also the same hardware.
Doesn't the latest driver work without your change? Try alsa-driver-snapshot tarball below if not tested yet. ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/alsa-driver-snapshot.tar.gz
Or sound git tree master / for-next branches if you prefer kernel GIT: git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
I was not able to build the sound tree, but I installed the mainline kernel build (29th sept):
http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.31.1/
and sound does not work with that either.
Takashi
--- manjo
On Wed, 23 Sep 2009, Takashi Iwai wrote:
At Wed, 23 Sep 2009 00:39:45 -0500 (CDT), Manoj Iyer wrote:
From c96629e96fecbe59de7124ec913019ed378d0029 Mon Sep 17 00:00:00 2001
From: Manoj Iyer manoj.iyer@canonical.com Date: Tue, 22 Sep 2009 18:33:29 -0500 Subject: [PATCH] [PATCH REALTEK] Added quirk to enable sound on Toshiba NB200
Patch was tested on Toshiba NB200 and is found to enable sound.
So, it doesn't work without the model quirk? Could you give alsa-info.sh output (run with --no-upload option)?
thanks,
Takashi
Signed-off-by: Manoj Iyer manoj.iyer@canonical.com Cc: stable@kernel.org
sound/pci/hda/patch_realtek.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 30eeb30..713bf69 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -16876,6 +16876,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", ALC662_3ST_6ch_DIG),
- SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB200", ALC663_ASUS_MODE4), SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", ALC662_3ST_6ch_DIG),
-- 1.6.3.3
--- manjo
At Tue, 29 Sep 2009 19:23:27 -0500 (CDT), manoj.iyer@canonical.com wrote:
Thanks. And what about my first question?
No, without the change sound does not work, and I can confirm this on NB200, NB205, and I hear that NB210 hass also the same hardware.
OK.
Doesn't the latest driver work without your change? Try alsa-driver-snapshot tarball below if not tested yet. ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/alsa-driver-snapshot.tar.gz
Or sound git tree master / for-next branches if you prefer kernel GIT: git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
I was not able to build the sound tree, but I installed the mainline kernel build (29th sept):
http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.31.1/
and sound does not work with that either.
2.6.31.x is way too old for testing the new stuff :) Any chance to test 2.6.32-rc1?
thanks,
Takashi
2.6.31.x is way too old for testing the new stuff :) Any chance to test 2.6.32-rc1?
http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.32-rc1/
I tried the 2.6.32-rc1 today, and sound does not work for me on the NB200.
--- manjo
At Thu, 1 Oct 2009 02:11:35 -0500 (CDT), manoj.iyer@canonical.com wrote:
2.6.31.x is way too old for testing the new stuff :) Any chance to test 2.6.32-rc1?
http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.32-rc1/
I tried the 2.6.32-rc1 today, and sound does not work for me on the NB200.
OK, thanks for checking. After looking at the code a bit more deeply, it turned out that the BIOS auto-parser doesn't work with this particular configuration (the speaker with mono pin 0x17).
I'm going to fix it later, but I applied your patch as the quick fix for the time being.
Takashi
At Thu, 01 Oct 2009 10:26:05 +0200, I wrote:
At Thu, 1 Oct 2009 02:11:35 -0500 (CDT), manoj.iyer@canonical.com wrote:
2.6.31.x is way too old for testing the new stuff :) Any chance to test 2.6.32-rc1?
http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.32-rc1/
I tried the 2.6.32-rc1 today, and sound does not work for me on the NB200.
OK, thanks for checking. After looking at the code a bit more deeply, it turned out that the BIOS auto-parser doesn't work with this particular configuration (the speaker with mono pin 0x17).
I'm going to fix it later, but I applied your patch as the quick fix for the time being.
Could you try the patch below with model=auto? This will make the auto-parser working, hopefully.
thanks,
Takashi
--- diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 87da5e8..7810d3d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -17146,70 +17146,145 @@ static struct alc_config_preset alc662_presets[] = { * BIOS auto configuration */
+/* convert from MIX nid to DAC */ +static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid) +{ + if (nid == 0x0f) + return 0x02; + else if (nid >= 0x0c && nid <= 0x0e) + return nid - 0x0c + 0x02; + else + return 0; +} + +/* get MIX nid connected to the given pin targeted to DAC */ +static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, + hda_nid_t dac) +{ + hda_nid_t mix[4]; + int i, num; + + num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); + for (i = 0; i < num; i++) { + if (alc662_mix_to_dac(mix[i]) == dac) + return mix[i]; + } + return 0; +} + +/* look for an empty DAC slot */ +static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t srcs[5]; + int i, j, num; + + num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); + if (num < 0) + return 0; + for (i = 0; i < num; i++) { + hda_nid_t nid = alc662_mix_to_dac(srcs[i]); + if (!nid) + continue; + for (j = 0; j < spec->multiout.num_dacs; j++) + if (spec->multiout.dac_nids[j] == nid) + break; + if (j >= spec->multiout.num_dacs) + return nid; + } + return 0; +} + +/* fill in the dac_nids table from the parsed pin configuration */ +static int alc662_auto_fill_dac_nids(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct alc_spec *spec = codec->spec; + int i; + hda_nid_t dac; + + spec->multiout.dac_nids = spec->private_dac_nids; + for (i = 0; i < cfg->line_outs; i++) { + dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]); + if (!dac) + continue; + spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; + } + return 0; +} + +static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx, + hda_nid_t nid, unsigned int chs) +{ + char name[32]; + sprintf(name, "%s Playback Volume", pfx); + return add_control(spec, ALC_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); +} + +static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx, + hda_nid_t nid, unsigned int chs) +{ + char name[32]; + sprintf(name, "%s Playback Switch", pfx); + return add_control(spec, ALC_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT)); +} + +#define alc662_add_stereo_vol(spec, pfx, nid) \ + alc662_add_vol_ctl(spec, pfx, nid, 3) +#define alc662_add_stereo_sw(spec, pfx, nid) \ + alc662_add_sw_ctl(spec, pfx, nid, 3) + /* add playback controls from the parsed DAC table */ -static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, +static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - char name[32]; + struct alc_spec *spec = codec->spec; static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; - hda_nid_t nid; + hda_nid_t nid, mix; int i, err;
for (i = 0; i < cfg->line_outs; i++) { - if (!spec->multiout.dac_nids[i]) + nid = spec->multiout.dac_nids[i]; + if (!nid) + continue; + mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid); + if (!mix) continue; - nid = alc880_idx_to_dac(i); if (i == 2) { /* Center/LFE */ - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Center Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, - HDA_OUTPUT)); + err = alc662_add_vol_ctl(spec, "Center", nid, 1); if (err < 0) return err; - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, - HDA_OUTPUT)); + err = alc662_add_vol_ctl(spec, "LFE", nid, 2); if (err < 0) return err; - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(0x0e, 1, 0, - HDA_INPUT)); + err = alc662_add_sw_ctl(spec, "Center", mix, 1); if (err < 0) return err; - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, - HDA_INPUT)); + err = alc662_add_sw_ctl(spec, "LFE", mix, 2); if (err < 0) return err; } else { const char *pfx; if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - if (!cfg->hp_pins) + if (cfg->hp_outs) pfx = "Speaker"; else pfx = "PCM"; } else pfx = chname[i]; - sprintf(name, "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - HDA_OUTPUT)); + err = alc662_add_vol_ctl(spec, pfx, nid, 3); if (err < 0) return err; if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) pfx = "Speaker"; - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i), - 3, 0, HDA_INPUT)); + err = alc662_add_sw_ctl(spec, pfx, mix, 3); if (err < 0) return err; } @@ -17218,54 +17293,38 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, }
/* add playback controls for speaker and HP outputs */ -static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, +/* return DAC nid if any new DAC is assigned */ +static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, const char *pfx) { - hda_nid_t nid; + struct alc_spec *spec = codec->spec; + hda_nid_t nid, mix; int err; - char name[32];
if (!pin) return 0; - - if (pin == 0x17) { - /* ALC663 has a mono output pin on 0x17 */ + nid = alc662_look_for_dac(codec, pin); + if (!nid) { + char name[32]; + /* the corresponding DAC is already occupied */ + if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) + return 0; /* no way */ + /* create a switch only */ sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT)); - return err; + return add_control(spec, ALC_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); }
- if (alc880_is_fixed_pin(pin)) { - nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); - /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */ - /* specify the DAC as the extra output */ - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - else - spec->multiout.extra_out_nid[0] = nid; - /* control HP volume/switch on the output mixer amp */ - nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); - sprintf(name, "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); - if (err < 0) - return err; - } else if (alc880_is_multi_pin(pin)) { - /* set manual connection */ - /* we have only a switch on HP-out PIN */ - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - return 0; + mix = alc662_dac_to_mix(codec, pin, nid); + if (!mix) + return 0; + err = alc662_add_vol_ctl(spec, pfx, nid, 3); + if (err < 0) + return err; + err = alc662_add_sw_ctl(spec, pfx, mix, 3); + if (err < 0) + return err; + return nid; }
/* create playback/capture controls for input pins */ @@ -17274,30 +17333,35 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, - int dac_idx) + hda_nid_t dac) { + int i, num; + hda_nid_t srcs[4]; + alc_set_pin_output(codec, nid, pin_type); /* need the manual connection? */ - if (alc880_is_multi_pin(nid)) { - struct alc_spec *spec = codec->spec; - int idx = alc880_multi_pin_idx(nid); - snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, - AC_VERB_SET_CONNECT_SEL, - alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); + num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs)); + if (num <= 1) + return; + for (i = 0; i < num; i++) { + if (alc662_mix_to_dac(srcs[i]) != dac) + continue; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i); + return; } }
static void alc662_auto_init_multi_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + int pin_type = get_pin_type(spec->autocfg.line_out_type); int i;
for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; - int pin_type = get_pin_type(spec->autocfg.line_out_type); if (nid) alc662_auto_set_output_and_unmute(codec, nid, pin_type, - i); + spec->multiout.dac_nids[i]); } }
@@ -17307,12 +17371,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec) hda_nid_t pin;
pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - /* use dac 0 */ - alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); + if (pin) + alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, + spec->multiout.hp_nid); pin = spec->autocfg.speaker_pins[0]; if (pin) - alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); + alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, + spec->multiout.extra_out_nid[0]); }
#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID @@ -17350,21 +17415,25 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (!spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */
- err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); + err = alc662_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err; - err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg); + err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; - err = alc662_auto_create_extra_out(spec, + err = alc662_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0], "Speaker"); if (err < 0) return err; - err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], + if (err) + spec->multiout.extra_out_nid[0] = err; + err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], "Headphone"); if (err < 0) return err; + if (err) + spec->multiout.hp_nid = err; err = alc662_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err;
Sure, I will try this over the weekend and report the results back here.
On Thu, 1 Oct 2009, Takashi Iwai wrote:
At Thu, 01 Oct 2009 10:26:05 +0200, I wrote:
At Thu, 1 Oct 2009 02:11:35 -0500 (CDT), manoj.iyer@canonical.com wrote:
2.6.31.x is way too old for testing the new stuff :) Any chance to test 2.6.32-rc1?
http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.32-rc1/
I tried the 2.6.32-rc1 today, and sound does not work for me on the NB200.
OK, thanks for checking. After looking at the code a bit more deeply, it turned out that the BIOS auto-parser doesn't work with this particular configuration (the speaker with mono pin 0x17).
I'm going to fix it later, but I applied your patch as the quick fix for the time being.
Could you try the patch below with model=auto? This will make the auto-parser working, hopefully.
thanks,
Takashi
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 87da5e8..7810d3d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -17146,70 +17146,145 @@ static struct alc_config_preset alc662_presets[] = {
- BIOS auto configuration
*/
+/* convert from MIX nid to DAC */ +static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid) +{
- if (nid == 0x0f)
return 0x02;
- else if (nid >= 0x0c && nid <= 0x0e)
return nid - 0x0c + 0x02;
- else
return 0;
+}
+/* get MIX nid connected to the given pin targeted to DAC */ +static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
hda_nid_t dac)
+{
- hda_nid_t mix[4];
- int i, num;
- num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
- for (i = 0; i < num; i++) {
if (alc662_mix_to_dac(mix[i]) == dac)
return mix[i];
- }
- return 0;
+}
+/* look for an empty DAC slot */ +static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin) +{
- struct alc_spec *spec = codec->spec;
- hda_nid_t srcs[5];
- int i, j, num;
- num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
- if (num < 0)
return 0;
- for (i = 0; i < num; i++) {
hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
if (!nid)
continue;
for (j = 0; j < spec->multiout.num_dacs; j++)
if (spec->multiout.dac_nids[j] == nid)
break;
if (j >= spec->multiout.num_dacs)
return nid;
- }
- return 0;
+}
+/* fill in the dac_nids table from the parsed pin configuration */ +static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
+{
- struct alc_spec *spec = codec->spec;
- int i;
- hda_nid_t dac;
- spec->multiout.dac_nids = spec->private_dac_nids;
- for (i = 0; i < cfg->line_outs; i++) {
dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
if (!dac)
continue;
spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
- }
- return 0;
+}
+static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
+{
- char name[32];
- sprintf(name, "%s Playback Volume", pfx);
- return add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+}
+static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
+{
- char name[32];
- sprintf(name, "%s Playback Switch", pfx);
- return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
+}
+#define alc662_add_stereo_vol(spec, pfx, nid) \
- alc662_add_vol_ctl(spec, pfx, nid, 3)
+#define alc662_add_stereo_sw(spec, pfx, nid) \
- alc662_add_sw_ctl(spec, pfx, nid, 3)
/* add playback controls from the parsed DAC table */ -static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, +static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) {
- char name[32];
- struct alc_spec *spec = codec->spec; static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
- hda_nid_t nid;
hda_nid_t nid, mix; int i, err;
for (i = 0; i < cfg->line_outs; i++) {
if (!spec->multiout.dac_nids[i])
nid = spec->multiout.dac_nids[i];
if (!nid)
continue;
mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
if (!mix) continue;
if (i == 2) { /* Center/LFE */nid = alc880_idx_to_dac(i);
err = add_control(spec, ALC_CTL_WIDGET_VOL,
"Center Playback Volume",
HDA_COMPOSE_AMP_VAL(nid, 1, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, "Center", nid, 1); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_VOL,
"LFE Playback Volume",
HDA_COMPOSE_AMP_VAL(nid, 2, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, "LFE", nid, 2); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_MUTE,
"Center Playback Switch",
HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
HDA_INPUT));
err = alc662_add_sw_ctl(spec, "Center", mix, 1); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_MUTE,
"LFE Playback Switch",
HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
HDA_INPUT));
} else { const char *pfx; if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {err = alc662_add_sw_ctl(spec, "LFE", mix, 2); if (err < 0) return err;
if (!cfg->hp_pins)
if (cfg->hp_outs) pfx = "Speaker"; else pfx = "PCM"; } else pfx = chname[i];
sprintf(name, "%s Playback Volume", pfx);
err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, pfx, nid, 3); if (err < 0) return err; if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) pfx = "Speaker";
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
3, 0, HDA_INPUT));
}err = alc662_add_sw_ctl(spec, pfx, mix, 3); if (err < 0) return err;
@@ -17218,54 +17293,38 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, }
/* add playback controls for speaker and HP outputs */ -static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, +/* return DAC nid if any new DAC is assigned */ +static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, const char *pfx) {
- hda_nid_t nid;
- struct alc_spec *spec = codec->spec;
- hda_nid_t nid, mix; int err;
char name[32];
if (!pin) return 0;
if (pin == 0x17) {
/* ALC663 has a mono output pin on 0x17 */
- nid = alc662_look_for_dac(codec, pin);
- if (!nid) {
char name[32];
/* the corresponding DAC is already occupied */
if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
return 0; /* no way */
sprintf(name, "%s Playback Switch", pfx);/* create a switch only */
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
return err;
return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
}HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (alc880_is_fixed_pin(pin)) {
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
/* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
/* specify the DAC as the extra output */
if (!spec->multiout.hp_nid)
spec->multiout.hp_nid = nid;
else
spec->multiout.extra_out_nid[0] = nid;
/* control HP volume/switch on the output mixer amp */
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
sprintf(name, "%s Playback Volume", pfx);
err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_BIND_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
if (err < 0)
return err;
- } else if (alc880_is_multi_pin(pin)) {
/* set manual connection */
/* we have only a switch on HP-out PIN */
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
- }
- return 0;
- mix = alc662_dac_to_mix(codec, pin, nid);
- if (!mix)
return 0;
- err = alc662_add_vol_ctl(spec, pfx, nid, 3);
- if (err < 0)
return err;
- err = alc662_add_sw_ctl(spec, pfx, mix, 3);
- if (err < 0)
return err;
- return nid;
}
/* create playback/capture controls for input pins */ @@ -17274,30 +17333,35 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type,
int dac_idx)
hda_nid_t dac)
{
- int i, num;
- hda_nid_t srcs[4];
- alc_set_pin_output(codec, nid, pin_type); /* need the manual connection? */
- if (alc880_is_multi_pin(nid)) {
struct alc_spec *spec = codec->spec;
int idx = alc880_multi_pin_idx(nid);
snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
AC_VERB_SET_CONNECT_SEL,
alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
- num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
- if (num <= 1)
return;
- for (i = 0; i < num; i++) {
if (alc662_mix_to_dac(srcs[i]) != dac)
continue;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
}return;
}
static void alc662_auto_init_multi_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec;
int pin_type = get_pin_type(spec->autocfg.line_out_type); int i;
for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i];
if (nid) alc662_auto_set_output_and_unmute(codec, nid, pin_type,int pin_type = get_pin_type(spec->autocfg.line_out_type);
i);
}spec->multiout.dac_nids[i]);
}
@@ -17307,12 +17371,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec) hda_nid_t pin;
pin = spec->autocfg.hp_pins[0];
- if (pin) /* connect to front */
/* use dac 0 */
alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
- if (pin)
alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
pin = spec->autocfg.speaker_pins[0]; if (pin)spec->multiout.hp_nid);
alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
spec->multiout.extra_out_nid[0]);
}
#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID @@ -17350,21 +17415,25 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (!spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */
- err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
- err = alc662_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err;
- err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
- err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err;
- err = alc662_auto_create_extra_out(spec,
- err = alc662_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0], "Speaker"); if (err < 0) return err;
- err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
- if (err)
spec->multiout.extra_out_nid[0] = err;
- err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], "Headphone"); if (err < 0) return err;
- if (err)
err = alc662_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err;spec->multiout.hp_nid = err;
I am a little puzzled. The patch did not apply cleanly to the karmic source tree, so I had to hand patch it. But, even with the quirk I submitted, the patch you pointed me to killed sound again. Could I have done something wrong?
--- manjo
On Thu, 1 Oct 2009, Takashi Iwai wrote:
At Thu, 01 Oct 2009 10:26:05 +0200, I wrote:
At Thu, 1 Oct 2009 02:11:35 -0500 (CDT), manoj.iyer@canonical.com wrote:
2.6.31.x is way too old for testing the new stuff :) Any chance to test 2.6.32-rc1?
http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.32-rc1/
I tried the 2.6.32-rc1 today, and sound does not work for me on the NB200.
OK, thanks for checking. After looking at the code a bit more deeply, it turned out that the BIOS auto-parser doesn't work with this particular configuration (the speaker with mono pin 0x17).
I'm going to fix it later, but I applied your patch as the quick fix for the time being.
Could you try the patch below with model=auto? This will make the auto-parser working, hopefully.
thanks,
Takashi
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 87da5e8..7810d3d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -17146,70 +17146,145 @@ static struct alc_config_preset alc662_presets[] = {
- BIOS auto configuration
*/
+/* convert from MIX nid to DAC */ +static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid) +{
- if (nid == 0x0f)
return 0x02;
- else if (nid >= 0x0c && nid <= 0x0e)
return nid - 0x0c + 0x02;
- else
return 0;
+}
+/* get MIX nid connected to the given pin targeted to DAC */ +static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
hda_nid_t dac)
+{
- hda_nid_t mix[4];
- int i, num;
- num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
- for (i = 0; i < num; i++) {
if (alc662_mix_to_dac(mix[i]) == dac)
return mix[i];
- }
- return 0;
+}
+/* look for an empty DAC slot */ +static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin) +{
- struct alc_spec *spec = codec->spec;
- hda_nid_t srcs[5];
- int i, j, num;
- num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
- if (num < 0)
return 0;
- for (i = 0; i < num; i++) {
hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
if (!nid)
continue;
for (j = 0; j < spec->multiout.num_dacs; j++)
if (spec->multiout.dac_nids[j] == nid)
break;
if (j >= spec->multiout.num_dacs)
return nid;
- }
- return 0;
+}
+/* fill in the dac_nids table from the parsed pin configuration */ +static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
+{
- struct alc_spec *spec = codec->spec;
- int i;
- hda_nid_t dac;
- spec->multiout.dac_nids = spec->private_dac_nids;
- for (i = 0; i < cfg->line_outs; i++) {
dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
if (!dac)
continue;
spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
- }
- return 0;
+}
+static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
+{
- char name[32];
- sprintf(name, "%s Playback Volume", pfx);
- return add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+}
+static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
+{
- char name[32];
- sprintf(name, "%s Playback Switch", pfx);
- return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
+}
+#define alc662_add_stereo_vol(spec, pfx, nid) \
- alc662_add_vol_ctl(spec, pfx, nid, 3)
+#define alc662_add_stereo_sw(spec, pfx, nid) \
- alc662_add_sw_ctl(spec, pfx, nid, 3)
/* add playback controls from the parsed DAC table */ -static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, +static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) {
- char name[32];
- struct alc_spec *spec = codec->spec; static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
- hda_nid_t nid;
hda_nid_t nid, mix; int i, err;
for (i = 0; i < cfg->line_outs; i++) {
if (!spec->multiout.dac_nids[i])
nid = spec->multiout.dac_nids[i];
if (!nid)
continue;
mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
if (!mix) continue;
if (i == 2) { /* Center/LFE */nid = alc880_idx_to_dac(i);
err = add_control(spec, ALC_CTL_WIDGET_VOL,
"Center Playback Volume",
HDA_COMPOSE_AMP_VAL(nid, 1, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, "Center", nid, 1); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_VOL,
"LFE Playback Volume",
HDA_COMPOSE_AMP_VAL(nid, 2, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, "LFE", nid, 2); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_MUTE,
"Center Playback Switch",
HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
HDA_INPUT));
err = alc662_add_sw_ctl(spec, "Center", mix, 1); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_MUTE,
"LFE Playback Switch",
HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
HDA_INPUT));
} else { const char *pfx; if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {err = alc662_add_sw_ctl(spec, "LFE", mix, 2); if (err < 0) return err;
if (!cfg->hp_pins)
if (cfg->hp_outs) pfx = "Speaker"; else pfx = "PCM"; } else pfx = chname[i];
sprintf(name, "%s Playback Volume", pfx);
err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, pfx, nid, 3); if (err < 0) return err; if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) pfx = "Speaker";
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
3, 0, HDA_INPUT));
}err = alc662_add_sw_ctl(spec, pfx, mix, 3); if (err < 0) return err;
@@ -17218,54 +17293,38 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, }
/* add playback controls for speaker and HP outputs */ -static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, +/* return DAC nid if any new DAC is assigned */ +static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, const char *pfx) {
- hda_nid_t nid;
- struct alc_spec *spec = codec->spec;
- hda_nid_t nid, mix; int err;
char name[32];
if (!pin) return 0;
if (pin == 0x17) {
/* ALC663 has a mono output pin on 0x17 */
- nid = alc662_look_for_dac(codec, pin);
- if (!nid) {
char name[32];
/* the corresponding DAC is already occupied */
if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
return 0; /* no way */
sprintf(name, "%s Playback Switch", pfx);/* create a switch only */
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
return err;
return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
}HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (alc880_is_fixed_pin(pin)) {
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
/* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
/* specify the DAC as the extra output */
if (!spec->multiout.hp_nid)
spec->multiout.hp_nid = nid;
else
spec->multiout.extra_out_nid[0] = nid;
/* control HP volume/switch on the output mixer amp */
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
sprintf(name, "%s Playback Volume", pfx);
err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_BIND_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
if (err < 0)
return err;
- } else if (alc880_is_multi_pin(pin)) {
/* set manual connection */
/* we have only a switch on HP-out PIN */
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
- }
- return 0;
- mix = alc662_dac_to_mix(codec, pin, nid);
- if (!mix)
return 0;
- err = alc662_add_vol_ctl(spec, pfx, nid, 3);
- if (err < 0)
return err;
- err = alc662_add_sw_ctl(spec, pfx, mix, 3);
- if (err < 0)
return err;
- return nid;
}
/* create playback/capture controls for input pins */ @@ -17274,30 +17333,35 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type,
int dac_idx)
hda_nid_t dac)
{
- int i, num;
- hda_nid_t srcs[4];
- alc_set_pin_output(codec, nid, pin_type); /* need the manual connection? */
- if (alc880_is_multi_pin(nid)) {
struct alc_spec *spec = codec->spec;
int idx = alc880_multi_pin_idx(nid);
snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
AC_VERB_SET_CONNECT_SEL,
alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
- num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
- if (num <= 1)
return;
- for (i = 0; i < num; i++) {
if (alc662_mix_to_dac(srcs[i]) != dac)
continue;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
}return;
}
static void alc662_auto_init_multi_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec;
int pin_type = get_pin_type(spec->autocfg.line_out_type); int i;
for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i];
if (nid) alc662_auto_set_output_and_unmute(codec, nid, pin_type,int pin_type = get_pin_type(spec->autocfg.line_out_type);
i);
}spec->multiout.dac_nids[i]);
}
@@ -17307,12 +17371,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec) hda_nid_t pin;
pin = spec->autocfg.hp_pins[0];
- if (pin) /* connect to front */
/* use dac 0 */
alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
- if (pin)
alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
pin = spec->autocfg.speaker_pins[0]; if (pin)spec->multiout.hp_nid);
alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
spec->multiout.extra_out_nid[0]);
}
#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID @@ -17350,21 +17415,25 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (!spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */
- err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
- err = alc662_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err;
- err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
- err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err;
- err = alc662_auto_create_extra_out(spec,
- err = alc662_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0], "Speaker"); if (err < 0) return err;
- err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
- if (err)
spec->multiout.extra_out_nid[0] = err;
- err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], "Headphone"); if (err < 0) return err;
- if (err)
err = alc662_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err;spec->multiout.hp_nid = err;
At Mon, 5 Oct 2009 19:13:47 -0500 (CDT), manoj.iyer@canonical.com wrote:
I am a little puzzled. The patch did not apply cleanly to the karmic source tree, so I had to hand patch it. But, even with the quirk I submitted, the patch you pointed me to killed sound again. Could I have done something wrong?
Try 2.6.32-rc3 kernel at best. It already includes this fix. No reason to stick with the modified kernel just for testing.
(And compiling a kernel won't take time if you set up kconfig properly. Even on a recent netbook, it's about 10 minutes.)
thanks,
Takashi
I can confirm that patch fixes broken mic on HP mini. It is labeled as "LineIn".
On Tue, 6 Oct 2009, Takashi Iwai wrote:
At Mon, 5 Oct 2009 19:13:47 -0500 (CDT), manoj.iyer@canonical.com wrote:
I am a little puzzled. The patch did not apply cleanly to the karmic source tree, so I had to hand patch it. But, even with the quirk I submitted, the patch you pointed me to killed sound again. Could I have done something wrong?
Try 2.6.32-rc3 kernel at best. It already includes this fix. No reason to stick with the modified kernel just for testing.
(And compiling a kernel won't take time if you set up kconfig properly. Even on a recent netbook, it's about 10 minutes.)
thanks,
Takashi
Takashi San,
Like I reported earlier, the patch you mailed me (See patch below) breaks sound on Toshiba NB200/205 again, even with my quirk. Any chance that we can work on getting this fixed? If you point me in the right direction I can dig into this some, also, mainline http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.32-rc1/ does not work. iirc, you mentioned that this patch made it into mainline as well.
Thanks
On Thu, 1 Oct 2009, Takashi Iwai wrote:
At Thu, 01 Oct 2009 10:26:05 +0200, I wrote:
At Thu, 1 Oct 2009 02:11:35 -0500 (CDT), manoj.iyer@canonical.com wrote:
2.6.31.x is way too old for testing the new stuff :) Any chance to test 2.6.32-rc1?
http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.32-rc1/
I tried the 2.6.32-rc1 today, and sound does not work for me on the NB200.
OK, thanks for checking. After looking at the code a bit more deeply, it turned out that the BIOS auto-parser doesn't work with this particular configuration (the speaker with mono pin 0x17).
I'm going to fix it later, but I applied your patch as the quick fix for the time being.
Could you try the patch below with model=auto? This will make the auto-parser working, hopefully.
thanks,
Takashi
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 87da5e8..7810d3d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -17146,70 +17146,145 @@ static struct alc_config_preset alc662_presets[] = {
- BIOS auto configuration
*/
+/* convert from MIX nid to DAC */ +static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid) +{
- if (nid == 0x0f)
return 0x02;
- else if (nid >= 0x0c && nid <= 0x0e)
return nid - 0x0c + 0x02;
- else
return 0;
+}
+/* get MIX nid connected to the given pin targeted to DAC */ +static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
hda_nid_t dac)
+{
- hda_nid_t mix[4];
- int i, num;
- num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
- for (i = 0; i < num; i++) {
if (alc662_mix_to_dac(mix[i]) == dac)
return mix[i];
- }
- return 0;
+}
+/* look for an empty DAC slot */ +static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin) +{
- struct alc_spec *spec = codec->spec;
- hda_nid_t srcs[5];
- int i, j, num;
- num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
- if (num < 0)
return 0;
- for (i = 0; i < num; i++) {
hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
if (!nid)
continue;
for (j = 0; j < spec->multiout.num_dacs; j++)
if (spec->multiout.dac_nids[j] == nid)
break;
if (j >= spec->multiout.num_dacs)
return nid;
- }
- return 0;
+}
+/* fill in the dac_nids table from the parsed pin configuration */ +static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
+{
- struct alc_spec *spec = codec->spec;
- int i;
- hda_nid_t dac;
- spec->multiout.dac_nids = spec->private_dac_nids;
- for (i = 0; i < cfg->line_outs; i++) {
dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
if (!dac)
continue;
spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
- }
- return 0;
+}
+static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
+{
- char name[32];
- sprintf(name, "%s Playback Volume", pfx);
- return add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+}
+static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
+{
- char name[32];
- sprintf(name, "%s Playback Switch", pfx);
- return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
+}
+#define alc662_add_stereo_vol(spec, pfx, nid) \
- alc662_add_vol_ctl(spec, pfx, nid, 3)
+#define alc662_add_stereo_sw(spec, pfx, nid) \
- alc662_add_sw_ctl(spec, pfx, nid, 3)
/* add playback controls from the parsed DAC table */ -static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, +static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) {
- char name[32];
- struct alc_spec *spec = codec->spec; static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
- hda_nid_t nid;
hda_nid_t nid, mix; int i, err;
for (i = 0; i < cfg->line_outs; i++) {
if (!spec->multiout.dac_nids[i])
nid = spec->multiout.dac_nids[i];
if (!nid)
continue;
mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
if (!mix) continue;
if (i == 2) { /* Center/LFE */nid = alc880_idx_to_dac(i);
err = add_control(spec, ALC_CTL_WIDGET_VOL,
"Center Playback Volume",
HDA_COMPOSE_AMP_VAL(nid, 1, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, "Center", nid, 1); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_VOL,
"LFE Playback Volume",
HDA_COMPOSE_AMP_VAL(nid, 2, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, "LFE", nid, 2); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_MUTE,
"Center Playback Switch",
HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
HDA_INPUT));
err = alc662_add_sw_ctl(spec, "Center", mix, 1); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_MUTE,
"LFE Playback Switch",
HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
HDA_INPUT));
} else { const char *pfx; if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {err = alc662_add_sw_ctl(spec, "LFE", mix, 2); if (err < 0) return err;
if (!cfg->hp_pins)
if (cfg->hp_outs) pfx = "Speaker"; else pfx = "PCM"; } else pfx = chname[i];
sprintf(name, "%s Playback Volume", pfx);
err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, pfx, nid, 3); if (err < 0) return err; if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) pfx = "Speaker";
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
3, 0, HDA_INPUT));
}err = alc662_add_sw_ctl(spec, pfx, mix, 3); if (err < 0) return err;
@@ -17218,54 +17293,38 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, }
/* add playback controls for speaker and HP outputs */ -static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, +/* return DAC nid if any new DAC is assigned */ +static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, const char *pfx) {
- hda_nid_t nid;
- struct alc_spec *spec = codec->spec;
- hda_nid_t nid, mix; int err;
char name[32];
if (!pin) return 0;
if (pin == 0x17) {
/* ALC663 has a mono output pin on 0x17 */
- nid = alc662_look_for_dac(codec, pin);
- if (!nid) {
char name[32];
/* the corresponding DAC is already occupied */
if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
return 0; /* no way */
sprintf(name, "%s Playback Switch", pfx);/* create a switch only */
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
return err;
return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
}HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (alc880_is_fixed_pin(pin)) {
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
/* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
/* specify the DAC as the extra output */
if (!spec->multiout.hp_nid)
spec->multiout.hp_nid = nid;
else
spec->multiout.extra_out_nid[0] = nid;
/* control HP volume/switch on the output mixer amp */
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
sprintf(name, "%s Playback Volume", pfx);
err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_BIND_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
if (err < 0)
return err;
- } else if (alc880_is_multi_pin(pin)) {
/* set manual connection */
/* we have only a switch on HP-out PIN */
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
- }
- return 0;
- mix = alc662_dac_to_mix(codec, pin, nid);
- if (!mix)
return 0;
- err = alc662_add_vol_ctl(spec, pfx, nid, 3);
- if (err < 0)
return err;
- err = alc662_add_sw_ctl(spec, pfx, mix, 3);
- if (err < 0)
return err;
- return nid;
}
/* create playback/capture controls for input pins */ @@ -17274,30 +17333,35 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type,
int dac_idx)
hda_nid_t dac)
{
- int i, num;
- hda_nid_t srcs[4];
- alc_set_pin_output(codec, nid, pin_type); /* need the manual connection? */
- if (alc880_is_multi_pin(nid)) {
struct alc_spec *spec = codec->spec;
int idx = alc880_multi_pin_idx(nid);
snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
AC_VERB_SET_CONNECT_SEL,
alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
- num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
- if (num <= 1)
return;
- for (i = 0; i < num; i++) {
if (alc662_mix_to_dac(srcs[i]) != dac)
continue;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
}return;
}
static void alc662_auto_init_multi_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec;
int pin_type = get_pin_type(spec->autocfg.line_out_type); int i;
for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i];
if (nid) alc662_auto_set_output_and_unmute(codec, nid, pin_type,int pin_type = get_pin_type(spec->autocfg.line_out_type);
i);
}spec->multiout.dac_nids[i]);
}
@@ -17307,12 +17371,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec) hda_nid_t pin;
pin = spec->autocfg.hp_pins[0];
- if (pin) /* connect to front */
/* use dac 0 */
alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
- if (pin)
alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
pin = spec->autocfg.speaker_pins[0]; if (pin)spec->multiout.hp_nid);
alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
spec->multiout.extra_out_nid[0]);
}
#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID @@ -17350,21 +17415,25 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (!spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */
- err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
- err = alc662_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err;
- err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
- err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err;
- err = alc662_auto_create_extra_out(spec,
- err = alc662_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0], "Speaker"); if (err < 0) return err;
- err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
- if (err)
spec->multiout.extra_out_nid[0] = err;
- err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], "Headphone"); if (err < 0) return err;
- if (err)
err = alc662_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err;spec->multiout.hp_nid = err;
At Wed, 7 Oct 2009 15:34:59 -0500 (CDT), manoj.iyer@canonical.com wrote:
Takashi San,
Like I reported earlier, the patch you mailed me (See patch below) breaks sound on Toshiba NB200/205 again, even with my quirk.
This can't be. The patch I sent changes only the auto-parser, so with the quirk it must be skipped.
Any chance that we can work on getting this fixed? If you point me in the right direction I can dig into this some, also, mainline http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.32-rc1/ does not work. iirc, you mentioned that this patch made it into mainline as well.
Try 2.6.32-rc3 as is. If it doesn't work, please give alsa-info.sh output back.
thanks,
Takashi
Thanks
On Thu, 1 Oct 2009, Takashi Iwai wrote:
At Thu, 01 Oct 2009 10:26:05 +0200, I wrote:
At Thu, 1 Oct 2009 02:11:35 -0500 (CDT), manoj.iyer@canonical.com wrote:
2.6.31.x is way too old for testing the new stuff :) Any chance to test 2.6.32-rc1?
http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.32-rc1/
I tried the 2.6.32-rc1 today, and sound does not work for me on the NB200.
OK, thanks for checking. After looking at the code a bit more deeply, it turned out that the BIOS auto-parser doesn't work with this particular configuration (the speaker with mono pin 0x17).
I'm going to fix it later, but I applied your patch as the quick fix for the time being.
Could you try the patch below with model=auto? This will make the auto-parser working, hopefully.
thanks,
Takashi
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 87da5e8..7810d3d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -17146,70 +17146,145 @@ static struct alc_config_preset alc662_presets[] = {
- BIOS auto configuration
*/
+/* convert from MIX nid to DAC */ +static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid) +{
- if (nid == 0x0f)
return 0x02;
- else if (nid >= 0x0c && nid <= 0x0e)
return nid - 0x0c + 0x02;
- else
return 0;
+}
+/* get MIX nid connected to the given pin targeted to DAC */ +static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
hda_nid_t dac)
+{
- hda_nid_t mix[4];
- int i, num;
- num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
- for (i = 0; i < num; i++) {
if (alc662_mix_to_dac(mix[i]) == dac)
return mix[i];
- }
- return 0;
+}
+/* look for an empty DAC slot */ +static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin) +{
- struct alc_spec *spec = codec->spec;
- hda_nid_t srcs[5];
- int i, j, num;
- num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
- if (num < 0)
return 0;
- for (i = 0; i < num; i++) {
hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
if (!nid)
continue;
for (j = 0; j < spec->multiout.num_dacs; j++)
if (spec->multiout.dac_nids[j] == nid)
break;
if (j >= spec->multiout.num_dacs)
return nid;
- }
- return 0;
+}
+/* fill in the dac_nids table from the parsed pin configuration */ +static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
+{
- struct alc_spec *spec = codec->spec;
- int i;
- hda_nid_t dac;
- spec->multiout.dac_nids = spec->private_dac_nids;
- for (i = 0; i < cfg->line_outs; i++) {
dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
if (!dac)
continue;
spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
- }
- return 0;
+}
+static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
+{
- char name[32];
- sprintf(name, "%s Playback Volume", pfx);
- return add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+}
+static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
+{
- char name[32];
- sprintf(name, "%s Playback Switch", pfx);
- return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
+}
+#define alc662_add_stereo_vol(spec, pfx, nid) \
- alc662_add_vol_ctl(spec, pfx, nid, 3)
+#define alc662_add_stereo_sw(spec, pfx, nid) \
- alc662_add_sw_ctl(spec, pfx, nid, 3)
/* add playback controls from the parsed DAC table */ -static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, +static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) {
- char name[32];
- struct alc_spec *spec = codec->spec; static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
- hda_nid_t nid;
hda_nid_t nid, mix; int i, err;
for (i = 0; i < cfg->line_outs; i++) {
if (!spec->multiout.dac_nids[i])
nid = spec->multiout.dac_nids[i];
if (!nid)
continue;
mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
if (!mix) continue;
if (i == 2) { /* Center/LFE */nid = alc880_idx_to_dac(i);
err = add_control(spec, ALC_CTL_WIDGET_VOL,
"Center Playback Volume",
HDA_COMPOSE_AMP_VAL(nid, 1, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, "Center", nid, 1); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_VOL,
"LFE Playback Volume",
HDA_COMPOSE_AMP_VAL(nid, 2, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, "LFE", nid, 2); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_MUTE,
"Center Playback Switch",
HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
HDA_INPUT));
err = alc662_add_sw_ctl(spec, "Center", mix, 1); if (err < 0) return err;
err = add_control(spec, ALC_CTL_WIDGET_MUTE,
"LFE Playback Switch",
HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
HDA_INPUT));
} else { const char *pfx; if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {err = alc662_add_sw_ctl(spec, "LFE", mix, 2); if (err < 0) return err;
if (!cfg->hp_pins)
if (cfg->hp_outs) pfx = "Speaker"; else pfx = "PCM"; } else pfx = chname[i];
sprintf(name, "%s Playback Volume", pfx);
err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 0,
HDA_OUTPUT));
err = alc662_add_vol_ctl(spec, pfx, nid, 3); if (err < 0) return err; if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) pfx = "Speaker";
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
3, 0, HDA_INPUT));
}err = alc662_add_sw_ctl(spec, pfx, mix, 3); if (err < 0) return err;
@@ -17218,54 +17293,38 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, }
/* add playback controls for speaker and HP outputs */ -static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, +/* return DAC nid if any new DAC is assigned */ +static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, const char *pfx) {
- hda_nid_t nid;
- struct alc_spec *spec = codec->spec;
- hda_nid_t nid, mix; int err;
char name[32];
if (!pin) return 0;
if (pin == 0x17) {
/* ALC663 has a mono output pin on 0x17 */
- nid = alc662_look_for_dac(codec, pin);
- if (!nid) {
char name[32];
/* the corresponding DAC is already occupied */
if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
return 0; /* no way */
sprintf(name, "%s Playback Switch", pfx);/* create a switch only */
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
return err;
return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
}HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (alc880_is_fixed_pin(pin)) {
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
/* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
/* specify the DAC as the extra output */
if (!spec->multiout.hp_nid)
spec->multiout.hp_nid = nid;
else
spec->multiout.extra_out_nid[0] = nid;
/* control HP volume/switch on the output mixer amp */
nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
sprintf(name, "%s Playback Volume", pfx);
err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_BIND_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
if (err < 0)
return err;
- } else if (alc880_is_multi_pin(pin)) {
/* set manual connection */
/* we have only a switch on HP-out PIN */
sprintf(name, "%s Playback Switch", pfx);
err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
- }
- return 0;
- mix = alc662_dac_to_mix(codec, pin, nid);
- if (!mix)
return 0;
- err = alc662_add_vol_ctl(spec, pfx, nid, 3);
- if (err < 0)
return err;
- err = alc662_add_sw_ctl(spec, pfx, mix, 3);
- if (err < 0)
return err;
- return nid;
}
/* create playback/capture controls for input pins */ @@ -17274,30 +17333,35 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type,
int dac_idx)
hda_nid_t dac)
{
- int i, num;
- hda_nid_t srcs[4];
- alc_set_pin_output(codec, nid, pin_type); /* need the manual connection? */
- if (alc880_is_multi_pin(nid)) {
struct alc_spec *spec = codec->spec;
int idx = alc880_multi_pin_idx(nid);
snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
AC_VERB_SET_CONNECT_SEL,
alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
- num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
- if (num <= 1)
return;
- for (i = 0; i < num; i++) {
if (alc662_mix_to_dac(srcs[i]) != dac)
continue;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
}return;
}
static void alc662_auto_init_multi_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec;
int pin_type = get_pin_type(spec->autocfg.line_out_type); int i;
for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i];
if (nid) alc662_auto_set_output_and_unmute(codec, nid, pin_type,int pin_type = get_pin_type(spec->autocfg.line_out_type);
i);
}spec->multiout.dac_nids[i]);
}
@@ -17307,12 +17371,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec) hda_nid_t pin;
pin = spec->autocfg.hp_pins[0];
- if (pin) /* connect to front */
/* use dac 0 */
alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
- if (pin)
alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
pin = spec->autocfg.speaker_pins[0]; if (pin)spec->multiout.hp_nid);
alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
spec->multiout.extra_out_nid[0]);
}
#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID @@ -17350,21 +17415,25 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (!spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */
- err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
- err = alc662_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err;
- err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
- err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err;
- err = alc662_auto_create_extra_out(spec,
- err = alc662_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0], "Speaker"); if (err < 0) return err;
- err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
- if (err)
spec->multiout.extra_out_nid[0] = err;
- err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], "Headphone"); if (err < 0) return err;
- if (err)
err = alc662_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err;spec->multiout.hp_nid = err;
participants (2)
-
manoj.iyer@canonical.com
-
Takashi Iwai