From 43c1b2e9209cc824177a5a13e34fb21dfab3455a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 May 2011 10:35:15 +0200 Subject: [PATCH] ALSA: hda - Add support of dock-mic detection to Conexant auto-parser In addition to the normal external mic jack, check also the mic jack on a docking-station as well, and select the input source appropriately. The similar functionality was already implemented in patch_sigmatel.c. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 98 +++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 39 deletions(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ac59536..2a04fea 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -85,6 +85,8 @@ struct conexant_spec { unsigned int line_present; unsigned int auto_mic; int auto_mic_ext; /* imux_pins[] index for ext mic */ + int auto_mic_dock; /* imux_pins[] index for dock mic */ + int auto_mic_int; /* imux_pins[] index for int mic */ unsigned int need_dac_fix; hda_nid_t slave_dig_outs[2]; @@ -3737,18 +3739,27 @@ static const struct snd_kcontrol_new cx_auto_capture_mixers[] = { {} }; +static bool select_automic(struct hda_codec *codec, int idx, bool detect) +{ + struct conexant_spec *spec = codec->spec; + if (idx < 0) + return false; + if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin)) + return false; + cx_auto_mux_enum_update(codec, &spec->private_imux, idx); + return true; +} + /* automatic switch internal and external mic */ static void cx_auto_automic(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - int ext_idx = spec->auto_mic_ext; if (!spec->auto_mic) return; - if (snd_hda_jack_detect(codec, spec->imux_info[ext_idx].pin)) - cx_auto_mux_enum_update(codec, &spec->private_imux, ext_idx); - else - cx_auto_mux_enum_update(codec, &spec->private_imux, !ext_idx); + if (!select_automic(codec, spec->auto_mic_ext, true)) + if (!select_automic(codec, spec->auto_mic_dock, true)) + select_automic(codec, spec->auto_mic_int, false); } static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) @@ -3768,42 +3779,43 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) } } -/* return true if it's an internal-mic pin */ -static int is_int_mic(struct hda_codec *codec, hda_nid_t pin) -{ - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); - return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && - snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT; -} - -/* return true if it's an external-mic pin */ -static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin) -{ - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); - return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && - snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL && - is_jack_detectable(codec, pin); -} - /* check whether the pin config is suitable for auto-mic switching; - * auto-mic is enabled only when one int-mic and one-ext mic exist + * auto-mic is enabled only when one int-mic and one ext- and/or + * one dock-mic exist */ static void cx_auto_check_auto_mic(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; + int pset[INPUT_PIN_ATTR_NORMAL + 1]; + int i; - if (is_ext_mic(codec, spec->imux_info[0].pin) && - is_int_mic(codec, spec->imux_info[1].pin)) { - spec->auto_mic = 1; - spec->auto_mic_ext = 0; - return; - } - if (is_int_mic(codec, spec->imux_info[0].pin) && - is_ext_mic(codec, spec->imux_info[1].pin)) { - spec->auto_mic = 1; - spec->auto_mic_ext = 1; - return; + for (i = 0; i < INPUT_PIN_ATTR_NORMAL; i++) + pset[i] = -1; + for (i = 0; i < spec->private_imux.num_items; i++) { + hda_nid_t pin = spec->imux_info[i].pin; + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); + int attr; + if (get_defcfg_device(def_conf) != AC_JACK_MIC_IN) + return; /* no-mic input */ + attr = snd_hda_get_input_pin_attr(def_conf); + if (attr == INPUT_PIN_ATTR_UNUSED) + continue; + if (attr > INPUT_PIN_ATTR_NORMAL) + attr = INPUT_PIN_ATTR_NORMAL; + if (attr != INPUT_PIN_ATTR_INT && + !is_jack_detectable(codec, pin)) + continue; + if (pset[attr] >= 0) + return; /* already occupied */ + pset[attr] = i; } + if (pset[INPUT_PIN_ATTR_INT] < 0 || + (pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK])) + return; /* no input to switch*/ + spec->auto_mic = 1; + spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL]; + spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK]; + spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT]; } static void cx_auto_parse_input(struct hda_codec *codec) @@ -3832,7 +3844,7 @@ static void cx_auto_parse_input(struct hda_codec *codec) } } } - if (imux->num_items == 2 && cfg->num_inputs == 2) + if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items) cx_auto_check_auto_mic(codec); if (imux->num_items > 1 && !spec->auto_mic) { for (i = 1; i < imux->num_items; i++) { @@ -4022,10 +4034,18 @@ static void cx_auto_init_input(struct hda_codec *codec) } if (spec->auto_mic) { - int ext_idx = spec->auto_mic_ext; - snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | CONEXANT_MIC_EVENT); + if (spec->auto_mic_ext >= 0) { + snd_hda_codec_write(codec, + cfg->inputs[spec->auto_mic_ext].pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | CONEXANT_MIC_EVENT); + } + if (spec->auto_mic_dock >= 0) { + snd_hda_codec_write(codec, + cfg->inputs[spec->auto_mic_dock].pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | CONEXANT_MIC_EVENT); + } cx_auto_automic(codec); } else { select_input_connection(codec, spec->imux_info[0].adc, -- 2.7.4