Re: Fwd: [PATCH] ALSA: hda/generic: Add mic autoswitch support for dyn_adc_switch mode

From: Takashi Iwai

Date: Thu May 07 2026 - 11:06:00 EST


On Wed, 06 May 2026 09:03:52 +0200,
Zhang Heng wrote:
>
>
>
>
> -------- 转发的消息 --------
> 主题: Re: [PATCH] ALSA: hda/generic: Add mic autoswitch support for
> dyn_adc_switch mode
> 日期: Wed, 6 May 2026 14:19:14 +0800
> 发件人: Zhang Heng <zhangheng@xxxxxxxxxx>
> 收件人: Takashi Iwai <tiwai@xxxxxxx>
>
>
>
>
> 在 2026/5/5 0:25, Takashi Iwai 写道:
> > On Sun, 03 May 2026 13:45:12 +0200,
> > Zhang Heng wrote:
> >> When auto_mic is not available but dyn_adc_switch mode is enabled
> >> (e.g., on laptops with both front and rear mic jacks), this patch
> >> enables automatic microphone switching based on jack detection.
> >>
> >> The patch includes three changes:
> >>
> >> 1. In check_dyn_adc_switch(): Register jack detect callbacks for
> >> all input pins when dyn_adc_switch is enabled and auto_mic is
> >> not available.
> >>
> >> 2. In call_mic_autoswitch(): Add handling for dyn_adc_switch mode
> >> to check imux_pins[] for jack presence, searching from back to
> >> front (last inserted wins).
> >>
> >> 3. In mux_select(): Notify Capture Source controls after switching
> >> to sync with user-space (PulseAudio/PipeWire).
> >>
> >> Problem description:
> >> On Ubuntu 20.04 (with older PulseAudio/PipeWire):
> >> - Front mic is unplugged
> >> - Plug in rear mic
> >> - Jack event is reported correctly
> >> - Volume control (PulseAudio/PipeWire) recognizes the rear mic
> >> - But alsamixer does NOT switch to rear mic
> >> - Codec also does NOT perform the switch
> >>
> >> The root cause is that in dyn_adc_switch mode without auto_mic,
> >> the jack detect callback was not properly set up to trigger the
> >> mic autoswitch. The call_mic_autoswitch() function only calls
> >> mic_autoswitch_hook or snd_hda_gen_mic_autoswitch(), which rely
> >> on auto_mic being enabled.
> >>
> >> Additionally, after mux_select() performs the switch, user-space
> >> (PulseAudio/PipeWire) may not be aware of the path change,
> >> causing Capture Switch to show 'off'.
> >>
> >> This patch fixes both issues by:
> >> 1. Registering jack detect callbacks for all input pins in
> >> dyn_adc_switch mode
> >> 2. Notifying Capture Source controls after switching
> >>
> >> Tested on SN6186 codec with Ubuntu 20.04 and 25.10.
> >>
> >> Question to the community: Is this approach correct? Should additional
> >> changes be made to handle mute state preservation, or is this purely
> >> a user-space issue that requires updating PulseAudio/PipeWire?
> >>
> >> Testing and feedback are welcome.
> > I think the basic idea is OK. We can treat the auto-mic with dynamic
> > ADC switches, too.
> >
> > But it's not clear what's the actual intent in your code changes:
> >
> >
> >> Signed-off-by: Zhang Heng <zhangheng@xxxxxxxxxx>
> >> ---
> >> sound/hda/codecs/generic.c | 82 ++++++++++++++++++++++++++++++++++++--
> >> 1 file changed, 79 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c
> >> index 660a9f2c0ded..c536de10d8b8 100644
> >> --- a/sound/hda/codecs/generic.c
> >> +++ b/sound/hda/codecs/generic.c
> >> @@ -27,6 +27,10 @@
> >> #include "hda_beep.h"
> >> #include "generic.h"
> >> +/* Forward declaration */
> >> +static void call_mic_autoswitch(struct hda_codec *codec,
> >> + struct hda_jack_callback *jack);
> >> +
> >> /**
> >> * snd_hda_gen_spec_init - initialize hda_gen_spec struct
> >> @@ -3238,6 +3242,19 @@ static int check_dyn_adc_switch(struct
> >> hda_codec *codec)
> >> if (!spec->dyn_adc_switch && spec->multi_cap_vol)
> >> spec->num_adc_nids = 1;
> >> + /* Enable mic autoswitch for dyn_adc_switch mode when auto_mic is
> >> not available */
> >> + if (!spec->auto_mic && imux->num_items > 1) {
> >> + int i;
> >> + for (i = 0; i < imux->num_items; i++) {
> >> + hda_nid_t pin = spec->imux_pins[i];
> >> + if (!is_jack_detectable(codec, pin))
> >> + continue;
> >> + snd_hda_jack_detect_enable_callback(codec, pin,
> >> + call_mic_autoswitch);
> >> + }
> >> + codec_dbg(codec, "Enable mic autoswitch for input sources\n");
> >> + }
> > IMO, this should be rather put at auto_mic_check_imux() instead,
> > something like:
> >
> > @@ -4789,13 +4789,15 @@ static bool auto_mic_check_imux(struct
> > hda_codec *codec)
> > const struct hda_input_mux *imux;
> > int i;
> > - imux = &spec->input_mux;
> > - for (i = 0; i < spec->am_num_entries; i++) {
> > - spec->am_entry[i].idx =
> > - find_idx_in_nid_list(spec->am_entry[i].pin,
> > - spec->imux_pins, imux->num_items);
> > - if (spec->am_entry[i].idx < 0)
> > - return false; /* no corresponding imux */
> > + if (!spec->dyn_adc_switch) {
> > + imux = &spec->input_mux;
> > + for (i = 0; i < spec->am_num_entries; i++) {
> > + spec->am_entry[i].idx =
> > + find_idx_in_nid_list(spec->am_entry[i].pin,
> > + spec->imux_pins, imux->num_items);
> > + if (spec->am_entry[i].idx < 0)
> > + return false; /* no corresponding imux */
> > + }
> > }
> > /* we don't need the jack detection for the first pin */
> >
> In fact, auto_ic_check_imux cannot be executed on desktop computers at
> all. You can take a look at the check_outo_ic_availability section
> for (int i = 0; i < cfg->num_inputs; i++) {
>     hda_nid_t nid = cfg->inputs[i].pin;
>     unsigned int attr;
>     attr = snd_hda_codec_get_pincfg(codec, nid);
>     attr = snd_hda_get_input_pin_attr(attr);
>     if (types & (1 << attr))        For desktop computers, the rear
> mic and line are an attr, which will be directly returned here.

Do you mean that the mic is no built-in mic? If so, the auto-mic
isn't the way to go.

The driver can't judge which one has a higher priority between an mic
jack and a line jack. OTOH, in the case of built-in mic vs mic jack,
it's clear who should win, and the driver provides the auto-mic
feature. So, unless this condition is met, leaving the choice to
user-space is the designed behavior.


thanks,

Takashi