diff options
Diffstat (limited to 'sound/pci/hda/patch_hdmi.c')
-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 | ||