aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_probe_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_probe_helper.c')
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 2fbdcca7ca9a..33bf550a1d3f 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -103,6 +103,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
103 int count = 0; 103 int count = 0;
104 int mode_flags = 0; 104 int mode_flags = 0;
105 bool verbose_prune = true; 105 bool verbose_prune = true;
106 enum drm_connector_status old_status;
106 107
107 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 108 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
108 109
@@ -121,7 +122,33 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
121 if (connector->funcs->force) 122 if (connector->funcs->force)
122 connector->funcs->force(connector); 123 connector->funcs->force(connector);
123 } else { 124 } else {
125 old_status = connector->status;
126
124 connector->status = connector->funcs->detect(connector, true); 127 connector->status = connector->funcs->detect(connector, true);
128
129 /*
130 * Normally either the driver's hpd code or the poll loop should
131 * pick up any changes and fire the hotplug event. But if
132 * userspace sneaks in a probe, we might miss a change. Hence
133 * check here, and if anything changed start the hotplug code.
134 */
135 if (old_status != connector->status) {
136 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
137 connector->base.id,
138 connector->name,
139 old_status, connector->status);
140
141 /*
142 * The hotplug event code might call into the fb
143 * helpers, and so expects that we do not hold any
144 * locks. Fire up the poll struct instead, it will
145 * disable itself again.
146 */
147 dev->mode_config.delayed_event = true;
148 if (dev->mode_config.poll_enabled)
149 schedule_delayed_work(&dev->mode_config.output_poll_work,
150 0);
151 }
125 } 152 }
126 153
127 /* Re-enable polling in case the global poll config changed. */ 154 /* Re-enable polling in case the global poll config changed. */
@@ -274,10 +301,14 @@ static void output_poll_execute(struct work_struct *work)
274 struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); 301 struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);
275 struct drm_connector *connector; 302 struct drm_connector *connector;
276 enum drm_connector_status old_status; 303 enum drm_connector_status old_status;
277 bool repoll = false, changed = false; 304 bool repoll = false, changed;
305
306 /* Pick up any changes detected by the probe functions. */
307 changed = dev->mode_config.delayed_event;
308 dev->mode_config.delayed_event = false;
278 309
279 if (!drm_kms_helper_poll) 310 if (!drm_kms_helper_poll)
280 return; 311 goto out;
281 312
282 mutex_lock(&dev->mode_config.mutex); 313 mutex_lock(&dev->mode_config.mutex);
283 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 314 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -319,6 +350,7 @@ static void output_poll_execute(struct work_struct *work)
319 350
320 mutex_unlock(&dev->mode_config.mutex); 351 mutex_unlock(&dev->mode_config.mutex);
321 352
353out:
322 if (changed) 354 if (changed)
323 drm_kms_helper_hotplug_event(dev); 355 drm_kms_helper_hotplug_event(dev);
324 356