diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-05-17 06:05:02 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-05-17 06:34:57 -0400 |
commit | 8ed99d976812d1e14a254b9ac1fe6255af8270ff (patch) | |
tree | 21e25f9c6a69ec21a72a5580f40c1e414b4b5ff0 /sound | |
parent | e35d9d6a153493055fc888add70786154f00edd4 (diff) |
ALSA: hda - Add dock-mic detection support to Realtek auto-parser
In addition to the normal mic jack, the mic (or line-in) jack on the
docking-station is checked also as a candidate for auto-selection.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 82 |
1 files changed, 65 insertions, 17 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 24bc8a67a39d..cee89b1ef393 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -360,6 +360,7 @@ struct alc_spec { | |||
360 | const struct hda_input_mux *input_mux; | 360 | const struct hda_input_mux *input_mux; |
361 | unsigned int cur_mux[3]; | 361 | unsigned int cur_mux[3]; |
362 | struct alc_mic_route ext_mic; | 362 | struct alc_mic_route ext_mic; |
363 | struct alc_mic_route dock_mic; | ||
363 | struct alc_mic_route int_mic; | 364 | struct alc_mic_route int_mic; |
364 | 365 | ||
365 | /* channel model */ | 366 | /* channel model */ |
@@ -1057,6 +1058,7 @@ static int alc_init_jacks(struct hda_codec *codec) | |||
1057 | int err; | 1058 | int err; |
1058 | unsigned int hp_nid = spec->autocfg.hp_pins[0]; | 1059 | unsigned int hp_nid = spec->autocfg.hp_pins[0]; |
1059 | unsigned int mic_nid = spec->ext_mic.pin; | 1060 | unsigned int mic_nid = spec->ext_mic.pin; |
1061 | unsigned int dock_nid = spec->dock_mic.pin; | ||
1060 | 1062 | ||
1061 | if (hp_nid) { | 1063 | if (hp_nid) { |
1062 | err = snd_hda_input_jack_add(codec, hp_nid, | 1064 | err = snd_hda_input_jack_add(codec, hp_nid, |
@@ -1073,6 +1075,13 @@ static int alc_init_jacks(struct hda_codec *codec) | |||
1073 | return err; | 1075 | return err; |
1074 | snd_hda_input_jack_report(codec, mic_nid); | 1076 | snd_hda_input_jack_report(codec, mic_nid); |
1075 | } | 1077 | } |
1078 | if (dock_nid) { | ||
1079 | err = snd_hda_input_jack_add(codec, dock_nid, | ||
1080 | SND_JACK_MICROPHONE, NULL); | ||
1081 | if (err < 0) | ||
1082 | return err; | ||
1083 | snd_hda_input_jack_report(codec, dock_nid); | ||
1084 | } | ||
1076 | #endif /* CONFIG_SND_HDA_INPUT_JACK */ | 1085 | #endif /* CONFIG_SND_HDA_INPUT_JACK */ |
1077 | return 0; | 1086 | return 0; |
1078 | } | 1087 | } |
@@ -1217,7 +1226,7 @@ static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec) | |||
1217 | static void alc_mic_automute(struct hda_codec *codec) | 1226 | static void alc_mic_automute(struct hda_codec *codec) |
1218 | { | 1227 | { |
1219 | struct alc_spec *spec = codec->spec; | 1228 | struct alc_spec *spec = codec->spec; |
1220 | struct alc_mic_route *dead, *alive; | 1229 | struct alc_mic_route *dead1, *dead2, *alive; |
1221 | unsigned int present, type; | 1230 | unsigned int present, type; |
1222 | hda_nid_t cap_nid; | 1231 | hda_nid_t cap_nid; |
1223 | 1232 | ||
@@ -1235,13 +1244,24 @@ static void alc_mic_automute(struct hda_codec *codec) | |||
1235 | 1244 | ||
1236 | cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; | 1245 | cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; |
1237 | 1246 | ||
1247 | alive = &spec->int_mic; | ||
1248 | dead1 = &spec->ext_mic; | ||
1249 | dead2 = &spec->dock_mic; | ||
1250 | |||
1238 | present = snd_hda_jack_detect(codec, spec->ext_mic.pin); | 1251 | present = snd_hda_jack_detect(codec, spec->ext_mic.pin); |
1239 | if (present) { | 1252 | if (present) { |
1240 | alive = &spec->ext_mic; | 1253 | alive = &spec->ext_mic; |
1241 | dead = &spec->int_mic; | 1254 | dead1 = &spec->int_mic; |
1242 | } else { | 1255 | dead2 = &spec->dock_mic; |
1243 | alive = &spec->int_mic; | 1256 | } |
1244 | dead = &spec->ext_mic; | 1257 | if (!present && spec->dock_mic.pin > 0) { |
1258 | present = snd_hda_jack_detect(codec, spec->dock_mic.pin); | ||
1259 | if (present) { | ||
1260 | alive = &spec->dock_mic; | ||
1261 | dead1 = &spec->int_mic; | ||
1262 | dead2 = &spec->ext_mic; | ||
1263 | } | ||
1264 | snd_hda_input_jack_report(codec, spec->dock_mic.pin); | ||
1245 | } | 1265 | } |
1246 | 1266 | ||
1247 | type = get_wcaps_type(get_wcaps(codec, cap_nid)); | 1267 | type = get_wcaps_type(get_wcaps(codec, cap_nid)); |
@@ -1250,9 +1270,14 @@ static void alc_mic_automute(struct hda_codec *codec) | |||
1250 | snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, | 1270 | snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, |
1251 | alive->mux_idx, | 1271 | alive->mux_idx, |
1252 | HDA_AMP_MUTE, 0); | 1272 | HDA_AMP_MUTE, 0); |
1253 | snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, | 1273 | if (dead1->pin > 0) |
1254 | dead->mux_idx, | 1274 | snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, |
1255 | HDA_AMP_MUTE, HDA_AMP_MUTE); | 1275 | dead1->mux_idx, |
1276 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
1277 | if (dead2->pin > 0) | ||
1278 | snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, | ||
1279 | dead2->mux_idx, | ||
1280 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
1256 | } else { | 1281 | } else { |
1257 | /* MUX style (e.g. ALC880) */ | 1282 | /* MUX style (e.g. ALC880) */ |
1258 | snd_hda_codec_write_cache(codec, cap_nid, 0, | 1283 | snd_hda_codec_write_cache(codec, cap_nid, 0, |
@@ -1598,15 +1623,10 @@ static void alc_init_auto_mic(struct hda_codec *codec) | |||
1598 | { | 1623 | { |
1599 | struct alc_spec *spec = codec->spec; | 1624 | struct alc_spec *spec = codec->spec; |
1600 | struct auto_pin_cfg *cfg = &spec->autocfg; | 1625 | struct auto_pin_cfg *cfg = &spec->autocfg; |
1601 | hda_nid_t fixed, ext; | 1626 | hda_nid_t fixed, ext, dock; |
1602 | int i; | 1627 | int i; |
1603 | 1628 | ||
1604 | /* there must be only two mic inputs exclusively */ | 1629 | fixed = ext = dock = 0; |
1605 | for (i = 0; i < cfg->num_inputs; i++) | ||
1606 | if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN) | ||
1607 | return; | ||
1608 | |||
1609 | fixed = ext = 0; | ||
1610 | for (i = 0; i < cfg->num_inputs; i++) { | 1630 | for (i = 0; i < cfg->num_inputs; i++) { |
1611 | hda_nid_t nid = cfg->inputs[i].pin; | 1631 | hda_nid_t nid = cfg->inputs[i].pin; |
1612 | unsigned int defcfg; | 1632 | unsigned int defcfg; |
@@ -1615,26 +1635,45 @@ static void alc_init_auto_mic(struct hda_codec *codec) | |||
1615 | case INPUT_PIN_ATTR_INT: | 1635 | case INPUT_PIN_ATTR_INT: |
1616 | if (fixed) | 1636 | if (fixed) |
1617 | return; /* already occupied */ | 1637 | return; /* already occupied */ |
1638 | if (cfg->inputs[i].type != AUTO_PIN_MIC) | ||
1639 | return; /* invalid type */ | ||
1618 | fixed = nid; | 1640 | fixed = nid; |
1619 | break; | 1641 | break; |
1620 | case INPUT_PIN_ATTR_UNUSED: | 1642 | case INPUT_PIN_ATTR_UNUSED: |
1621 | return; /* invalid entry */ | 1643 | return; /* invalid entry */ |
1644 | case INPUT_PIN_ATTR_DOCK: | ||
1645 | if (dock) | ||
1646 | return; /* already occupied */ | ||
1647 | if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) | ||
1648 | return; /* invalid type */ | ||
1649 | dock = nid; | ||
1650 | break; | ||
1622 | default: | 1651 | default: |
1623 | if (ext) | 1652 | if (ext) |
1624 | return; /* already occupied */ | 1653 | return; /* already occupied */ |
1654 | if (cfg->inputs[i].type != AUTO_PIN_MIC) | ||
1655 | return; /* invalid type */ | ||
1625 | ext = nid; | 1656 | ext = nid; |
1626 | break; | 1657 | break; |
1627 | } | 1658 | } |
1628 | } | 1659 | } |
1660 | if (!ext && dock) { | ||
1661 | ext = dock; | ||
1662 | dock = 0; | ||
1663 | } | ||
1629 | if (!ext || !fixed) | 1664 | if (!ext || !fixed) |
1630 | return; | 1665 | return; |
1631 | if (!is_jack_detectable(codec, ext)) | 1666 | if (!is_jack_detectable(codec, ext)) |
1632 | return; /* no unsol support */ | 1667 | return; /* no unsol support */ |
1633 | snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n", | 1668 | if (dock && !is_jack_detectable(codec, dock)) |
1634 | ext, fixed); | 1669 | return; /* no unsol support */ |
1670 | snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", | ||
1671 | ext, fixed, dock); | ||
1635 | spec->ext_mic.pin = ext; | 1672 | spec->ext_mic.pin = ext; |
1673 | spec->dock_mic.pin = dock; | ||
1636 | spec->int_mic.pin = fixed; | 1674 | spec->int_mic.pin = fixed; |
1637 | spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ | 1675 | spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ |
1676 | spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ | ||
1638 | spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ | 1677 | spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ |
1639 | spec->auto_mic = 1; | 1678 | spec->auto_mic = 1; |
1640 | snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0, | 1679 | snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0, |
@@ -5716,6 +5755,12 @@ static void fixup_automic_adc(struct hda_codec *codec) | |||
5716 | spec->capsrc_nids += i; | 5755 | spec->capsrc_nids += i; |
5717 | spec->adc_nids += i; | 5756 | spec->adc_nids += i; |
5718 | spec->num_adc_nids = 1; | 5757 | spec->num_adc_nids = 1; |
5758 | /* optional dock-mic */ | ||
5759 | eidx = get_connection_index(codec, cap, spec->dock_mic.pin); | ||
5760 | if (eidx < 0) | ||
5761 | spec->dock_mic.pin = 0; | ||
5762 | else | ||
5763 | spec->dock_mic.mux_idx = eidx; | ||
5719 | return; | 5764 | return; |
5720 | } | 5765 | } |
5721 | snd_printd(KERN_INFO "hda_codec: %s: " | 5766 | snd_printd(KERN_INFO "hda_codec: %s: " |
@@ -5743,6 +5788,8 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) | |||
5743 | struct alc_spec *spec = codec->spec; | 5788 | struct alc_spec *spec = codec->spec; |
5744 | int i; | 5789 | int i; |
5745 | 5790 | ||
5791 | if (!pin) | ||
5792 | return 0; | ||
5746 | for (i = 0; i < spec->num_adc_nids; i++) { | 5793 | for (i = 0; i < spec->num_adc_nids; i++) { |
5747 | hda_nid_t cap = spec->capsrc_nids ? | 5794 | hda_nid_t cap = spec->capsrc_nids ? |
5748 | spec->capsrc_nids[i] : spec->adc_nids[i]; | 5795 | spec->capsrc_nids[i] : spec->adc_nids[i]; |
@@ -5783,6 +5830,7 @@ static void fixup_dual_adc_switch(struct hda_codec *codec) | |||
5783 | { | 5830 | { |
5784 | struct alc_spec *spec = codec->spec; | 5831 | struct alc_spec *spec = codec->spec; |
5785 | init_capsrc_for_pin(codec, spec->ext_mic.pin); | 5832 | init_capsrc_for_pin(codec, spec->ext_mic.pin); |
5833 | init_capsrc_for_pin(codec, spec->dock_mic.pin); | ||
5786 | init_capsrc_for_pin(codec, spec->int_mic.pin); | 5834 | init_capsrc_for_pin(codec, spec->int_mic.pin); |
5787 | } | 5835 | } |
5788 | 5836 | ||