diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index b142ac260d97..764401951041 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -807,3 +807,98 @@ int drm_helper_resume_force_mode(struct drm_device *dev) | |||
807 | return 0; | 807 | return 0; |
808 | } | 808 | } |
809 | EXPORT_SYMBOL(drm_helper_resume_force_mode); | 809 | EXPORT_SYMBOL(drm_helper_resume_force_mode); |
810 | |||
811 | static struct slow_work_ops output_poll_ops; | ||
812 | |||
813 | #define DRM_OUTPUT_POLL_PERIOD (10*HZ) | ||
814 | static void output_poll_execute(struct slow_work *work) | ||
815 | { | ||
816 | struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work); | ||
817 | struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work); | ||
818 | struct drm_connector *connector; | ||
819 | enum drm_connector_status old_status, status; | ||
820 | bool repoll = false, changed = false; | ||
821 | int ret; | ||
822 | |||
823 | mutex_lock(&dev->mode_config.mutex); | ||
824 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
825 | |||
826 | /* if this is HPD or polled don't check it - | ||
827 | TV out for instance */ | ||
828 | if (!connector->polled) | ||
829 | continue; | ||
830 | |||
831 | else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT)) | ||
832 | repoll = true; | ||
833 | |||
834 | old_status = connector->status; | ||
835 | /* if we are connected and don't want to poll for disconnect | ||
836 | skip it */ | ||
837 | if (old_status == connector_status_connected && | ||
838 | !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) && | ||
839 | !(connector->polled & DRM_CONNECTOR_POLL_HPD)) | ||
840 | continue; | ||
841 | |||
842 | status = connector->funcs->detect(connector); | ||
843 | if (old_status != status) | ||
844 | changed = true; | ||
845 | } | ||
846 | |||
847 | mutex_unlock(&dev->mode_config.mutex); | ||
848 | |||
849 | if (changed) { | ||
850 | /* send a uevent + call fbdev */ | ||
851 | drm_sysfs_hotplug_event(dev); | ||
852 | if (dev->mode_config.funcs->output_poll_changed) | ||
853 | dev->mode_config.funcs->output_poll_changed(dev); | ||
854 | } | ||
855 | |||
856 | if (repoll) { | ||
857 | ret = delayed_slow_work_enqueue(delayed_work, DRM_OUTPUT_POLL_PERIOD); | ||
858 | if (ret) | ||
859 | DRM_ERROR("delayed enqueue failed %d\n", ret); | ||
860 | } | ||
861 | } | ||
862 | |||
863 | void drm_kms_helper_poll_init(struct drm_device *dev) | ||
864 | { | ||
865 | struct drm_connector *connector; | ||
866 | bool poll = false; | ||
867 | int ret; | ||
868 | |||
869 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
870 | if (connector->polled) | ||
871 | poll = true; | ||
872 | } | ||
873 | slow_work_register_user(THIS_MODULE); | ||
874 | delayed_slow_work_init(&dev->mode_config.output_poll_slow_work, | ||
875 | &output_poll_ops); | ||
876 | |||
877 | if (poll) { | ||
878 | ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD); | ||
879 | if (ret) | ||
880 | DRM_ERROR("delayed enqueue failed %d\n", ret); | ||
881 | } | ||
882 | } | ||
883 | EXPORT_SYMBOL(drm_kms_helper_poll_init); | ||
884 | |||
885 | void drm_kms_helper_poll_fini(struct drm_device *dev) | ||
886 | { | ||
887 | delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); | ||
888 | slow_work_unregister_user(THIS_MODULE); | ||
889 | } | ||
890 | EXPORT_SYMBOL(drm_kms_helper_poll_fini); | ||
891 | |||
892 | void drm_helper_hpd_irq_event(struct drm_device *dev) | ||
893 | { | ||
894 | if (!dev->mode_config.poll_enabled) | ||
895 | return; | ||
896 | delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); | ||
897 | /* schedule a slow work asap */ | ||
898 | delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0); | ||
899 | } | ||
900 | EXPORT_SYMBOL(drm_helper_hpd_irq_event); | ||
901 | |||
902 | static struct slow_work_ops output_poll_ops = { | ||
903 | .execute = output_poll_execute, | ||
904 | }; | ||