diff options
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 32 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 1 |
2 files changed, 32 insertions, 1 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 738a4294d820..f6829ba58e86 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -122,6 +122,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, | |||
122 | int count = 0; | 122 | int count = 0; |
123 | int mode_flags = 0; | 123 | int mode_flags = 0; |
124 | bool verbose_prune = true; | 124 | bool verbose_prune = true; |
125 | enum drm_connector_status old_status; | ||
125 | 126 | ||
126 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, | 127 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, |
127 | drm_get_connector_name(connector)); | 128 | drm_get_connector_name(connector)); |
@@ -137,7 +138,32 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, | |||
137 | if (connector->funcs->force) | 138 | if (connector->funcs->force) |
138 | connector->funcs->force(connector); | 139 | connector->funcs->force(connector); |
139 | } else { | 140 | } else { |
141 | old_status = connector->status; | ||
142 | |||
140 | connector->status = connector->funcs->detect(connector, true); | 143 | connector->status = connector->funcs->detect(connector, true); |
144 | |||
145 | /* | ||
146 | * Normally either the driver's hpd code or the poll loop should | ||
147 | * pick up any changes and fire the hotplug event. But if | ||
148 | * userspace sneaks in a probe, we might miss a change. Hence | ||
149 | * check here, and if anything changed start the hotplug code. | ||
150 | */ | ||
151 | if (old_status != connector->status) { | ||
152 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", | ||
153 | connector->base.id, | ||
154 | drm_get_connector_name(connector), | ||
155 | old_status, connector->status); | ||
156 | |||
157 | /* | ||
158 | * The hotplug event code might call into the fb | ||
159 | * helpers, and so expects that we do not hold any | ||
160 | * locks. Fire up the poll struct instead, it will | ||
161 | * disable itself again. | ||
162 | */ | ||
163 | dev->mode_config.delayed_event = true; | ||
164 | schedule_delayed_work(&dev->mode_config.output_poll_work, | ||
165 | 0); | ||
166 | } | ||
141 | } | 167 | } |
142 | 168 | ||
143 | /* Re-enable polling in case the global poll config changed. */ | 169 | /* Re-enable polling in case the global poll config changed. */ |
@@ -985,7 +1011,11 @@ static void output_poll_execute(struct work_struct *work) | |||
985 | struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); | 1011 | struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); |
986 | struct drm_connector *connector; | 1012 | struct drm_connector *connector; |
987 | enum drm_connector_status old_status; | 1013 | enum drm_connector_status old_status; |
988 | bool repoll = false, changed = false; | 1014 | bool repoll = false, changed; |
1015 | |||
1016 | /* Pick up any changes detected by the probe functions. */ | ||
1017 | changed = dev->mode_config.delayed_event; | ||
1018 | dev->mode_config.delayed_event = false; | ||
989 | 1019 | ||
990 | if (!drm_kms_helper_poll) | 1020 | if (!drm_kms_helper_poll) |
991 | return; | 1021 | return; |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index b9ddd3d42acf..0fd007af8de9 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -808,6 +808,7 @@ struct drm_mode_config { | |||
808 | /* output poll support */ | 808 | /* output poll support */ |
809 | bool poll_enabled; | 809 | bool poll_enabled; |
810 | bool poll_running; | 810 | bool poll_running; |
811 | bool delayed_event; | ||
811 | struct delayed_work output_poll_work; | 812 | struct delayed_work output_poll_work; |
812 | 813 | ||
813 | /* pointers to standard properties */ | 814 | /* pointers to standard properties */ |