diff options
| author | Wu Fengguang <fengguang.wu@intel.com> | 2011-11-16 03:29:47 -0500 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2011-11-16 04:44:42 -0500 |
| commit | 744626dada90cb1231a65b08874aa7a9f11c2ea8 (patch) | |
| tree | af45566be0dd278ed698f00deb1b734ad0b492d3 | |
| parent | b95d68b8179764e29558b75cec35ef4a6a98925b (diff) | |
ALSA: hda - delayed ELD repoll
The Intel HDMI chips (ironlake at least) are found to have ~250ms delay
between the ELD_Valid=1 hotplug event is send and the ELD buffer becomes
actually readable. During the time the ELD buffer is mysteriously all 0.
Fix it by scheduling a delayed work to re-read ELD buffer after 300ms.
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/pci/hda/patch_hdmi.c | 36 |
1 files changed, 29 insertions, 7 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index aebfee50bd88..a76139b60154 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
| @@ -65,7 +65,10 @@ struct hdmi_spec_per_pin { | |||
| 65 | hda_nid_t pin_nid; | 65 | hda_nid_t pin_nid; |
| 66 | int num_mux_nids; | 66 | int num_mux_nids; |
| 67 | hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; | 67 | hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; |
| 68 | |||
| 69 | struct hda_codec *codec; | ||
| 68 | struct hdmi_eld sink_eld; | 70 | struct hdmi_eld sink_eld; |
| 71 | struct delayed_work work; | ||
| 69 | }; | 72 | }; |
| 70 | 73 | ||
| 71 | struct hdmi_spec { | 74 | struct hdmi_spec { |
| @@ -745,8 +748,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, | |||
| 745 | * Unsolicited events | 748 | * Unsolicited events |
| 746 | */ | 749 | */ |
| 747 | 750 | ||
| 748 | static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, | 751 | static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry); |
| 749 | struct hdmi_eld *eld); | ||
| 750 | 752 | ||
| 751 | static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | 753 | static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) |
| 752 | { | 754 | { |
| @@ -766,7 +768,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
| 766 | return; | 768 | return; |
| 767 | eld = &spec->pins[pin_idx].sink_eld; | 769 | eld = &spec->pins[pin_idx].sink_eld; |
| 768 | 770 | ||
| 769 | hdmi_present_sense(codec, pin_nid, eld); | 771 | hdmi_present_sense(&spec->pins[pin_idx], true); |
| 770 | 772 | ||
| 771 | /* | 773 | /* |
| 772 | * HDMI sink's ELD info cannot always be retrieved for now, e.g. | 774 | * HDMI sink's ELD info cannot always be retrieved for now, e.g. |
| @@ -968,9 +970,11 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) | |||
| 968 | return 0; | 970 | return 0; |
| 969 | } | 971 | } |
| 970 | 972 | ||
| 971 | static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, | 973 | static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry) |
| 972 | struct hdmi_eld *eld) | ||
| 973 | { | 974 | { |
| 975 | struct hda_codec *codec = per_pin->codec; | ||
| 976 | struct hdmi_eld *eld = &per_pin->sink_eld; | ||
| 977 | hda_nid_t pin_nid = per_pin->pin_nid; | ||
| 974 | /* | 978 | /* |
| 975 | * Always execute a GetPinSense verb here, even when called from | 979 | * Always execute a GetPinSense verb here, even when called from |
| 976 | * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited | 980 | * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited |
| @@ -992,13 +996,27 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, | |||
| 992 | "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", | 996 | "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", |
| 993 | codec->addr, pin_nid, eld->monitor_present, eld_valid); | 997 | codec->addr, pin_nid, eld->monitor_present, eld_valid); |
| 994 | 998 | ||
| 995 | if (eld_valid) | 999 | if (eld_valid) { |
| 996 | if (!snd_hdmi_get_eld(eld, codec, pin_nid)) | 1000 | if (!snd_hdmi_get_eld(eld, codec, pin_nid)) |
| 997 | snd_hdmi_show_eld(eld); | 1001 | snd_hdmi_show_eld(eld); |
| 1002 | else if (retry) { | ||
| 1003 | queue_delayed_work(codec->bus->workq, | ||
| 1004 | &per_pin->work, | ||
| 1005 | msecs_to_jiffies(300)); | ||
| 1006 | } | ||
| 1007 | } | ||
| 998 | 1008 | ||
| 999 | snd_hda_input_jack_report(codec, pin_nid); | 1009 | snd_hda_input_jack_report(codec, pin_nid); |
| 1000 | } | 1010 | } |
| 1001 | 1011 | ||
| 1012 | static void hdmi_repoll_eld(struct work_struct *work) | ||
| 1013 | { | ||
| 1014 | struct hdmi_spec_per_pin *per_pin = | ||
| 1015 | container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work); | ||
| 1016 | |||
| 1017 | hdmi_present_sense(per_pin, false); | ||
| 1018 | } | ||
| 1019 | |||
| 1002 | static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) | 1020 | static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) |
| 1003 | { | 1021 | { |
| 1004 | struct hdmi_spec *spec = codec->spec; | 1022 | struct hdmi_spec *spec = codec->spec; |
| @@ -1227,7 +1245,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) | |||
| 1227 | if (err < 0) | 1245 | if (err < 0) |
| 1228 | return err; | 1246 | return err; |
| 1229 | 1247 | ||
| 1230 | hdmi_present_sense(codec, per_pin->pin_nid, &per_pin->sink_eld); | 1248 | hdmi_present_sense(per_pin, false); |
| 1231 | return 0; | 1249 | return 0; |
| 1232 | } | 1250 | } |
| 1233 | 1251 | ||
| @@ -1278,6 +1296,8 @@ static int generic_hdmi_init(struct hda_codec *codec) | |||
| 1278 | AC_VERB_SET_UNSOLICITED_ENABLE, | 1296 | AC_VERB_SET_UNSOLICITED_ENABLE, |
| 1279 | AC_USRSP_EN | pin_nid); | 1297 | AC_USRSP_EN | pin_nid); |
| 1280 | 1298 | ||
| 1299 | per_pin->codec = codec; | ||
| 1300 | INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld); | ||
| 1281 | snd_hda_eld_proc_new(codec, eld, pin_idx); | 1301 | snd_hda_eld_proc_new(codec, eld, pin_idx); |
| 1282 | } | 1302 | } |
| 1283 | return 0; | 1303 | return 0; |
| @@ -1292,10 +1312,12 @@ static void generic_hdmi_free(struct hda_codec *codec) | |||
| 1292 | struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; | 1312 | struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; |
| 1293 | struct hdmi_eld *eld = &per_pin->sink_eld; | 1313 | struct hdmi_eld *eld = &per_pin->sink_eld; |
| 1294 | 1314 | ||
| 1315 | cancel_delayed_work(&per_pin->work); | ||
| 1295 | snd_hda_eld_proc_free(codec, eld); | 1316 | snd_hda_eld_proc_free(codec, eld); |
| 1296 | } | 1317 | } |
| 1297 | snd_hda_input_jack_free(codec); | 1318 | snd_hda_input_jack_free(codec); |
| 1298 | 1319 | ||
| 1320 | flush_workqueue(codec->bus->workq); | ||
| 1299 | kfree(spec); | 1321 | kfree(spec); |
| 1300 | } | 1322 | } |
| 1301 | 1323 | ||
