[alsa-devel] [ALC668]: Asus N751JK - Incorrect default pin assignment for external base speaker and external microphone not working

Arthur Borsboom arthurborsboom at gmail.com
Thu Jul 9 20:34:35 CEST 2015


Hi Raymond,

I would like to apply your patches to a Linux kernel tree, so I can test
them.
However, the patches get rejected against Mainline kernel 4.1.1 and
4.2.0-rc1.

What kernel version did you use to write these patches?

On 6 July 2015 at 05:19, Raymond Yau <superquad.vortex2 at gmail.com> wrote:

> >
> > I have tested the patch by manually adding the lines of code into
> mainline kernel 4.1.1.
> >
> > The base speakers works.
>
> Do you need special name for the external subwoofer jack detect control
> for pulseaudio automatically switch from stereo profile to 2.1 profile ?
>
> int snd_hda_jack_add_kctls(struct hda_codec *codec,
>    const struct auto_pin_cfg *cfg)
> {
> const hda_nid_t *p;
> int i, err;
>
> ...
>
> for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) {
> +     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;
> }
>
> > The headset microphone works.
> > The headphone, headset microphone and microphone jack detection seems to
> work in PulseAudio (showing by plugged or unplugged status).
> > However it does not automatically switch the (un)plugged microphone.
> > My guess is that it does not know if it should use the headset
> microphone or the microphone (instead of the default internal microphone).
> >
> > Do you think there is a way to automate the forward and backward
> switching between the internal microphone and headset microphone?
> >
>
>
> http://bazaar.launchpad.net/~unity-settings-daemon-team/unity-settings-daemon/trunk/view/head:/plugins/media-keys/what-did-you-plug-in/pa-backend.c
>
>   Headphone Mic Jack - indicates headphone and mic-in mode share the same
> jack,  i e, not two separate jacks. Hardware cannot distinguish between
> headphone and a mic.
>    Headset Mic Phantom Jack - indicates headset jack where hardware can
> not distinguish between headphones and headsets
>    Headset Mic Jack - indicates headset jack where hardware can
> distinguish between headphones and headsets. There is no use popping up a
> dialog in this case, unless we already need to do this for the mic-in mode.
>
> Auto mic need headset mic support jack detection
>
> There are two methods, both methods need to give up the capability of
> using headphone and mic
>
> cannot use hint for user to select this feature since user hint is applied
> after pin fixup
>
> 1) create headset mic jack as slave of headphone jack , this use headphone
> jack sense for the jack state of headset mic
>
>         spec->gen.combo_use_only_as_headset = 0;
>
> 2) change headphone jack to headset jack, this require add [Element
> Headset] to pulseaudio conf files
>
>         spec->gen.headset_and_no_hp = 0;
>
> Method 1 -
>
> Cons - hda-emu cannot emulate this master slave jack ctl and gated/gating
> jack ctl
>
> Method 2
>
> Cons - some notebook has
>
> a) headset and headphone jacks
>
> b)r headset and dock headset
>
>
> diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
> index ac0db16..7e9b7ae 100644
> --- a/sound/pci/hda/hda_generic.c
> +++ b/sound/pci/hda/hda_generic.c
> @@ -4384,6 +4384,9 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec
> *codec,
>          /* don't detect pins retasked as outputs */
>          if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN)
>              continue;
> +        if (pin == spec->headset_mic_pin)
> +            if (spec->headset_and_no_hp)
> +                pin = spec->autocfg.hp_pins[0];
>          if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) {
>              mux_select(codec, 0, spec->am_entry[i].idx);
>              return;
> diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
> index 56e4139..4c3e043 100644
> --- a/sound/pci/hda/hda_generic.h
> +++ b/sound/pci/hda/hda_generic.h
> @@ -236,6 +236,10 @@ 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 combo_use_only_as_headset:1;  /* headphone mic jack -
> slave of headphone jack */
> +    unsigned int headset_and_no_hp:1;  /* headset jack */
> +
> +    hda_nid_t headset_mic_pin;
>
>      /* 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..771e84f 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,10 @@ 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);
> +        if (jack->master_nid)
> +            jack->pin_sense = read_pin_sense(codec, jack->master_nid);
> +        else
> +            jack->pin_sense = read_pin_sense(codec, jack->nid);
>
>      /* A gating jack indicates the jack is invalid if gating is unplugged
> */
>      if (jack->gating_jack && !snd_hda_jack_detect(codec,
> jack->gating_jack))
> @@ -205,11 +209,20 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all);
>  u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
>  {
>      struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
> +    struct hda_jack_tbl *slave;
> +    u32 sense;
>      if (jack) {
>          jack_detect_update(codec, jack);
>          return jack->pin_sense;
>      }
> -    return read_pin_sense(codec, nid);
> +    if (jack->master_nid)
> +        return read_pin_sense(codec, jack->master_nid);
> +    sense = read_pin_sense(codec, nid);
> +    if (jack->slave_nid) {
> +        slave = snd_hda_jack_tbl_get(codec, jack->slave_nid);
> +        slave->pin_sense = sense;
> +    }
> +    return sense;
>  }
>  EXPORT_SYMBOL_GPL(snd_hda_pin_sense);
>
> @@ -317,6 +330,28 @@ int snd_hda_jack_set_gating_jack(struct hda_codec
> *codec, hda_nid_t gated_nid,
>  EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack);
>
>  /**
> + * snd_hda_jack_set_master_slave
> + * @codec: the HDA codec
> + * @master_nid: use this nid for pin sense
> + * @slave_nid:  update slave jack pin sense
> + * use master pin sense for slave pin sense
> + */
> +int snd_hda_jack_set_master_slave(struct hda_codec *codec, hda_nid_t
> master_nid,
> +                 hda_nid_t slave_nid)
> +{
> +    struct hda_jack_tbl *master = snd_hda_jack_tbl_get(codec, master_nid);
> +    struct hda_jack_tbl *slave = snd_hda_jack_tbl_get(codec, slave_nid);
> +    if (master)
> +        master->slave_nid = slave_nid;
> +    if (slave) {
> +        slave->master_nid = master_nid;
> +        snd_hda_codec_write_cache(codec, slave_nid, 0,
> +                     AC_VERB_SET_UNSOLICITED_ENABLE, 0);
> +    }
> +    return 0;
> +}
> +
> +/**
>   * snd_hda_jack_report_sync - sync the states of all jacks and report if
> changed
>   * @codec: the HDA codec
>   */
> @@ -469,7 +504,8 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
>                 const struct auto_pin_cfg *cfg)
>  {
>      const hda_nid_t *p;
> -    int i, err;
> +    int i, err, loc;
> +    struct hda_gen_spec *spec = codec->spec;
>
>      for (i = 0; i < cfg->num_inputs; i++) {
>          /* If we have headphone mics; make sure they get the right name
> @@ -481,22 +517,37 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
>              else
>                  err = add_jack_kctl(codec, cfg->inputs[i].pin,
>                              cfg, "Headphone Mic");
> -        } else
> -            err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg,
> +        } else {
> +            if (cfg->inputs[i].is_headset_mic) {
> +                if (!spec->headset_and_no_hp)
> +                    err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg,
> NULL);
> +                else
> +                    err = 0;
> +            }
> +            else
> +                err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg,
>                          NULL);
> +        }
>          if (err < 0)
>              return err;
>      }
>
>      for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) {
> -        err = add_jack_kctl(codec, *p, cfg, NULL);
> +        loc = get_defcfg_location(get_wcaps(codec, *p));
> +        if (i == 1 && cfg->line_outs == 2 && loc == AC_JACK_LOC_EXTERNAL)
> +            err = add_jack_kctl(codec, *p, cfg, "External Subwoofer");
> +        else
> +            err = add_jack_kctl(codec, *p, cfg, NULL);
>          if (err < 0)
>              return err;
>      }
>      for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) {
>          if (*p == *cfg->line_out_pins) /* might be duplicated */
>              break;
> -        err = add_jack_kctl(codec, *p, cfg, NULL);
> +        if (spec->headset_and_no_hp && i == 0)
> +            err = add_jack_kctl(codec, *p, cfg, "Headset");
> +        else
> +            err = add_jack_kctl(codec, *p, cfg, NULL);
>          if (err < 0)
>              return err;
>      }
> @@ -507,6 +558,13 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
>          if (err < 0)
>              return err;
>      }
> +
> +    if (spec->combo_use_only_as_headset)
> +        for (i = 0; i < cfg->num_inputs; i++) {
> +            if (cfg->inputs[i].is_headset_mic)
> +                snd_hda_jack_set_master_slave(codec, cfg->hp_pins[0],
> cfg->inputs[i].pin);
> +        }
> +
>      for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) {
>          err = add_jack_kctl(codec, *p, cfg, NULL);
>          if (err < 0)
> diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
> index 387d309..364cfa5 100644
> --- a/sound/pci/hda/hda_jack.h
> +++ b/sound/pci/hda/hda_jack.h
> @@ -39,6 +39,8 @@ struct hda_jack_tbl {
>      unsigned int block_report:1;    /* in a transitional state - do not
> report to userspace */
>      hda_nid_t gating_jack;        /* valid when gating jack plugged */
>      hda_nid_t gated_jack;        /* gated is dependent on this jack */
> +    hda_nid_t master_nid;        /* use master_nid for jack sense */
> +    hda_nid_t slave_nid;        /* update slave_nid jack state */
>      int type;
>      struct snd_jack *jack;
>  };
> diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
> index 8e02cdf..598a442 100644
> --- a/sound/pci/hda/patch_realtek.c
> +++ b/sound/pci/hda/patch_realtek.c
> @@ -3998,6 +3998,16 @@ static void alc_update_headset_mode(struct
> hda_codec *codec)
>          return;
>      }
>
> +    if (spec->gen.combo_use_only_as_headset ||
> +        spec->gen.headset_and_no_hp) {
> +        if (snd_hda_jack_detect(codec, hp_pin)) {
> +            new_headset_mode = ALC_HEADSET_MODE_HEADSET;
> +            alc_determine_headset_type(codec);
> +            codec_info(codec, "mic_autoswitch\n");
> +            snd_hda_gen_mic_autoswitch(codec, NULL);
> +        }
> +    }
> +
>      switch (new_headset_mode) {
>      case ALC_HEADSET_MODE_UNPLUGGED:
>          alc_headset_mode_unplugged(codec);
> @@ -4056,8 +4066,10 @@ static void alc_probe_headset_mode(struct hda_codec
> *codec)
>
>      /* Find mic pins */
>      for (i = 0; i < cfg->num_inputs; i++) {
> -        if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin)
> +        if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin) {
>              spec->headset_mic_pin = cfg->inputs[i].pin;
> +            spec->gen.headset_mic_pin = spec->headset_mic_pin;
> +        }
>          if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin)
>              spec->headphone_mic_pin = cfg->inputs[i].pin;
>      }
> @@ -4074,7 +4086,11 @@ static void alc_fixup_headset_mode(struct hda_codec
> *codec,
>
>      switch (action) {
>      case HDA_FIXUP_ACT_PRE_PROBE:
> -        spec->parse_flags |= HDA_PINCFG_HEADSET_MIC |
> HDA_PINCFG_HEADPHONE_MIC;
> +        if (spec->gen.combo_use_only_as_headset ||
> +            spec->gen.headset_and_no_hp)
> +            spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> +        else
> +            spec->parse_flags |= HDA_PINCFG_HEADSET_MIC |
> HDA_PINCFG_HEADPHONE_MIC;
>          break;
>      case HDA_FIXUP_ACT_PROBE:
>          alc_probe_headset_mode(codec);
> @@ -6149,6 +6165,43 @@ static void alc668_restore_default_value(struct
> hda_codec *codec)
>      alc_process_coef_fw(codec, alc668_coefs);
>  }
>
> +static void alc668_fixup_asus_n751jk(struct hda_codec *codec,
> +                   const struct hda_fixup *fix, int action)
> +{
> +    struct alc_spec *spec = codec->spec;
> +    static const struct hda_pintbl normal_cfgs[] = {
> +        { 0x19, 0x03a1913d }, /* use as headphone mic, without its own
> jack detect */
> +        { 0x1a, 0x04110011 }, /* bass speaker at Ext Right with jack
> detect */
> +        { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack
> detect */
> +        { }
> +    };
> +    static const struct hda_pintbl headset_cfgs[] = {
> +        { 0x19, 0x411111f0 }, /* N/A */
> +        { 0x1a, 0x04110011 }, /* bass speaker at Ext Right with jack
> detect */
> +        { 0x1b, 0x03a1103c }, /* use as headset mic, without its own jack
> detect */
> +        { }
> +    };
> +    switch(action){
> +    case HDA_FIXUP_ACT_PRE_PROBE:
> +        spec->gen.combo_use_only_as_headset = 0;
> +        spec->gen.headset_and_no_hp = 0;
> +        codec_info(codec, "use as headset %d\n",
> spec->gen.combo_use_only_as_headset);
> +        if (spec->gen.combo_use_only_as_headset ||
> +            spec->gen.headset_and_no_hp) {
> +            snd_hda_apply_pincfgs(codec, headset_cfgs);
> +            spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> +        }
> +        else {
> +            snd_hda_apply_pincfgs(codec, normal_cfgs);
> +            spec->parse_flags |= HDA_PINCFG_HEADSET_MIC |
> HDA_PINCFG_HEADPHONE_MIC;
> +        }
> +        break;
> +    case HDA_FIXUP_ACT_BUILD:
> +        alc_fixup_bass_chmap(codec,  fix, action);
> +        break;
> +    }
> +}
> +
>  enum {
>      ALC662_FIXUP_ASPIRE,
>      ALC662_FIXUP_LED_GPIO1,
> @@ -6179,6 +6232,7 @@ enum {
>      ALC668_FIXUP_AUTO_MUTE,
>      ALC668_FIXUP_DELL_DISABLE_AAMIX,
>      ALC668_FIXUP_DELL_XPS13,
> +    ALC668_FIXUP_ASUS_N751JK,
>  };
>
>  static const struct hda_fixup alc662_fixups[] = {
> @@ -6419,6 +6473,12 @@ static const struct hda_fixup alc662_fixups[] = {
>          .type = HDA_FIXUP_FUNC,
>          .v.func = alc_fixup_bass_chmap,
>      },
> +    [ALC668_FIXUP_ASUS_N751JK] = {
> +        .type = HDA_FIXUP_FUNC,
> +        .v.func = alc668_fixup_asus_n751jk,
> +        .chained = true,
> +        .chain_id = ALC668_FIXUP_HEADSET_MODE,
> +    },
>  };
>
>  static const struct snd_pci_quirk alc662_fixup_tbl[] = {
> @@ -6441,6 +6501,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[]
> = {
>      SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
>      SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A),
>      SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ",
> ALC662_FIXUP_BASS_MODE4_CHMAP),
> +    SND_PCI_QUIRK(0x1043, 0x17bd, "Asus N751JK",
> ALC668_FIXUP_ASUS_N751JK),
>      SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
>      SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
>      SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ",
> ALC662_FIXUP_BASS_MODE4_CHMAP),
>
>
>


-- 
Arthur Borsboom
Lieven de Keystraat 77
3067 KG, Rotterdam
The Netherlands
Mob: +31629089953
Email: arthurborsboom at gmail.com
Skype: Arthur Borsboom, The Hague, The Netherlands

[image: View Arthur's LinkedIn profile]
<http://uk.linkedin.com/in/arthurborsboom>


More information about the Alsa-devel mailing list