diff options
Diffstat (limited to 'sound/pci/hda/patch_hdmi.c')
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 59 |
1 files changed, 37 insertions, 22 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 81b7b791b3c3..c505fd5d338c 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -65,7 +65,11 @@ 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; | ||
72 | int repoll_count; | ||
69 | }; | 73 | }; |
70 | 74 | ||
71 | struct hdmi_spec { | 75 | struct hdmi_spec { |
@@ -745,8 +749,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, | |||
745 | * Unsolicited events | 749 | * Unsolicited events |
746 | */ | 750 | */ |
747 | 751 | ||
748 | static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, | 752 | static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll); |
749 | struct hdmi_eld *eld); | ||
750 | 753 | ||
751 | static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | 754 | static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) |
752 | { | 755 | { |
@@ -755,7 +758,6 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
755 | int pd = !!(res & AC_UNSOL_RES_PD); | 758 | int pd = !!(res & AC_UNSOL_RES_PD); |
756 | int eldv = !!(res & AC_UNSOL_RES_ELDV); | 759 | int eldv = !!(res & AC_UNSOL_RES_ELDV); |
757 | int pin_idx; | 760 | int pin_idx; |
758 | struct hdmi_eld *eld; | ||
759 | 761 | ||
760 | printk(KERN_INFO | 762 | printk(KERN_INFO |
761 | "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", | 763 | "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", |
@@ -764,17 +766,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
764 | pin_idx = pin_nid_to_pin_index(spec, pin_nid); | 766 | pin_idx = pin_nid_to_pin_index(spec, pin_nid); |
765 | if (pin_idx < 0) | 767 | if (pin_idx < 0) |
766 | return; | 768 | return; |
767 | eld = &spec->pins[pin_idx].sink_eld; | ||
768 | |||
769 | hdmi_present_sense(codec, pin_nid, eld); | ||
770 | 769 | ||
771 | /* | 770 | hdmi_present_sense(&spec->pins[pin_idx], 1); |
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 | } | 771 | } |
779 | 772 | ||
780 | static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) | 773 | static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) |
@@ -968,9 +961,11 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) | |||
968 | return 0; | 961 | return 0; |
969 | } | 962 | } |
970 | 963 | ||
971 | static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, | 964 | static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) |
972 | struct hdmi_eld *eld) | ||
973 | { | 965 | { |
966 | struct hda_codec *codec = per_pin->codec; | ||
967 | struct hdmi_eld *eld = &per_pin->sink_eld; | ||
968 | hda_nid_t pin_nid = per_pin->pin_nid; | ||
974 | /* | 969 | /* |
975 | * Always execute a GetPinSense verb here, even when called from | 970 | * Always execute a GetPinSense verb here, even when called from |
976 | * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited | 971 | * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited |
@@ -980,26 +975,42 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, | |||
980 | * the unsolicited response to avoid custom WARs. | 975 | * the unsolicited response to avoid custom WARs. |
981 | */ | 976 | */ |
982 | int present = snd_hda_pin_sense(codec, pin_nid); | 977 | int present = snd_hda_pin_sense(codec, pin_nid); |
978 | bool eld_valid = false; | ||
983 | 979 | ||
984 | memset(eld, 0, sizeof(*eld)); | 980 | memset(eld, 0, offsetof(struct hdmi_eld, eld_buffer)); |
985 | 981 | ||
986 | eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); | 982 | eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); |
987 | if (eld->monitor_present) | 983 | if (eld->monitor_present) |
988 | eld->eld_valid = !!(present & AC_PINSENSE_ELDV); | 984 | eld_valid = !!(present & AC_PINSENSE_ELDV); |
989 | else | ||
990 | eld->eld_valid = 0; | ||
991 | 985 | ||
992 | printk(KERN_INFO | 986 | printk(KERN_INFO |
993 | "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", | 987 | "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", |
994 | codec->addr, pin_nid, eld->monitor_present, eld->eld_valid); | 988 | codec->addr, pin_nid, eld->monitor_present, eld_valid); |
995 | 989 | ||
996 | if (eld->eld_valid) | 990 | if (eld_valid) { |
997 | if (!snd_hdmi_get_eld(eld, codec, pin_nid)) | 991 | if (!snd_hdmi_get_eld(eld, codec, pin_nid)) |
998 | snd_hdmi_show_eld(eld); | 992 | snd_hdmi_show_eld(eld); |
993 | else if (repoll) { | ||
994 | queue_delayed_work(codec->bus->workq, | ||
995 | &per_pin->work, | ||
996 | msecs_to_jiffies(300)); | ||
997 | } | ||
998 | } | ||
999 | 999 | ||
1000 | snd_hda_input_jack_report(codec, pin_nid); | 1000 | snd_hda_input_jack_report(codec, pin_nid); |
1001 | } | 1001 | } |
1002 | 1002 | ||
1003 | static void hdmi_repoll_eld(struct work_struct *work) | ||
1004 | { | ||
1005 | struct hdmi_spec_per_pin *per_pin = | ||
1006 | container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work); | ||
1007 | |||
1008 | if (per_pin->repoll_count++ > 6) | ||
1009 | per_pin->repoll_count = 0; | ||
1010 | |||
1011 | hdmi_present_sense(per_pin, per_pin->repoll_count); | ||
1012 | } | ||
1013 | |||
1003 | static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) | 1014 | static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) |
1004 | { | 1015 | { |
1005 | struct hdmi_spec *spec = codec->spec; | 1016 | struct hdmi_spec *spec = codec->spec; |
@@ -1228,7 +1239,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) | |||
1228 | if (err < 0) | 1239 | if (err < 0) |
1229 | return err; | 1240 | return err; |
1230 | 1241 | ||
1231 | hdmi_present_sense(codec, per_pin->pin_nid, &per_pin->sink_eld); | 1242 | hdmi_present_sense(per_pin, 0); |
1232 | return 0; | 1243 | return 0; |
1233 | } | 1244 | } |
1234 | 1245 | ||
@@ -1279,6 +1290,8 @@ static int generic_hdmi_init(struct hda_codec *codec) | |||
1279 | AC_VERB_SET_UNSOLICITED_ENABLE, | 1290 | AC_VERB_SET_UNSOLICITED_ENABLE, |
1280 | AC_USRSP_EN | pin_nid); | 1291 | AC_USRSP_EN | pin_nid); |
1281 | 1292 | ||
1293 | per_pin->codec = codec; | ||
1294 | INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld); | ||
1282 | snd_hda_eld_proc_new(codec, eld, pin_idx); | 1295 | snd_hda_eld_proc_new(codec, eld, pin_idx); |
1283 | } | 1296 | } |
1284 | return 0; | 1297 | return 0; |
@@ -1293,10 +1306,12 @@ static void generic_hdmi_free(struct hda_codec *codec) | |||
1293 | struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; | 1306 | struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; |
1294 | struct hdmi_eld *eld = &per_pin->sink_eld; | 1307 | struct hdmi_eld *eld = &per_pin->sink_eld; |
1295 | 1308 | ||
1309 | cancel_delayed_work(&per_pin->work); | ||
1296 | snd_hda_eld_proc_free(codec, eld); | 1310 | snd_hda_eld_proc_free(codec, eld); |
1297 | } | 1311 | } |
1298 | snd_hda_input_jack_free(codec); | 1312 | snd_hda_input_jack_free(codec); |
1299 | 1313 | ||
1314 | flush_workqueue(codec->bus->workq); | ||
1300 | kfree(spec); | 1315 | kfree(spec); |
1301 | } | 1316 | } |
1302 | 1317 | ||