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

Message ID CAN8cciajhQsvasRPJuBGp9Hsj5vaiaczczDPAz5dR03UAad2Sg@mail.gmail.com
State New
Headers show

Commit Message

Raymond Yau July 6, 2015, 3:19 a.m. UTC
>
> 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


         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),

Comments

Arthur Borsboom July 8, 2015, 6:51 a.m. UTC | #1
Hi Raymond,

First I think I am going to split this mail into two topics, starting with
the easiest one, the External Base speaker.

The code above added two new options: Surround 2.1 and Surround 4.0.
After plugging in the base speaker:

- The Base speaker plays without this code (but the previous code was
necessary) on the Speakers.
- The Base speaker does not play on Surround 2.1
- The Base speaker does play on Surround 4.0
- The Base speaker does not switch automatically to any Surround when
plugged in.

Recently I have been developing against the mainline Kernel 4.2-rc1, but it
gives me only kernel panics.
Than I realized that I should develop against the Alsa tree. What is the
best tree to develop patches against?

On 6 July 2015 at 05:19, Raymond Yau <superquad.vortex2@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 July 9, 2015, 6:34 p.m. UTC | #2
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@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),
>
>
>
Raymond Yau July 10, 2015, 7:49 a.m. UTC | #3
>
> First I think I am going to split this mail into two topics, starting
with the easiest one, the External Base speaker.
>
> The code above added two new options: Surround 2.1 and Surround 4.0.
> After plugging in the base speaker:
>
> - The Base speaker plays without this code (but the previous code was
necessary) on the Speakers.
> - The Base speaker does not play on Surround 2.1
> - The Base speaker does play on Surround 4.0
> - The Base speaker does not switch automatically to any Surround when
plugged in.

How do you test ? Using sound preference or alsa speaker-test

https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/commit/sound/pci/hda?id=8e38395360844806041ea69ab9690f5f174bc40c

Seem pulseaudio bug since driver only define stereo and 2.1 channel map
and  there is no surround 4.0 channel map

http://git.alsa-project.org/?p=alsa-lib.git;a=commitdiff;h=48f1b308cc66152eb6db66742dd0d08d888cda8d;hp=5c4cd46810cef8850b037fca9e38ffd43b0bff22

+       ttable.0.FL 1
+       ttable.1.FR 1
+       ttable.2.LFE 1

surround21 is supposed to be also used on 5.1 speaker since it only check

Do you mean it only work on 5.1 speaker since there are three combination
of 2.1 chmap ?

https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/commit/sound?id=ee81abb623cb5e03c182d16871bb4fb34fdc9b4f

1) hda default 2.1

{ .channels = 4,
  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
   SNDRV_CHMAP_LFE , SNDRV_CHMAP_LFE } },
{ }

2) acer aspire /* LFE only on left */

{ .channels = 4,
  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
   SNDRV_CHMAP_LFE, SNDRV_CHMAP_NA} }, /* LFE only on left */
{ }

3) LFE only on right on asus latop external sonic master subwoofer
{ .channels = 4,
  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
   SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */
{ }

speaker-test  don't check channel map

Those asus n series laptop with alc663 seem use  node 0x1e to for the
detection of external subwoofer but node 0x1e pincap does not support
detect and unsol event

This mean those subwoofer need to use __snd_hda_jack_add_kctl() which does
not check pincap and unsol event

This require change of __snd_hda_jack_add_kctl() by adding new parameter
sense_nid to use another nid for jack sense without enable unsol event

However there is bug in hda_jack implementation , snd_hda_jack_detect() can
be called in patch_realtek.c before creation of the jacktbl entry (i.e.
before snd_hda_jack_add_kctls()

https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/1040873/comments/115

Did you found the message  " lfe filter activated (LR4 type)" in pulseaudio
verbose log ?
Arthur Borsboom July 13, 2015, 7:12 a.m. UTC | #4
Hi Raymond,

Honestly some of the Alsa code talk is a bit over my head, so maybe I
should just stick to providing PCI/Vendor ID's and test results. :)

RY> How do you test ? Using sound preference or alsa speaker-test

I apply some of your code by retyping this into the mainline kernel 4.2-rc1
code, compile and install the kernel, and then test the audio.
The subwoofer I test by playing music with my music player, Audacious.
When testing different configurations and output profiles I use pavucontrol.
For testing the microphone, I open pavucontrol, switch the input source
between Internal Microphone and Microphone and look at the volumebar to see
if the microphone works fine.

Do you have suggestions how to apply and test the provided patches?

On 10 July 2015 at 09:49, Raymond Yau <superquad.vortex2@gmail.com> wrote:

>
> >
> > First I think I am going to split this mail into two topics, starting
> with the easiest one, the External Base speaker.
> >
> > The code above added two new options: Surround 2.1 and Surround 4.0.
> > After plugging in the base speaker:
> >
> > - The Base speaker plays without this code (but the previous code was
> necessary) on the Speakers.
> > - The Base speaker does not play on Surround 2.1
> > - The Base speaker does play on Surround 4.0
> > - The Base speaker does not switch automatically to any Surround when
> plugged in.
>
> How do you test ? Using sound preference or alsa speaker-test
>
>
> https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/commit/sound/pci/hda?id=8e38395360844806041ea69ab9690f5f174bc40c
>
> Seem pulseaudio bug since driver only define stereo and 2.1 channel map
> and  there is no surround 4.0 channel map
>
>
> http://git.alsa-project.org/?p=alsa-lib.git;a=commitdiff;h=48f1b308cc66152eb6db66742dd0d08d888cda8d;hp=5c4cd46810cef8850b037fca9e38ffd43b0bff22
>
> +       ttable.0.FL 1
> +       ttable.1.FR 1
> +       ttable.2.LFE 1
>
> surround21 is supposed to be also used on 5.1 speaker since it only check
>
> Do you mean it only work on 5.1 speaker since there are three combination
> of 2.1 chmap ?
>
>
> https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/commit/sound?id=ee81abb623cb5e03c182d16871bb4fb34fdc9b4f
>
> 1) hda default 2.1
>
> { .channels = 4,
>   .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
>    SNDRV_CHMAP_LFE , SNDRV_CHMAP_LFE } },
> { }
>
> 2) acer aspire /* LFE only on left */
>
> { .channels = 4,
>   .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
>    SNDRV_CHMAP_LFE, SNDRV_CHMAP_NA} }, /* LFE only on left */
> { }
>
> 3) LFE only on right on asus latop external sonic master subwoofer
> { .channels = 4,
>   .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
>    SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */
> { }
>
> speaker-test  don't check channel map
>
> Those asus n series laptop with alc663 seem use  node 0x1e to for the
> detection of external subwoofer but node 0x1e pincap does not support
> detect and unsol event
>
> This mean those subwoofer need to use __snd_hda_jack_add_kctl() which does
> not check pincap and unsol event
>
> This require change of __snd_hda_jack_add_kctl() by adding new parameter
> sense_nid to use another nid for jack sense without enable unsol event
>
> However there is bug in hda_jack implementation , snd_hda_jack_detect()
> can be called in patch_realtek.c before creation of the jacktbl entry (i.e.
> before snd_hda_jack_add_kctls()
>
>
> https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/1040873/comments/115
>
> Did you found the message  " lfe filter activated (LR4 type)" in
> pulseaudio verbose log ?
>
Raymond Yau July 13, 2015, 11:24 a.m. UTC | #5
>
> Honestly some of the Alsa code talk is a bit over my head, so maybe I
should just stick to providing PCI/Vendor ID's and test results. :)
>
> RY> How do you test ? Using sound preference or alsa speaker-test
>
> I apply some of your code by retyping this into the mainline kernel
4.2-rc1 code, compile and install the kernel, and then test the audio.
> The subwoofer I test by playing music with my music player, Audacious.
> When testing different configurations and output profiles I use
pavucontrol.
> For testing the microphone, I open pavucontrol, switch the input source
between Internal Microphone and Microphone and look at the volumebar to see
if the microphone works fine.
>
> Do you have suggestions how to apply and test the provided patches?
>

you have to provide alsa-info of patched driver

http://git.alsa-project.org/?p=alsa-lib.git;a=blob;f=test/chmap.c;hb=HEAD

./chmap -Dhw:0 query

Do chmap show the stereo and 2.1 channel map ?

the "External Subwoofer Jack" detect kctl should return true when you plug
the Sonic Master Subwoofer and false when you unplug

after you add analog-output-subwoofer.conf and replace the output path
analog-output-lineout and analog-output-speaker in 2.1 profiles in
profile-sets/default.conf

You have to provide pulseaudio verbsose log if pulseaudio did not
automatically switch to 2.1 profile

The dirty workaround for the headset mic when your codec cannot distinguish
headphone and headset but you use only headset

Change the headset.conf to use jsck headphone instead of headset mic jack

http://cgit.freedesktop.org/pulseaudio/pulseaudio/plain/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf

-[Jack Headset Mic]
-required-any = any

-[Jack Headset Mic Phantom]
-state.plugged = unknown
-state.unplugged = unknown
-required-any = any

[Jack Headphone]
-state.plugged = unknown
+required-any = any
Arthur Borsboom July 25, 2015, 2:57 p.m. UTC | #6
Alsa-info patched kernel:
http://www.alsa-project.org/db/?f=cd23a3f0bb72e38d73224620e3e8ab57a73aa441

Chmap results:

Type = FIXED, Channels = 2
  FL FR
Type = FIXED, Channels = 4
  FL FR NA LFE

When unplugging the subwoofer, then chmap gives this and stays like this.

Cannot open PCM stream hw:1 for PLAYBACK

[Pavucontrol] -> [Configuration] -> [Built-in Audio] gives

Analog Stereo Duplex
Analog Stereo Output
Analog Surround 2.1 Output + Analog Stereo Input
Analog Surround 2.1 Output
Analog Surround 4.0 Output + Analog Stereo Input
Analog Surround 4.0 Output
Analog Stereo Input
Off

Pulseaudio verbose log while plugging in the subwoofer:
http://pastebin.com/Ya5u1qz6

On 13 July 2015 at 13:24, Raymond Yau <superquad.vortex2@gmail.com> wrote:

>
> >
> > Honestly some of the Alsa code talk is a bit over my head, so maybe I
> should just stick to providing PCI/Vendor ID's and test results. :)
> >
> > RY> How do you test ? Using sound preference or alsa speaker-test
> >
> > I apply some of your code by retyping this into the mainline kernel
> 4.2-rc1 code, compile and install the kernel, and then test the audio.
> > The subwoofer I test by playing music with my music player, Audacious.
> > When testing different configurations and output profiles I use
> pavucontrol.
> > For testing the microphone, I open pavucontrol, switch the input source
> between Internal Microphone and Microphone and look at the volumebar to see
> if the microphone works fine.
> >
> > Do you have suggestions how to apply and test the provided patches?
> >
>
> you have to provide alsa-info of patched driver
>
> http://git.alsa-project.org/?p=alsa-lib.git;a=blob;f=test/chmap.c;hb=HEAD
>
> ./chmap -Dhw:0 query
>
> Do chmap show the stereo and 2.1 channel map ?
>
> the "External Subwoofer Jack" detect kctl should return true when you plug
> the Sonic Master Subwoofer and false when you unplug
>
> after you add analog-output-subwoofer.conf and replace the output path
> analog-output-lineout and analog-output-speaker in 2.1 profiles in
> profile-sets/default.conf
>
> You have to provide pulseaudio verbsose log if pulseaudio did not
> automatically switch to 2.1 profile
>
> The dirty workaround for the headset mic when your codec cannot
> distinguish headphone and headset but you use only headset
>
> Change the headset.conf to use jsck headphone instead of headset mic jack
>
>
> http://cgit.freedesktop.org/pulseaudio/pulseaudio/plain/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf
>
> -[Jack Headset Mic]
> -required-any = any
>
> -[Jack Headset Mic Phantom]
> -state.plugged = unknown
> -state.unplugged = unknown
> -required-any = any
>
> [Jack Headphone]
> -state.plugged = unknown
> +required-any = any
>
>
>
>
>
Raymond Yau July 26, 2015, 1:28 a.m. UTC | #7
>
> Alsa-info patched kernel:
http://www.alsa-project.org/db/?f=cd23a3f0bb72e38d73224620e3e8ab57a73aa441

Node 0x1a [Pin Complex] wcaps 0x40058f: Stereo Amp-In Amp-Out
  Control: name="Bass Speaker Playback Switch", index=0, device=0
    ControlAmp: chs=3, dir=Out, idx=0, ofs=0
  Control: name="Speaker Surround Jack", index=0, device=0
  Amp-In caps: ofs=0x00, nsteps=0x03, stepsize=0x27, mute=0
  Amp-In vals:  [0x00 0x00]
  Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
  Amp-Out vals:  [0x80 0x80]
  Pincap 0x0000373c: IN OUT HP Detect
    Vref caps: HIZ 50 GRD 80 100
  Pin Default 0x411111f0: [N/A] Speaker at Ext Rear
    Conn = 1/8, Color = Black
    DefAssociation = 0xf, Sequence = 0x0
    Misc = NO_PRESENCE
  Pin-ctls: 0x00: VREF_HIZ
  Unsolicited: tag=05, enabled=1
  Power states:  D0 D1 D2 D3 EPSS
  Power: setting=D0, actual=D0
  Connection: 3
     0x0c 0x0d* 0x0e

"Speaker Surround Jack" should return true when you plugged the external
subwoofer as you didn't change the name of the jack detect kctl

>
> Chmap results:
>
> Type = FIXED, Channels = 2
>   FL FR
> Type = FIXED, Channels = 4
>   FL FR NA LFE
>
> When unplugging the subwoofer, then chmap gives this and stays like this.
>
> Cannot open PCM stream hw:1 for PLAYBACK
>
> [Pavucontrol] -> [Configuration] -> [Built-in Audio] gives
>
> Analog Stereo Duplex
> Analog Stereo Output
> Analog Surround 2.1 Output + Analog Stereo Input
> Analog Surround 2.1 Output
> Analog Surround 4.0 Output + Analog Stereo Input
> Analog Surround 4.0 Output
> Analog Stereo Input
> Off
>
> Pulseaudio verbose log while plugging in the subwoofer:
http://pastebin.com/Ya5u1qz6

Seem not probe surround21 profile
Arthur Borsboom July 26, 2015, 11:55 a.m. UTC | #8
Hi Raymond,

I have to apologize.

When you said Pulseaudio might have a bug, I rechecked my steps and I
believe I had only applied half of your patches.
I have applied all the patches this time, against the 4.2.0-rc3 kernel and
posted the requested info again.

alsa-info:
http://www.alsa-project.org/db/?f=ab56d544c53402fc7fdb96956299753de2708a6f

chmap-result (stable, does not change after plugging or unplugging jacks):

Type = FIXED, Channels = 2
  FL FR
Type = FIXED, Channels = 4
  FL FR NA LFE

[Pavucontrol] -> [Configuration] -> [Built-in Audio] gives

Analog Stereo Duplex
Analog Stereo Output
Analog Surround 2.1 Output + Analog Stereo Input
Analog Surround 2.1 Output
Analog Surround 4.0 Output + Analog Stereo Input
Analog Surround 4.0 Output
Analog Stereo Input
Off

Pulseaudio verbose log: http://pastebin.com/MwC3KQS5

Pulseaudio log is created by the following steps:

1. echo autospawn = no >> ~/.config/pulse/client.conf
2. killall pulseaudio
3. LANG=C pulseaudio -vvvv --log-time=1 > ~/pulseverbose.log 2>&1
4. Wait a couple of seconds
5. Plugin jack external subwoofer
6. Plugin jack headset
7. Press CTRL-C

Are the results the same, or is there more hope this time? :-)

On 13 July 2015 at 13:24, Raymond Yau <superquad.vortex2@gmail.com> wrote:

>
> >
> > Honestly some of the Alsa code talk is a bit over my head, so maybe I
> should just stick to providing PCI/Vendor ID's and test results. :)
> >
> > RY> How do you test ? Using sound preference or alsa speaker-test
> >
> > I apply some of your code by retyping this into the mainline kernel
> 4.2-rc1 code, compile and install the kernel, and then test the audio.
> > The subwoofer I test by playing music with my music player, Audacious.
> > When testing different configurations and output profiles I use
> pavucontrol.
> > For testing the microphone, I open pavucontrol, switch the input source
> between Internal Microphone and Microphone and look at the volumebar to see
> if the microphone works fine.
> >
> > Do you have suggestions how to apply and test the provided patches?
> >
>
> you have to provide alsa-info of patched driver
>
> http://git.alsa-project.org/?p=alsa-lib.git;a=blob;f=test/chmap.c;hb=HEAD
>
> ./chmap -Dhw:0 query
>
> Do chmap show the stereo and 2.1 channel map ?
>
> the "External Subwoofer Jack" detect kctl should return true when you plug
> the Sonic Master Subwoofer and false when you unplug
>
> after you add analog-output-subwoofer.conf and replace the output path
> analog-output-lineout and analog-output-speaker in 2.1 profiles in
> profile-sets/default.conf
>
> You have to provide pulseaudio verbsose log if pulseaudio did not
> automatically switch to 2.1 profile
>
> The dirty workaround for the headset mic when your codec cannot
> distinguish headphone and headset but you use only headset
>
> Change the headset.conf to use jsck headphone instead of headset mic jack
>
>
> http://cgit.freedesktop.org/pulseaudio/pulseaudio/plain/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf
>
> -[Jack Headset Mic]
> -required-any = any
>
> -[Jack Headset Mic Phantom]
> -state.plugged = unknown
> -state.unplugged = unknown
> -required-any = any
>
> [Jack Headphone]
> -state.plugged = unknown
> +required-any = any
>
>
>
>
>
Raymond Yau July 27, 2015, 2:11 a.m. UTC | #9
2015-07-26 19:55 GMT+08:00 Arthur Borsboom <arthurborsboom@gmail.com>:

> Hi Raymond,
>
> I have to apologize.
>
> When you said Pulseaudio might have a bug, I rechecked my steps and I
> believe I had only applied half of your patches.
> I have applied all the patches this time, against the 4.2.0-rc3 kernel and
> posted the requested info again.
>
> alsa-info:
> http://www.alsa-project.org/db/?f=ab56d544c53402fc7fdb96956299753de2708a6f
>


	control.23 {
		iface CARD
		name 'External Subwoofer Jack'
		value true
		comment {
			access read
			type BOOLEAN
			count 1
		}
	}

As "External Subwoofer Jack" can report the presence of the external
Sonice Master Subwoofer

You need David to answer whether pulseaudio can auto mute since there
is NO "Headphone Jack" kctl for model=dell-headset-multi


http://git.kernel.org/cgit/linux/kernel/git/tiwai/hda-emu.git/tree/codecs/canonical?id=HEAD

There is no "Headphone Jack" kctl for those alc3661-dell which use
dell-headset-multi,

	control.19 {
		iface CARD
		name 'Headphone Mic Jack'
		value false
		comment {
			access read
			type BOOLEAN
			count 1
		}
	}
	control.20 {
		iface CARD
		name 'Headset Mic Phantom Jack'
		value true
		comment {
			access read
			type BOOLEAN
			count 1
		}
	}
	control.21 {
		iface CARD
		name 'Internal Mic Phantom Jack'
		value true
		comment {
			access read
			type BOOLEAN
			count 1
		}
	}
	control.22 {
		iface CARD
		name 'Speaker Front Phantom Jack'
		value true
		comment {
			access read
			type BOOLEAN
			count 1
		}
	}



> chmap-result (stable, does not change after plugging or unplugging jacks):
>
> Type = FIXED, Channels = 2
>   FL FR
> Type = FIXED, Channels = 4
>   FL FR NA LFE
>
> [Pavucontrol] -> [Configuration] -> [Built-in Audio] gives
>
> Analog Stereo Duplex
> Analog Stereo Output
> Analog Surround 2.1 Output + Analog Stereo Input
> Analog Surround 2.1 Output
> Analog Surround 4.0 Output + Analog Stereo Input
> Analog Surround 4.0 Output
> Analog Stereo Input
> Off
>
> Pulseaudio verbose log: http://pastebin.com/MwC3KQS5
>

Pulseaudio expect "Headphone Jack" but it is not available in
dell-headset-multi


(   0.088|   0.000) D: [pulseaudio] alsa-mixer.c: Looking at profile
output:analog-surround-21
(   0.088|   0.000) D: [pulseaudio] alsa-mixer.c: Checking for playback on
Analog Surround 2.1 (analog-surround-21)
(   0.088|   0.000) D: [pulseaudio] alsa-util.c: Trying surround21:1 with
SND_PCM_NO_AUTO_FORMAT ...
(   0.088|   0.000) D: [pulseaudio] alsa-util.c: Managed to open
surround21:1
(   0.088|   0.000) D: [pulseaudio] alsa-util.c: Maximum hw buffer size is
11888 ms
(   0.106|   0.017) D: [pulseaudio] alsa-util.c: Set buffer size first (to
4408 samples), period size second (to 1102 samples).
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Profile
output:analog-surround-21 supported.
(   0.106|   0.000) I: [pulseaudio] (alsa-lib)control.c: Invalid CTL
surround21:1
(   0.106|   0.000) I: [pulseaudio] alsa-util.c: Unable to attach to mixer
surround21:1: No such file or directory
(   0.106|   0.000) I: [pulseaudio] alsa-util.c: Successfully attached to
mixer 'hw:1'
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Removing path
'analog-output' as it is a subset of 'analog-output-speaker'.
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Available mixer paths
(after tidying):
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Path Set 0xc8a0b0,
direction=1
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Path
analog-output-speaker (Speakers), direction=1, priority=100, probed=yes,
supported=yes, has_mute=yes, has_volume=yes, has_dB=yes, min_volume=0,
max_volume=87, min_dB=-181.5, max_dB=0
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Element Master,
direction=1, switch=1, volume=1, volume_limit=-1, enumeration=0,
required=0, required_any=0, required_absent=0, mask=0x7ffffffffffff,
n_channels=1, override_map=yes
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Element Headphone,
direction=1, switch=2, volume=2, volume_limit=-1, enumeration=0,
required=0, required_any=0, required_absent=0, mask=0x6, n_channels=2,
override_map=no
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Element Speaker,
direction=1, switch=1, volume=1, volume_limit=-1, enumeration=0,
required=0, required_any=4, required_absent=0, mask=0x3600000000f66,
n_channels=2, override_map=yes
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Element Bass Speaker,
direction=1, switch=1, volume=1, volume_limit=-1, enumeration=0,
required=0, required_any=4, required_absent=0, mask=0x80, n_channels=2,
override_map=yes
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Element PCM, direction=1,
switch=0, volume=1, volume_limit=-1, enumeration=0, required=0,
required_any=0, required_absent=0, mask=0x3600000000f66, n_channels=2,
override_map=yes
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Headphone,
alsa_name='Headphone Jack', detection unavailable
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Dock Headphone,
alsa_name='Dock Headphone Jack', detection unavailable
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Front Headphone,
alsa_name='Front Headphone Jack', detection unavailable
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Line Out,
alsa_name='Line Out Jack', detection unavailable
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Line Out Front,
alsa_name='Line Out Front Jack', detection unavailable
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Speaker Phantom,
alsa_name='Speaker Phantom Jack', detection unavailable
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Speaker Front
Phantom, alsa_name='Speaker Front Phantom Jack', detection possible
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Skipping profile
output:analog-surround-21+input:analog-mono - will not be able to open
input:analog-mono
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Looking at profile
output:analog-surround-21+input:analog-stereo
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Checking for recording on
Analog Stereo (analog-stereo)
(   0.106|   0.000) D: [pulseaudio] alsa-util.c: Trying front:1 with
SND_PCM_NO_AUTO_FORMAT ...
(   0.106|   0.000) D: [pulseaudio] alsa-util.c: Managed to open front:1
(   0.106|   0.000) D: [pulseaudio] alsa-util.c: Maximum hw buffer size is
23777 ms
(   0.106|   0.000) D: [pulseaudio] alsa-util.c: Set buffer size first (to
4408 samples), period size second (to 1102 samples).
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Profile
output:analog-surround-21+input:analog-stereo supported.
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Skipping profile
output:analog-surround-21+input:iec958-stereo - will not be able to open
input:iec958-stereo
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Looking at profile
output:analog-surround-40
(   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Checking for playback on
Analog Surround 4.0 (analog-surround-40)
(   0.106|   0.000) D: [pulseaudio] alsa-util.c: Trying surround40:1 with
SND_PCM_NO_AUTO_FORMAT ...
(   0.106|   0.000) D: [pulseaudio] alsa-util.c: Managed to open
surround40:1
(   0.107|   0.000) D: [pulseaudio] alsa-util.c: Maximum hw buffer size is
11888 ms
(   0.107|   0.000) D: [pulseaudio] alsa-util.c: Set buffer size first (to
4408 samples), period size second (to 1102 samples).
(   0.107|   0.000) D: [pulseaudio] alsa-mixer.c: Profile
output:analog-surround-40 supported.

it is pulseaudio bug to support surround40 since your laptop does not have
"RL and RR" chmap


>
>
Arthur Borsboom July 27, 2015, 6:48 a.m. UTC | #10
I shall file a bug against Pulseaudio with the subject.

Pulseaudio enables Surround 4.0, while chmap reports no RL and RR.

While waiting for the Pulseaudio result, do you think it is a good idea to
send your Alsa patches upstream, so at least some of the functionality
start working soon?
If so, do you guess this patch will be available in v4.2 or v4.3?

On 27 July 2015 at 04:11, Raymond Yau <superquad.vortex2@gmail.com> wrote:

>
>
> 2015-07-26 19:55 GMT+08:00 Arthur Borsboom <arthurborsboom@gmail.com>:
>
>> Hi Raymond,
>>
>> I have to apologize.
>>
>> When you said Pulseaudio might have a bug, I rechecked my steps and I
>> believe I had only applied half of your patches.
>> I have applied all the patches this time, against the 4.2.0-rc3 kernel
>> and posted the requested info again.
>>
>> alsa-info:
>> http://www.alsa-project.org/db/?f=ab56d544c53402fc7fdb96956299753de2708a6f
>>
>
>
> 	control.23 {
> 		iface CARD
> 		name 'External Subwoofer Jack'
> 		value true
> 		comment {
> 			access read
> 			type BOOLEAN
> 			count 1
> 		}
> 	}
>
> As "External Subwoofer Jack" can report the presence of the external Sonice Master Subwoofer
>
> You need David to answer whether pulseaudio can auto mute since there is NO "Headphone Jack" kctl for model=dell-headset-multi
>
>
>
> http://git.kernel.org/cgit/linux/kernel/git/tiwai/hda-emu.git/tree/codecs/canonical?id=HEAD
>
> There is no "Headphone Jack" kctl for those alc3661-dell which use
> dell-headset-multi,
>
> 	control.19 {
> 		iface CARD
> 		name 'Headphone Mic Jack'
> 		value false
> 		comment {
> 			access read
> 			type BOOLEAN
> 			count 1
> 		}
> 	}
> 	control.20 {
> 		iface CARD
> 		name 'Headset Mic Phantom Jack'
> 		value true
> 		comment {
> 			access read
> 			type BOOLEAN
> 			count 1
> 		}
> 	}
> 	control.21 {
> 		iface CARD
> 		name 'Internal Mic Phantom Jack'
> 		value true
> 		comment {
> 			access read
> 			type BOOLEAN
> 			count 1
> 		}
> 	}
> 	control.22 {
> 		iface CARD
> 		name 'Speaker Front Phantom Jack'
> 		value true
> 		comment {
> 			access read
> 			type BOOLEAN
> 			count 1
> 		}
> 	}
>
>
>
>> chmap-result (stable, does not change after plugging or unplugging jacks):
>>
>> Type = FIXED, Channels = 2
>>   FL FR
>> Type = FIXED, Channels = 4
>>   FL FR NA LFE
>>
>> [Pavucontrol] -> [Configuration] -> [Built-in Audio] gives
>>
>> Analog Stereo Duplex
>> Analog Stereo Output
>> Analog Surround 2.1 Output + Analog Stereo Input
>> Analog Surround 2.1 Output
>> Analog Surround 4.0 Output + Analog Stereo Input
>> Analog Surround 4.0 Output
>> Analog Stereo Input
>> Off
>>
>> Pulseaudio verbose log: http://pastebin.com/MwC3KQS5
>>
>
> Pulseaudio expect "Headphone Jack" but it is not available in
> dell-headset-multi
>
>
> (   0.088|   0.000) D: [pulseaudio] alsa-mixer.c: Looking at profile
> output:analog-surround-21
> (   0.088|   0.000) D: [pulseaudio] alsa-mixer.c: Checking for playback on
> Analog Surround 2.1 (analog-surround-21)
> (   0.088|   0.000) D: [pulseaudio] alsa-util.c: Trying surround21:1 with
> SND_PCM_NO_AUTO_FORMAT ...
> (   0.088|   0.000) D: [pulseaudio] alsa-util.c: Managed to open
> surround21:1
> (   0.088|   0.000) D: [pulseaudio] alsa-util.c: Maximum hw buffer size is
> 11888 ms
> (   0.106|   0.017) D: [pulseaudio] alsa-util.c: Set buffer size first (to
> 4408 samples), period size second (to 1102 samples).
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Profile
> output:analog-surround-21 supported.
> (   0.106|   0.000) I: [pulseaudio] (alsa-lib)control.c: Invalid CTL
> surround21:1
> (   0.106|   0.000) I: [pulseaudio] alsa-util.c: Unable to attach to mixer
> surround21:1: No such file or directory
> (   0.106|   0.000) I: [pulseaudio] alsa-util.c: Successfully attached to
> mixer 'hw:1'
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Removing path
> 'analog-output' as it is a subset of 'analog-output-speaker'.
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Available mixer paths
> (after tidying):
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Path Set 0xc8a0b0,
> direction=1
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Path
> analog-output-speaker (Speakers), direction=1, priority=100, probed=yes,
> supported=yes, has_mute=yes, has_volume=yes, has_dB=yes, min_volume=0,
> max_volume=87, min_dB=-181.5, max_dB=0
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Element Master,
> direction=1, switch=1, volume=1, volume_limit=-1, enumeration=0,
> required=0, required_any=0, required_absent=0, mask=0x7ffffffffffff,
> n_channels=1, override_map=yes
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Element Headphone,
> direction=1, switch=2, volume=2, volume_limit=-1, enumeration=0,
> required=0, required_any=0, required_absent=0, mask=0x6, n_channels=2,
> override_map=no
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Element Speaker,
> direction=1, switch=1, volume=1, volume_limit=-1, enumeration=0,
> required=0, required_any=4, required_absent=0, mask=0x3600000000f66,
> n_channels=2, override_map=yes
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Element Bass Speaker,
> direction=1, switch=1, volume=1, volume_limit=-1, enumeration=0,
> required=0, required_any=4, required_absent=0, mask=0x80, n_channels=2,
> override_map=yes
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Element PCM,
> direction=1, switch=0, volume=1, volume_limit=-1, enumeration=0,
> required=0, required_any=0, required_absent=0, mask=0x3600000000f66,
> n_channels=2, override_map=yes
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Headphone,
> alsa_name='Headphone Jack', detection unavailable
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Dock Headphone,
> alsa_name='Dock Headphone Jack', detection unavailable
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Front Headphone,
> alsa_name='Front Headphone Jack', detection unavailable
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Line Out,
> alsa_name='Line Out Jack', detection unavailable
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Line Out Front,
> alsa_name='Line Out Front Jack', detection unavailable
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Speaker Phantom,
> alsa_name='Speaker Phantom Jack', detection unavailable
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Jack Speaker Front
> Phantom, alsa_name='Speaker Front Phantom Jack', detection possible
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Skipping profile
> output:analog-surround-21+input:analog-mono - will not be able to open
> input:analog-mono
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Looking at profile
> output:analog-surround-21+input:analog-stereo
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Checking for recording
> on Analog Stereo (analog-stereo)
> (   0.106|   0.000) D: [pulseaudio] alsa-util.c: Trying front:1 with
> SND_PCM_NO_AUTO_FORMAT ...
> (   0.106|   0.000) D: [pulseaudio] alsa-util.c: Managed to open front:1
> (   0.106|   0.000) D: [pulseaudio] alsa-util.c: Maximum hw buffer size is
> 23777 ms
> (   0.106|   0.000) D: [pulseaudio] alsa-util.c: Set buffer size first (to
> 4408 samples), period size second (to 1102 samples).
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Profile
> output:analog-surround-21+input:analog-stereo supported.
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Skipping profile
> output:analog-surround-21+input:iec958-stereo - will not be able to open
> input:iec958-stereo
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Looking at profile
> output:analog-surround-40
> (   0.106|   0.000) D: [pulseaudio] alsa-mixer.c: Checking for playback on
> Analog Surround 4.0 (analog-surround-40)
> (   0.106|   0.000) D: [pulseaudio] alsa-util.c: Trying surround40:1 with
> SND_PCM_NO_AUTO_FORMAT ...
> (   0.106|   0.000) D: [pulseaudio] alsa-util.c: Managed to open
> surround40:1
> (   0.107|   0.000) D: [pulseaudio] alsa-util.c: Maximum hw buffer size is
> 11888 ms
> (   0.107|   0.000) D: [pulseaudio] alsa-util.c: Set buffer size first (to
> 4408 samples), period size second (to 1102 samples).
> (   0.107|   0.000) D: [pulseaudio] alsa-mixer.c: Profile
> output:analog-surround-40 supported.
>
> it is pulseaudio bug to support surround40 since your laptop does not have
> "RL and RR" chmap
>
>
>>
>>
>
Raymond Yau July 27, 2015, 9:08 a.m. UTC | #11
>
> I shall file a bug against Pulseaudio with the subject.
>
> Pulseaudio enables Surround 4.0, while chmap reports no RL and RR.
>
> While waiting for the Pulseaudio result, do you think it is a good idea
to send your Alsa patches upstream, so at least some of the functionality
start working soon?
> If so, do you guess this patch will be available in v4.2 or v4.3?

Do dell-headset-multi really work as expected ?

http://voices.canonical.com/david.henningsson/2014/03/07/headset-jacks-on-newer-laptops/

Seem need popup dialog to set the combo jack type correctly when you are
using headset or conventional mic

Do "pactl list sinks" show the headphone port since your alsa-info did not
have any Headphone Jack kctl ?

Your pulseaudio log only have surround21 profile but no message about lfe
filter enabled

     pa_log_debug("  lfe filter activated (LR4 type)");

http://cgit.freedesktop.org/pulseaudio/pulseaudio/commit/?id=979f19a434733afba0480e2ba456cccc98362e05
Arthur Borsboom July 27, 2015, 11:08 a.m. UTC | #12
At this moment the headset works this way: I plugin the headset, I change
the input source from Internal Microphone to Microphone and I can start
using the headset. There is no popup.

The sub woofer works on Pulseaudio setting "Stereo" and "Surround 4.0", but
not on "Surround 2.1".

pactl list sinks: http://pastebin.com/uZH1nwtE

On 27 July 2015 at 11:08, Raymond Yau <superquad.vortex2@gmail.com> wrote:

>
> >
> > I shall file a bug against Pulseaudio with the subject.
> >
> > Pulseaudio enables Surround 4.0, while chmap reports no RL and RR.
> >
> > While waiting for the Pulseaudio result, do you think it is a good idea
> to send your Alsa patches upstream, so at least some of the functionality
> start working soon?
> > If so, do you guess this patch will be available in v4.2 or v4.3?
>
> Do dell-headset-multi really work as expected ?
>
>
> http://voices.canonical.com/david.henningsson/2014/03/07/headset-jacks-on-newer-laptops/
>
> Seem need popup dialog to set the combo jack type correctly when you are
> using headset or conventional mic
>
> Do "pactl list sinks" show the headphone port since your alsa-info did not
> have any Headphone Jack kctl ?
>
> Your pulseaudio log only have surround21 profile but no message about lfe
> filter enabled
>
>      pa_log_debug("  lfe filter activated (LR4 type)");
>
>
> http://cgit.freedesktop.org/pulseaudio/pulseaudio/commit/?id=979f19a434733afba0480e2ba456cccc98362e05
>
Raymond Yau July 27, 2015, 12:59 p.m. UTC | #13
>
> At this moment the headset works this way: I plugin the headset, I change
the input source from Internal Microphone to Microphone and I can start
using the headset. There is no popup.
>
> The sub woofer works on Pulseaudio setting "Stereo" and "Surround 4.0",
but not on "Surround 2.1".

Refer to your pulseaudio verbose log

(   6.509|   1.381) D: [pulseaudio] module-alsa-card.c: Jack 'Headphone Mic
Jack' is now plugged in
(   6.509|   0.000) D: [pulseaudio] device-port.c: Setting port
analog-output-headphones to status yes

This look like pulseaudio use headphone mic jack to set the headphone to
available

(   6.509|   0.000) D: [pulseaudio] module-switch-on-port-available.c:
Finding best profile
(   6.509|   0.000) D: [pulseaudio] module-switch-on-port-available.c: No
suitable profile found
(   6.509|   0.000) D: [pulseaudio] device-port.c: Setting port
analog-input-headphone-mic to status unknown

(   6.509|   0.000) D: [pulseaudio] core-subscribe.c: Dropped redundant
event due to change event.
(   6.509|   0.000) D: [pulseaudio] device-port.c: Setting port
analog-input-headset-mic to status unknown

But I don't understand why pulseaudio set status of headphone mic and
headset mic to unknown

You did not use External Subwoofer Jack to change the status of external
subwoofer, there is no traces of external subwoofer jack in your log
Raymond Yau July 30, 2015, 3:05 a.m. UTC | #14
>
> "... after you replaced speakers.conf and lineout.conf by subwoofer.conf
..."
>
> I must have missed something again. I was under the impression that
changing the configuration files was a workaround when the patch would be
insufficient. Later today or tomorrow, I will reread this part and apply
changes to the configuration files and report back.

  Ports:
                analog-output-speaker: Speakers (priority: 10000)
                analog-output-headphones: Headphones (priority: 9000, not
available)
        Active Port: analog-output-speaker


When you select model=dell-headset-multi, the driver create "Headphone Mic
Jack" kctl with type 1 which is SND_JACK_HEADPHONE

type 2 is SND_JACK_MICROPHONE

type 3 is SND_JACK_HEADSET but hda jack does not use this type

https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/tree/include/sound/jack.h

JACK created Headphone Mic, type 1
CTRL: add: Headphone Mic Jack:0
JACK report Headphone Mic, status 0
JACK created Headset Mic Phantom, type 2
CTRL: add: Headset Mic Phantom Jack:0
JACK report Headset Mic Phantom, status 2
CTL Notify: Headset Mic Phantom Jack:0, mask=1
JACK created Internal Mic Phantom, type 2
CTRL: add: Internal Mic Phantom Jack:0
JACK report Internal Mic Phantom, status 2
CTL Notify: Internal Mic Phantom Jack:0, mask=1
JACK created Speaker Front Phantom, type 4
CTRL: add: Speaker Front Phantom Jack:0
JACK report Speaker Front Phantom, status 4
CTL Notify: Speaker Front Phantom Jack:0, mask=1
JACK created External Subwoofer, type 4
CTRL: add: External Subwoofer Jack:0

The problem of hda jack kctls are those retaskable I/O jack controls

1) multi io jacks in those 3 stack desktop
2) headphone/mic jack in asus netbook
3) dell-headset-multi combo jack

the role of the jack in 1) change from input to output when "Channel mode"
change from "2ch" to "4ch" or "6ch"

the role of the jack in 2) and 3) change from Output to Input when "Capture
Source" change from Internal Mic/Headset Mic to Headphone Mic

In your case, Headphone Mic Jack kctl return the presence of HP jack except
when the combo jack is set to support conventional mic (i.e. when the
driver change pin ctl of hp pin node 0x15 to zero and set pin ctl of mic
pin to IN),

The driver already unmute the internal speaker when you change capture
source to Headphone Mic

The only point is whether pulseaudio still regard this Headphone Mic Jack
as the availability of the headphone port when the capture source is
Headphone Mic

http://cgit.freedesktop.org/pulseaudio/pulseaudio/commit/?id=ca4942e89cf462e5f8c36ca9b8b689879083af6b

Patch
diff mbox

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: