]> Pileus Git - ~andy/linux/blobdiff - drivers/gpu/drm/drm_crtc.c
Merge remote-tracking branch 'airlied/drm-next' into drm-nouveau-next
[~andy/linux] / drivers / gpu / drm / drm_crtc.c
index a7dc1e266c989de11bdc6ca06fa7f5ff20b04293..fc83bb9eb51459cbdf5a1288fad6fa1c77d25b41 100644 (file)
@@ -1972,21 +1972,31 @@ out:
 int drm_mode_set_config_internal(struct drm_mode_set *set)
 {
        struct drm_crtc *crtc = set->crtc;
-       struct drm_framebuffer *fb, *old_fb;
+       struct drm_framebuffer *fb;
+       struct drm_crtc *tmp;
        int ret;
 
-       old_fb = crtc->fb;
+       /*
+        * NOTE: ->set_config can also disable other crtcs (if we steal all
+        * connectors from it), hence we need to refcount the fbs across all
+        * crtcs. Atomic modeset will have saner semantics ...
+        */
+       list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
+               tmp->old_fb = tmp->fb;
+
        fb = set->fb;
 
        ret = crtc->funcs->set_config(set);
        if (ret == 0) {
                /* crtc->fb must be updated by ->set_config, enforces this. */
                WARN_ON(fb != crtc->fb);
+       }
 
-               if (old_fb)
-                       drm_framebuffer_unreference(old_fb);
-               if (fb)
-                       drm_framebuffer_reference(fb);
+       list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
+               if (tmp->fb)
+                       drm_framebuffer_reference(tmp->fb);
+               if (tmp->old_fb)
+                       drm_framebuffer_unreference(tmp->old_fb);
        }
 
        return ret;
@@ -2168,10 +2178,10 @@ out:
        return ret;
 }
 
-int drm_mode_cursor_ioctl(struct drm_device *dev,
-                       void *data, struct drm_file *file_priv)
+static int drm_mode_cursor_common(struct drm_device *dev,
+                                 struct drm_mode_cursor2 *req,
+                                 struct drm_file *file_priv)
 {
-       struct drm_mode_cursor *req = data;
        struct drm_mode_object *obj;
        struct drm_crtc *crtc;
        int ret = 0;
@@ -2191,13 +2201,17 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
 
        mutex_lock(&crtc->mutex);
        if (req->flags & DRM_MODE_CURSOR_BO) {
-               if (!crtc->funcs->cursor_set) {
+               if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
                        ret = -ENXIO;
                        goto out;
                }
                /* Turns off the cursor if handle is 0 */
-               ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
-                                             req->width, req->height);
+               if (crtc->funcs->cursor_set2)
+                       ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
+                                                     req->width, req->height, req->hot_x, req->hot_y);
+               else
+                       ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
+                                                     req->width, req->height);
        }
 
        if (req->flags & DRM_MODE_CURSOR_MOVE) {
@@ -2212,6 +2226,25 @@ out:
        mutex_unlock(&crtc->mutex);
 
        return ret;
+
+}
+int drm_mode_cursor_ioctl(struct drm_device *dev,
+                       void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_cursor *req = data;
+       struct drm_mode_cursor2 new_req;
+
+       memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
+       new_req.hot_x = new_req.hot_y = 0;
+
+       return drm_mode_cursor_common(dev, &new_req, file_priv);
+}
+
+int drm_mode_cursor2_ioctl(struct drm_device *dev,
+                          void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_cursor2 *req = data;
+       return drm_mode_cursor_common(dev, req, file_priv);
 }
 
 /* Original addfb only supported RGB formats, so figure out which one */