diff options
Diffstat (limited to 'drivers/gpu/drm/drm_probe_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_probe_helper.c | 36 |
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 | ||
353 | out: | ||
322 | if (changed) | 354 | if (changed) |
323 | drm_kms_helper_hotplug_event(dev); | 355 | drm_kms_helper_hotplug_event(dev); |
324 | 356 | ||