summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2012-03-13 12:35:46 +0200
committerDave Airlie <airlied@redhat.com>2012-03-15 09:51:42 +0000
commitac235dafb60d3ba4fa4e7341503b16d6e0645ee7 (patch)
treea544dc5b4c4677b9627d82f87845d93be4fcb0c2
parent5f61bb421f01023986902200b6486978c07176f7 (diff)
downloadlinux-stable-ac235dafb60d3ba4fa4e7341503b16d6e0645ee7.tar.gz
linux-stable-ac235dafb60d3ba4fa4e7341503b16d6e0645ee7.tar.bz2
linux-stable-ac235dafb60d3ba4fa4e7341503b16d6e0645ee7.zip
drm: Fix drm_mode_attachmode_crtc()
Change drm_mode_attachmode_crtc() to take an "all or nothing" approach. If an error is returned, there are no side effects visible. Also change the function to always duplicate the mode passed in. Also change the function to not give up when it finds the first connector without and encoder. A simpler approach would be to just remove the function completely as it's unused currently. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_crtc.c38
-rw-r--r--include/drm/drm_crtc.h2
2 files changed, 28 insertions, 12 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 3f5c603f9a2c..37d34ad3a0b8 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2421,24 +2421,40 @@ static void drm_mode_attachmode(struct drm_device *dev,
}
int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc,
- struct drm_display_mode *mode)
+ const struct drm_display_mode *mode)
{
struct drm_connector *connector;
- struct drm_display_mode *dup_mode;
- int need_dup = 0;
+ int ret = 0;
+ struct drm_display_mode *dup_mode, *next;
+ LIST_HEAD(list);
+
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (!connector->encoder)
- break;
+ continue;
if (connector->encoder->crtc == crtc) {
- if (need_dup)
- dup_mode = drm_mode_duplicate(dev, mode);
- else
- dup_mode = mode;
- drm_mode_attachmode(dev, connector, dup_mode);
- need_dup = 1;
+ dup_mode = drm_mode_duplicate(dev, mode);
+ if (!dup_mode) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ list_add_tail(&dup_mode->head, &list);
}
}
- return 0;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if (!connector->encoder)
+ continue;
+ if (connector->encoder->crtc == crtc)
+ list_move_tail(list.next, &connector->user_modes);
+ }
+
+ WARN_ON(!list_empty(&list));
+
+ out:
+ list_for_each_entry_safe(dup_mode, next, &list, head)
+ drm_mode_destroy(dev, dup_mode);
+
+ return ret;
}
EXPORT_SYMBOL(drm_mode_attachmode_crtc);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 31715bd4f42a..fe7ebc6b8c93 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -869,7 +869,7 @@ extern int drm_mode_height(struct drm_display_mode *mode);
/* for us by fb module */
extern int drm_mode_attachmode_crtc(struct drm_device *dev,
struct drm_crtc *crtc,
- struct drm_display_mode *mode);
+ const struct drm_display_mode *mode);
extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode);
extern struct drm_display_mode *drm_mode_create(struct drm_device *dev);