At Wed, 22 Aug 2007 11:20:50 +0200, I wrote:
- When recording from the internal microphone the level is very, very low and almost
drowns in static noise.
There are "Mic Boost" and "Front Mic Boost" mixer volumes.
Not with model=laptop-eapd - my alas mixer only shows Master, PCM, Mic, Capture, Mix, External Amp and Internal Amp
The Mic Boost control was added _after_ 1.0.14 release. (Correction in the above text: Front Mic Boost doesn't exist for AD1986A but for other codec.)
So, please try HG version first. Then let's debug further.
Note that the auto-mute feature isn't implemented yet in HG version, too. But the mic boost should work at least.
The below is the untested patch for adding the auto-mute feature. A new model laptop-automute is implemented. Of course, it's against the latest HG version. Give it a try.
Takashi
diff -r 409d36cdf3b2 Documentation/ALSA-Configuration.txt --- a/Documentation/ALSA-Configuration.txt Wed Aug 22 09:45:03 2007 +0200 +++ b/Documentation/ALSA-Configuration.txt Wed Aug 22 11:51:09 2007 +0200 @@ -932,6 +932,7 @@ Prior to version 0.9.0rc4 options had a 3stack 3-stack, shared surrounds laptop 2-channel only (FSC V2060, Samsung M50) laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) + laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) ultra 2-channel with EAPD (Samsung Ultra tablet PC)
AD1988 diff -r 409d36cdf3b2 pci/hda/patch_analog.c --- a/pci/hda/patch_analog.c Wed Aug 22 09:45:03 2007 +0200 +++ b/pci/hda/patch_analog.c Wed Aug 22 11:51:09 2007 +0200 @@ -73,6 +73,8 @@ struct ad198x_spec { struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[4]; + + unsigned int jack_present :1;
#ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; @@ -568,6 +570,106 @@ static struct snd_kcontrol_new ad1986a_l HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "External Amplifier", + .info = ad198x_eapd_info, + .get = ad198x_eapd_get, + .put = ad198x_eapd_put, + .private_value = 0x1b | (1 << 8), /* port-D, inversed */ + }, + { } /* end */ +}; + +/* laptop-automute - 2ch only */ + +static void ad1986a_update_hp(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + unsigned int mute; + + if (spec->jack_present) + mute = HDA_AMP_MUTE; /* mute internal speaker */ + else + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); +} + +static void ad1986a_hp_automute(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + ad1986a_update_hp(codec); +} + +#define AD1986A_HP_EVENT 0x37 + +static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) != AD1986A_HP_EVENT) + return; + ad1986a_hp_automute(codec); +} + +static int ad1986a_hp_init(struct hda_codec *codec) +{ + ad198x_init(codec); + ad1986a_hp_automute(codec); + return 0; +} + +/* bind hp and internal speaker mute (with plug check) */ +static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) + ad1986a_update_hp(codec); + return change; +} + +static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = { + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = ad1986a_hp_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x18, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x18, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), { @@ -701,12 +803,20 @@ static struct hda_verb ad1986a_ultra_ini { } /* end */ };
+/* pin sensing on HP jack */ +static struct hda_verb ad1986a_hp_init_verbs[] = { + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, + {} +}; + + /* models */ enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD, + AD1986A_LAPTOP_AUTOMUTE, AD1986A_ULTRA, AD1986A_MODELS }; @@ -716,6 +826,7 @@ static const char *ad1986a_models[AD1986 [AD1986A_3STACK] = "3stack", [AD1986A_LAPTOP] = "laptop", [AD1986A_LAPTOP_EAPD] = "laptop-eapd", + [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", [AD1986A_ULTRA] = "ultra", };
@@ -744,7 +855,7 @@ static struct snd_pci_quirk ad1986a_cfg_ SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), - SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), {} }; @@ -820,6 +931,19 @@ static int patch_ad1986a(struct hda_code spec->multiout.dac_nids = ad1986a_laptop_dac_nids; spec->multiout.dig_out_nid = 0; spec->input_mux = &ad1986a_laptop_eapd_capture_source; + break; + case AD1986A_LAPTOP_AUTOMUTE: + spec->mixers[0] = ad1986a_laptop_automute_mixers; + spec->num_init_verbs = 3; + spec->init_verbs[1] = ad1986a_eapd_init_verbs; + spec->init_verbs[2] = ad1986a_hp_init_verbs; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = ad1986a_laptop_dac_nids; + spec->multiout.dig_out_nid = 0; + spec->input_mux = &ad1986a_laptop_eapd_capture_source; + codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; + codec->patch_ops.init = ad1986a_hp_init; break; case AD1986A_ULTRA: spec->mixers[0] = ad1986a_laptop_eapd_mixers;