diff options
Diffstat (limited to 'sound/pci/hda/patch_hdmi.c')
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 55 |
1 files changed, 33 insertions, 22 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 81b7b791b3c3..9850c5b481ea 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 | { |
@@ -755,7 +757,6 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
755 | int pd = !!(res & AC_UNSOL_RES_PD); | 757 | int pd = !!(res & AC_UNSOL_RES_PD); |
756 | int eldv = !!(res & AC_UNSOL_RES_ELDV); | 758 | int eldv = !!(res & AC_UNSOL_RES_ELDV); |
757 | int pin_idx; | 759 | int pin_idx; |
758 | struct hdmi_eld *eld; | ||
759 | 760 | ||
760 | printk(KERN_INFO | 761 | printk(KERN_INFO |
761 | "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", | 762 | "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", |
@@ -764,17 +765,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
764 | pin_idx = pin_nid_to_pin_index(spec, pin_nid); | 765 | pin_idx = pin_nid_to_pin_index(spec, pin_nid); |
765 | if (pin_idx < 0) | 766 | if (pin_idx < 0) |
766 | return; | 767 | return; |
767 | eld = &spec->pins[pin_idx].sink_eld; | ||
768 | |||
769 | hdmi_present_sense(codec, pin_nid, eld); | ||
770 | 768 | ||
771 | /* | 769 | hdmi_present_sense(&spec->pins[pin_idx], true); |
772 | * HDMI sink's ELD info cannot always be retrieved for now, e.g. | ||
773 | * in console or for audio devices. Assume the highest speakers | ||
774 | * configuration, to _not_ prohibit multi-channel audio playback. | ||
775 | */ | ||
776 | if (!eld->spk_alloc) | ||
777 | eld->spk_alloc = 0xffff; | ||
778 | } | 770 | } |
779 | 771 | ||
780 | static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) | 772 | static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) |
@@ -968,9 +960,11 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) | |||
968 | return 0; | 960 | return 0; |
969 | } | 961 | } |
970 | 962 | ||
971 | static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, | 963 | static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry) |
972 | struct hdmi_eld *eld) | ||
973 | { | 964 | { |
965 | struct hda_codec *codec = per_pin->codec; | ||
966 | struct hdmi_eld *eld = &per_pin->sink_eld; | ||
967 | hda_nid_t pin_nid = per_pin->pin_nid; | ||
974 | /* | 968 | /* |
975 | * Always execute a GetPinSense verb here, even when called from | 969 | * Always execute a GetPinSense verb here, even when called from |
976 | * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited | 970 | * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited |
@@ -980,26 +974,39 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, | |||
980 | * the unsolicited response to avoid custom WARs. | 974 | * the unsolicited response to avoid custom WARs. |
981 | */ | 975 | */ |
982 | int present = snd_hda_pin_sense(codec, pin_nid); | 976 | int present = snd_hda_pin_sense(codec, pin_nid); |
977 | bool eld_valid = false; | ||
983 | 978 | ||
984 | memset(eld, 0, sizeof(*eld)); | 979 | memset(eld, 0, offsetof(struct hdmi_eld, eld_buffer)); |
985 | 980 | ||
986 | eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); | 981 | eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); |
987 | if (eld->monitor_present) | 982 | if (eld->monitor_present) |
988 | eld->eld_valid = !!(present & AC_PINSENSE_ELDV); | 983 | eld_valid = !!(present & AC_PINSENSE_ELDV); |
989 | else | ||
990 | eld->eld_valid = 0; | ||
991 | 984 | ||
992 | printk(KERN_INFO | 985 | printk(KERN_INFO |
993 | "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", | 986 | "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", |
994 | codec->addr, pin_nid, eld->monitor_present, eld->eld_valid); | 987 | codec->addr, pin_nid, eld->monitor_present, eld_valid); |
995 | 988 | ||
996 | if (eld->eld_valid) | 989 | if (eld_valid) { |
997 | if (!snd_hdmi_get_eld(eld, codec, pin_nid)) | 990 | if (!snd_hdmi_get_eld(eld, codec, pin_nid)) |
998 | snd_hdmi_show_eld(eld); | 991 | snd_hdmi_show_eld(eld); |
992 | else if (retry) { | ||
993 | queue_delayed_work(codec->bus->workq, | ||
994 | &per_pin->work, | ||
995 | msecs_to_jiffies(300)); | ||
996 | } | ||
997 | } | ||
999 | 998 | ||
1000 | snd_hda_input_jack_report(codec, pin_nid); | 999 | snd_hda_input_jack_report(codec, pin_nid); |
1001 | } | 1000 | } |
1002 | 1001 | ||
1002 | static void hdmi_repoll_eld(struct work_struct *work) | ||
1003 | { | ||
1004 | struct hdmi_spec_per_pin *per_pin = | ||
1005 | container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work); | ||
1006 | |||
1007 | hdmi_present_sense(per_pin, false); | ||
1008 | } | ||
1009 | |||
1003 | static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) | 1010 | static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) |
1004 | { | 1011 | { |
1005 | struct hdmi_spec *spec = codec->spec; | 1012 | struct hdmi_spec *spec = codec->spec; |
@@ -1228,7 +1235,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) | |||
1228 | if (err < 0) | 1235 | if (err < 0) |
1229 | return err; | 1236 | return err; |
1230 | 1237 | ||
1231 | hdmi_present_sense(codec, per_pin->pin_nid, &per_pin->sink_eld); | 1238 | hdmi_present_sense(per_pin, false); |
1232 | return 0; | 1239 | return 0; |
1233 | } | 1240 | } |
1234 | 1241 | ||
@@ -1279,6 +1286,8 @@ static int generic_hdmi_init(struct hda_codec *codec) | |||
1279 | AC_VERB_SET_UNSOLICITED_ENABLE, | 1286 | AC_VERB_SET_UNSOLICITED_ENABLE, |
1280 | AC_USRSP_EN | pin_nid); | 1287 | AC_USRSP_EN | pin_nid); |
1281 | 1288 | ||
1289 | per_pin->codec = codec; | ||
1290 | INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld); | ||
1282 | snd_hda_eld_proc_new(codec, eld, pin_idx); | 1291 | snd_hda_eld_proc_new(codec, eld, pin_idx); |
1283 | } | 1292 | } |
1284 | return 0; | 1293 | return 0; |
@@ -1293,10 +1302,12 @@ static void generic_hdmi_free(struct hda_codec *codec) | |||
1293 | struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; | 1302 | struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; |
1294 | struct hdmi_eld *eld = &per_pin->sink_eld; | 1303 | struct hdmi_eld *eld = &per_pin->sink_eld; |
1295 | 1304 | ||
1305 | cancel_delayed_work(&per_pin->work); | ||
1296 | snd_hda_eld_proc_free(codec, eld); | 1306 | snd_hda_eld_proc_free(codec, eld); |
1297 | } | 1307 | } |
1298 | snd_hda_input_jack_free(codec); | 1308 | snd_hda_input_jack_free(codec); |
1299 | 1309 | ||
1310 | flush_workqueue(codec->bus->workq); | ||
1300 | kfree(spec); | 1311 | kfree(spec); |
1301 | } | 1312 | } |
1302 | 1313 | ||