diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-05-17 04:35:15 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-05-17 06:33:00 -0400 |
commit | 43c1b2e9209cc824177a5a13e34fb21dfab3455a (patch) | |
tree | a91f2d81088902097b3fd4ac5c1db665d5960021 /sound | |
parent | 52d3cb88d75701f800db16561ff12c7692b56e55 (diff) |
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 <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 98 |
1 files changed, 59 insertions, 39 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ac595363e0e0..2a04fea01692 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -85,6 +85,8 @@ struct conexant_spec { | |||
85 | unsigned int line_present; | 85 | unsigned int line_present; |
86 | unsigned int auto_mic; | 86 | unsigned int auto_mic; |
87 | int auto_mic_ext; /* imux_pins[] index for ext mic */ | 87 | int auto_mic_ext; /* imux_pins[] index for ext mic */ |
88 | int auto_mic_dock; /* imux_pins[] index for dock mic */ | ||
89 | int auto_mic_int; /* imux_pins[] index for int mic */ | ||
88 | unsigned int need_dac_fix; | 90 | unsigned int need_dac_fix; |
89 | hda_nid_t slave_dig_outs[2]; | 91 | hda_nid_t slave_dig_outs[2]; |
90 | 92 | ||
@@ -3737,18 +3739,27 @@ static const struct snd_kcontrol_new cx_auto_capture_mixers[] = { | |||
3737 | {} | 3739 | {} |
3738 | }; | 3740 | }; |
3739 | 3741 | ||
3742 | static bool select_automic(struct hda_codec *codec, int idx, bool detect) | ||
3743 | { | ||
3744 | struct conexant_spec *spec = codec->spec; | ||
3745 | if (idx < 0) | ||
3746 | return false; | ||
3747 | if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin)) | ||
3748 | return false; | ||
3749 | cx_auto_mux_enum_update(codec, &spec->private_imux, idx); | ||
3750 | return true; | ||
3751 | } | ||
3752 | |||
3740 | /* automatic switch internal and external mic */ | 3753 | /* automatic switch internal and external mic */ |
3741 | static void cx_auto_automic(struct hda_codec *codec) | 3754 | static void cx_auto_automic(struct hda_codec *codec) |
3742 | { | 3755 | { |
3743 | struct conexant_spec *spec = codec->spec; | 3756 | struct conexant_spec *spec = codec->spec; |
3744 | int ext_idx = spec->auto_mic_ext; | ||
3745 | 3757 | ||
3746 | if (!spec->auto_mic) | 3758 | if (!spec->auto_mic) |
3747 | return; | 3759 | return; |
3748 | if (snd_hda_jack_detect(codec, spec->imux_info[ext_idx].pin)) | 3760 | if (!select_automic(codec, spec->auto_mic_ext, true)) |
3749 | cx_auto_mux_enum_update(codec, &spec->private_imux, ext_idx); | 3761 | if (!select_automic(codec, spec->auto_mic_dock, true)) |
3750 | else | 3762 | select_automic(codec, spec->auto_mic_int, false); |
3751 | cx_auto_mux_enum_update(codec, &spec->private_imux, !ext_idx); | ||
3752 | } | 3763 | } |
3753 | 3764 | ||
3754 | static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) | 3765 | 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) | |||
3768 | } | 3779 | } |
3769 | } | 3780 | } |
3770 | 3781 | ||
3771 | /* return true if it's an internal-mic pin */ | ||
3772 | static int is_int_mic(struct hda_codec *codec, hda_nid_t pin) | ||
3773 | { | ||
3774 | unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); | ||
3775 | return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && | ||
3776 | snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT; | ||
3777 | } | ||
3778 | |||
3779 | /* return true if it's an external-mic pin */ | ||
3780 | static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin) | ||
3781 | { | ||
3782 | unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); | ||
3783 | return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && | ||
3784 | snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL && | ||
3785 | is_jack_detectable(codec, pin); | ||
3786 | } | ||
3787 | |||
3788 | /* check whether the pin config is suitable for auto-mic switching; | 3782 | /* check whether the pin config is suitable for auto-mic switching; |
3789 | * auto-mic is enabled only when one int-mic and one-ext mic exist | 3783 | * auto-mic is enabled only when one int-mic and one ext- and/or |
3784 | * one dock-mic exist | ||
3790 | */ | 3785 | */ |
3791 | static void cx_auto_check_auto_mic(struct hda_codec *codec) | 3786 | static void cx_auto_check_auto_mic(struct hda_codec *codec) |
3792 | { | 3787 | { |
3793 | struct conexant_spec *spec = codec->spec; | 3788 | struct conexant_spec *spec = codec->spec; |
3789 | int pset[INPUT_PIN_ATTR_NORMAL + 1]; | ||
3790 | int i; | ||
3794 | 3791 | ||
3795 | if (is_ext_mic(codec, spec->imux_info[0].pin) && | 3792 | for (i = 0; i < INPUT_PIN_ATTR_NORMAL; i++) |
3796 | is_int_mic(codec, spec->imux_info[1].pin)) { | 3793 | pset[i] = -1; |
3797 | spec->auto_mic = 1; | 3794 | for (i = 0; i < spec->private_imux.num_items; i++) { |
3798 | spec->auto_mic_ext = 0; | 3795 | hda_nid_t pin = spec->imux_info[i].pin; |
3799 | return; | 3796 | unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); |
3800 | } | 3797 | int attr; |
3801 | if (is_int_mic(codec, spec->imux_info[0].pin) && | 3798 | if (get_defcfg_device(def_conf) != AC_JACK_MIC_IN) |
3802 | is_ext_mic(codec, spec->imux_info[1].pin)) { | 3799 | return; /* no-mic input */ |
3803 | spec->auto_mic = 1; | 3800 | attr = snd_hda_get_input_pin_attr(def_conf); |
3804 | spec->auto_mic_ext = 1; | 3801 | if (attr == INPUT_PIN_ATTR_UNUSED) |
3805 | return; | 3802 | continue; |
3803 | if (attr > INPUT_PIN_ATTR_NORMAL) | ||
3804 | attr = INPUT_PIN_ATTR_NORMAL; | ||
3805 | if (attr != INPUT_PIN_ATTR_INT && | ||
3806 | !is_jack_detectable(codec, pin)) | ||
3807 | continue; | ||
3808 | if (pset[attr] >= 0) | ||
3809 | return; /* already occupied */ | ||
3810 | pset[attr] = i; | ||
3806 | } | 3811 | } |
3812 | if (pset[INPUT_PIN_ATTR_INT] < 0 || | ||
3813 | (pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK])) | ||
3814 | return; /* no input to switch*/ | ||
3815 | spec->auto_mic = 1; | ||
3816 | spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL]; | ||
3817 | spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK]; | ||
3818 | spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT]; | ||
3807 | } | 3819 | } |
3808 | 3820 | ||
3809 | static void cx_auto_parse_input(struct hda_codec *codec) | 3821 | static void cx_auto_parse_input(struct hda_codec *codec) |
@@ -3832,7 +3844,7 @@ static void cx_auto_parse_input(struct hda_codec *codec) | |||
3832 | } | 3844 | } |
3833 | } | 3845 | } |
3834 | } | 3846 | } |
3835 | if (imux->num_items == 2 && cfg->num_inputs == 2) | 3847 | if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items) |
3836 | cx_auto_check_auto_mic(codec); | 3848 | cx_auto_check_auto_mic(codec); |
3837 | if (imux->num_items > 1 && !spec->auto_mic) { | 3849 | if (imux->num_items > 1 && !spec->auto_mic) { |
3838 | for (i = 1; i < imux->num_items; i++) { | 3850 | for (i = 1; i < imux->num_items; i++) { |
@@ -4022,10 +4034,18 @@ static void cx_auto_init_input(struct hda_codec *codec) | |||
4022 | } | 4034 | } |
4023 | 4035 | ||
4024 | if (spec->auto_mic) { | 4036 | if (spec->auto_mic) { |
4025 | int ext_idx = spec->auto_mic_ext; | 4037 | if (spec->auto_mic_ext >= 0) { |
4026 | snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0, | 4038 | snd_hda_codec_write(codec, |
4027 | AC_VERB_SET_UNSOLICITED_ENABLE, | 4039 | cfg->inputs[spec->auto_mic_ext].pin, 0, |
4028 | AC_USRSP_EN | CONEXANT_MIC_EVENT); | 4040 | AC_VERB_SET_UNSOLICITED_ENABLE, |
4041 | AC_USRSP_EN | CONEXANT_MIC_EVENT); | ||
4042 | } | ||
4043 | if (spec->auto_mic_dock >= 0) { | ||
4044 | snd_hda_codec_write(codec, | ||
4045 | cfg->inputs[spec->auto_mic_dock].pin, 0, | ||
4046 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
4047 | AC_USRSP_EN | CONEXANT_MIC_EVENT); | ||
4048 | } | ||
4029 | cx_auto_automic(codec); | 4049 | cx_auto_automic(codec); |
4030 | } else { | 4050 | } else { |
4031 | select_input_connection(codec, spec->imux_info[0].adc, | 4051 | select_input_connection(codec, spec->imux_info[0].adc, |