From patchwork Wed Aug 5 01:40:36 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raymond Yau X-Patchwork-Id: 6945481 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 9C6B2C05AC for ; Wed, 5 Aug 2015 01:41:21 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3A4CA2053C for ; Wed, 5 Aug 2015 01:41:20 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 44632205CA for ; Wed, 5 Aug 2015 01:41:18 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 604E1265A73; Wed, 5 Aug 2015 03:41:09 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id A1C8C2659FE; Wed, 5 Aug 2015 03:40:54 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 666772659FE; Wed, 5 Aug 2015 03:40:44 +0200 (CEST) Received: from mail-oi0-f49.google.com (mail-oi0-f49.google.com [209.85.218.49]) by alsa0.perex.cz (Postfix) with ESMTP id 645F4265A36 for ; Wed, 5 Aug 2015 03:40:38 +0200 (CEST) Received: by oio137 with SMTP id 137so11482760oio.0 for ; Tue, 04 Aug 2015 18:40:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=mmtNTOs0iRC8pk/o9Jb264yTHxcla3Ko3e9H36KqR+I=; b=DfbY58gG9/RAWNqIoTiIuXKfx5+JhCKmnSwqu76KJWeT3pYaGKEo1q1n43WePoB4Y2 gAIvXS5ZnBXp9QxXLmdZLDIVRDH32CL++qQdBlJAMlHEcrmyiLFeLAwcSjfCcRzxSUW+ ms4Kj8zA49lS19/oSSgBxiQ5CsOxWaiWbSNTxUwzBDPNNIAq3mT019e/84Z1NxziHkV3 akMv11RoST/yhNpV7+9qxPM6AR8SyLAN6GJ13Mn6te7C8wFk9cAwppgU4cbAOQZ4w19I 32DhXwIymRt4887yyndLqqfhCW7XFJnc0hvIWsYdYFBuhfFpoiKDQSJ44LAo0yY19c9k bVlA== MIME-Version: 1.0 X-Received: by 10.202.49.196 with SMTP id x187mr5570942oix.81.1438738837237; Tue, 04 Aug 2015 18:40:37 -0700 (PDT) Received: by 10.202.63.197 with HTTP; Tue, 4 Aug 2015 18:40:36 -0700 (PDT) In-Reply-To: References: Date: Wed, 5 Aug 2015 09:40:36 +0800 Message-ID: From: Raymond Yau To: Arthur Borsboom X-Content-Filtered-By: Mailman/MimeDel 2.1.14 Cc: tiwai@suse.de, ALSA Development Mailing List , kailang@realtek.com, David Henningsson Subject: Re: [alsa-devel] [ALC668]: Asus N751JK - mic selection not working X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP > -------------------------------- > 2. External microphone > -------------------------------- > The Asus N751JK notebook (ALC668) has a 3,5mm 4-ring combo jack for > headphones and microphone. > The headphone is detected correct and auto-mute works good (jack detection). > The microphone is not detected and does not work. > I was unable to get it to work with hdajackretask or any of the Asus model settings, such as: > * options snd_hda_intel model=,asus-mode4 > I was able to get the microphone to work with the following setting: > * options snd_hda_intel model=,dell-headset-multi > This setting creates two new items in PulseAudio making a total of three: > * Internal microphone (works out of the box) > * Headset microphone (works indeed with a headset) > * Microphone (don't know if this works, since I don't have a single > microphone, but it does not work with the headset) > Unfortunately the auto-input-device-switch to the Headset microphone does > not seem to work. > When I plugin a headset, the headphones get detected and the Internal speakers are muted. > The Input device does not automatically switch from Internal microphone to Headset microphone. > I have to do this manually, after which it works. > I don't know if the microphone has a jack detection. > If it does not, maybe it is possible to use the headphones jack detection? > I have added the alsa-info without any snd_intel / alsa modifications here: http://www.alsa-project.org/db/?f=0b5135bd12f28bb5cb182f83bfa21bc50022faa6 > Result of "pactl list sources" plugged and unplugged in this order, with your previous patches applied. > > > Nothing: http://pastebin.com/RWuiW0RG > Headphones: http://pastebin.com/GvEkQ8HB > Microphone: http://pastebin.com/NRiREULS > Headset: http://pastebin.com/QuGLFD8A > Subwoofer: http://pastebin.com/nxZNGgyY > > For dell-headset-multi, [JACK Headphone Mic] may need fix in pulseaudio conf files However it seem that Sound Preference in Mate Ubutnu 15.10 Alpha only show active port of the source and You have to use pavucontrol to change the Capture Source/Active port manually after you plug the jack Following is a variant of the dell-headset-multi which support headset only asus_headset model require 1) pin fixup only the headset mic pin and no headphone mic pin 2) create "Headset Mic Jack" kctl by spec->hs_mic_use_hp_sense and new version of __snd_hda_jack_add_kct() with hp_pin as sense_nid "Headset Mic Jack" is also slave of "Headphone Jack" 3) modify check_auto_mic_availability() to allow auto mic selection for headset mic which use hs_mic_use_hp_sense 4) update mux_pin for alc668 codec when spec->auto_mic and alc668_combo_type is equal to ALC_HEADSET_MODE_HEADSET by snd_hda_gen_mic_autoswitch() This new model only support headset and it does not support headphone nor mic, only headphone has event input device and no headset mic event input For Dell Alienware 14, 17 and 18 which have three jacks: headset, headphone and mic, auto_mic is not enabled since two of the three capture sources are detectable diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index b077bb6..a96c56b 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -2097,14 +2097,21 @@ static int create_extra_out(struct hda_codec *codec, int path_idx, { struct nid_path *path; int err; + struct hda_gen_spec *spec = codec->spec; path = snd_hda_get_path_from_idx(codec, path_idx); if (!path) return 0; - err = add_stereo_vol(codec, pfx, cidx, path); + if ((strcmp(pfx, "Headphone") == 0) && spec->hs_mic_use_hp_sense) + err = add_stereo_vol(codec, "Headset", cidx, path); + else + err = add_stereo_vol(codec, pfx, cidx, path); if (err < 0) return err; - err = add_stereo_sw(codec, pfx, cidx, path); + if ((strcmp(pfx, "Headphone") == 0) && spec->hs_mic_use_hp_sense) + err = add_stereo_sw(codec, "Headset", cidx, path); + else + err = add_stereo_sw(codec, pfx, cidx, path); if (err < 0) return err; return 0; @@ -4665,7 +4672,9 @@ static int check_auto_mic_availability(struct hda_codec *codec) if (!spec->line_in_auto_switch && cfg->inputs[i].type != AUTO_PIN_MIC) return 0; /* only mic is allowed */ - if (!is_jack_detectable(codec, nid)) + if (!is_jack_detectable(codec, nid) && + !(spec->hs_mic_use_hp_sense && + cfg->inputs[i].is_headset_mic)) return 0; /* no unsol support */ break; } diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 56e4139..96f8214 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -236,6 +236,7 @@ struct hda_gen_spec { unsigned int indep_hp_enabled:1; /* independent HP enabled */ unsigned int have_aamix_ctl:1; unsigned int hp_mic_jack_modes:1; + unsigned int hs_mic_use_hp_sense:1; /* additional mute flags (only effective with auto_mute_via_amp=1) */ u64 mute_bits; diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 366efbf..2f308a5 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -19,6 +19,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" +#include "hda_generic.h" /** * is_jack_detectable - Check whether the given pin is jack-detectable @@ -157,7 +158,15 @@ static void jack_detect_update(struct hda_codec *codec, if (jack->phantom_jack) jack->pin_sense = AC_PINSENSE_PRESENCE; else - jack->pin_sense = read_pin_sense(codec, jack->nid); + jack->pin_sense = read_pin_sense(codec, + jack->sense_nid ? jack->sense_nid : jack->nid); + + if (jack->slave_nid) { + struct hda_jack_tbl *slave = + snd_hda_jack_tbl_get(codec, jack->slave_nid); + if (slave) + slave->pin_sense = jack->pin_sense; + } /* A gating jack indicates the jack is invalid if gating is unplugged */ if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack)) @@ -209,6 +218,8 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) jack_detect_update(codec, jack); return jack->pin_sense; } + if (jack->sense_nid) + return read_pin_sense(codec, jack->sense_nid); return read_pin_sense(codec, nid); } EXPORT_SYMBOL_GPL(snd_hda_pin_sense); @@ -384,7 +395,7 @@ static void hda_free_jack_priv(struct snd_jack *jack) * will have the given name and index. */ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, - const char *name, bool phantom_jack) + const char *name, bool phantom_jack, hda_nid_t sense_nid) { struct hda_jack_tbl *jack; int err, state, type; @@ -405,6 +416,7 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, jack->type = type; jack->jack->private_data = jack; jack->jack->private_free = hda_free_jack_priv; + jack->sense_nid = sense_nid; state = snd_hda_jack_detect(codec, nid); snd_jack_report(jack->jack, state ? jack->type : 0); @@ -422,7 +434,7 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, const char *name) { - return __snd_hda_jack_add_kctl(codec, nid, name, false); + return __snd_hda_jack_add_kctl(codec, nid, name, false, nid); } EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl); @@ -451,7 +463,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, if (phantom_jack) /* Example final name: "Internal Mic Phantom Jack" */ strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); - err = __snd_hda_jack_add_kctl(codec, nid, name, phantom_jack); + err = __snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, nid); if (err < 0) return err; @@ -469,6 +481,9 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { const hda_nid_t *p; + struct hda_jack_tbl *jack; + hda_nid_t headset_mic_nid = 0; + struct hda_gen_spec *spec = codec->spec; int i, err; for (i = 0; i < cfg->num_inputs; i++) { @@ -482,6 +497,13 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, "Headphone Mic"); } else + if (cfg->inputs[i].is_headset_mic && + spec->hs_mic_use_hp_sense && + !is_jack_detectable(codec, cfg->inputs[i].pin)) { + headset_mic_nid = cfg->inputs[i].pin; + err = __snd_hda_jack_add_kctl(codec, cfg->inputs[i].pin, + "Headset Mic", false, auto_cfg_hp_pins(cfg)[0]); + } else err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, NULL); if (err < 0) @@ -489,7 +511,10 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, } for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { - err = add_jack_kctl(codec, *p, cfg, NULL); + if ((cfg->line_outs == 2) && (i == 1)) + err = add_jack_kctl(codec, *p, cfg, "External Subwoofer"); + else + err = add_jack_kctl(codec, *p, cfg, NULL); if (err < 0) return err; } @@ -499,6 +524,11 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, err = add_jack_kctl(codec, *p, cfg, NULL); if (err < 0) return err; + if ((i == 0) && spec->hs_mic_use_hp_sense) { + jack = snd_hda_jack_tbl_get(codec, *p); + if (jack) + jack->slave_nid = headset_mic_nid; + } } for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { if (*p == *cfg->line_out_pins) /* might be duplicated */ diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 387d309..ef3d162 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -41,6 +41,8 @@ struct hda_jack_tbl { hda_nid_t gated_jack; /* gated is dependent on this jack */ int type; struct snd_jack *jack; + hda_nid_t sense_nid; + hda_nid_t slave_nid; }; struct hda_jack_tbl * diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c456c04..a402ed5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -104,6 +104,7 @@ struct alc_spec { hda_nid_t headphone_mic_pin; int current_headset_mode; int current_headset_type; + int alc668_combo_type; /* hooks */ void (*init_hook)(struct hda_codec *codec); @@ -3984,6 +3985,15 @@ static void alc_update_headset_mode(struct hda_codec *codec) int new_headset_mode; + if (codec->core.vendor_id == 0x10ec0668 && + spec->alc668_combo_type) { + if (spec->alc668_combo_type == ALC_HEADSET_MODE_HEADSET && + spec->gen.auto_mic) { + snd_hda_gen_mic_autoswitch(codec, NULL); + mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; + } + } + if (!snd_hda_jack_detect(codec, hp_pin)) new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED; else if (mux_pin == spec->headset_mic_pin) @@ -6232,6 +6242,37 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec, } } +static void alc668_fixup_asus_headset(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + const struct hda_pintbl pincfgs[] = { + { 0x1a, 0x04110011 }, /* external subwoofer */ + { 0x1b, 0x03a1113c }, /* headset mic */ + { } + }; + + struct alc_spec *spec = codec->spec; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_apply_pincfgs(codec, pincfgs); + spec->gen.hs_mic_use_hp_sense = 1; + spec->alc668_combo_type = ALC_HEADSET_MODE_HEADSET; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + break; + case HDA_FIXUP_ACT_PROBE: + alc_probe_headset_mode(codec); + break; + case HDA_FIXUP_ACT_INIT: + spec->current_headset_mode = 0; + alc_update_headset_mode(codec); + break; + case HDA_FIXUP_ACT_BUILD: + alc_fixup_bass_chmap(codec, fix, action); + break; + } +} + /* avoid D3 for keeping GPIO up */ static unsigned int gpio_led_power_filter(struct hda_codec *codec, hda_nid_t nid, @@ -6313,6 +6354,7 @@ enum { ALC662_FIXUP_INV_DMIC, ALC662_FIXUP_DELL_MIC_NO_PRESENCE, ALC668_FIXUP_DELL_MIC_NO_PRESENCE, + ALC668_FIXUP_ASUS_HEADSET, ALC662_FIXUP_HEADSET_MODE, ALC668_FIXUP_HEADSET_MODE, ALC662_FIXUP_BASS_MODE4_CHMAP, @@ -6530,6 +6572,10 @@ static const struct hda_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC668_FIXUP_HEADSET_MODE }, + [ALC668_FIXUP_ASUS_HEADSET] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc668_fixup_asus_headset, + }, [ALC668_FIXUP_HEADSET_MODE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode_alc668, @@ -6667,6 +6713,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = { {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"}, {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"}, {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"}, + {.id = ALC668_FIXUP_ASUS_HEADSET, .name = "asus-headset"}, {} };