|
@@ -2288,6 +2288,10 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
|
|
crtc = obj_to_crtc(obj);
|
|
crtc = obj_to_crtc(obj);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * setplane_internal will take care of deref'ing either the old or new
|
|
|
|
+ * framebuffer depending on success.
|
|
|
|
+ */
|
|
return setplane_internal(crtc, plane, fb,
|
|
return setplane_internal(crtc, plane, fb,
|
|
plane_req->crtc_x, plane_req->crtc_y,
|
|
plane_req->crtc_x, plane_req->crtc_y,
|
|
plane_req->crtc_w, plane_req->crtc_h,
|
|
plane_req->crtc_w, plane_req->crtc_h,
|
|
@@ -2541,6 +2545,102 @@ out:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * drm_mode_cursor_universal - translate legacy cursor ioctl call into a
|
|
|
|
+ * universal plane handler call
|
|
|
|
+ * @crtc: crtc to update cursor for
|
|
|
|
+ * @req: data pointer for the ioctl
|
|
|
|
+ * @file_priv: drm file for the ioctl call
|
|
|
|
+ *
|
|
|
|
+ * Legacy cursor ioctl's work directly with driver buffer handles. To
|
|
|
|
+ * translate legacy ioctl calls into universal plane handler calls, we need to
|
|
|
|
+ * wrap the native buffer handle in a drm_framebuffer.
|
|
|
|
+ *
|
|
|
|
+ * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB
|
|
|
|
+ * buffer with a pitch of 4*width; the universal plane interface should be used
|
|
|
|
+ * directly in cases where the hardware can support other buffer settings and
|
|
|
|
+ * userspace wants to make use of these capabilities.
|
|
|
|
+ *
|
|
|
|
+ * Returns:
|
|
|
|
+ * Zero on success, errno on failure.
|
|
|
|
+ */
|
|
|
|
+static int drm_mode_cursor_universal(struct drm_crtc *crtc,
|
|
|
|
+ struct drm_mode_cursor2 *req,
|
|
|
|
+ struct drm_file *file_priv)
|
|
|
|
+{
|
|
|
|
+ struct drm_device *dev = crtc->dev;
|
|
|
|
+ struct drm_framebuffer *fb = NULL;
|
|
|
|
+ struct drm_mode_fb_cmd2 fbreq = {
|
|
|
|
+ .width = req->width,
|
|
|
|
+ .height = req->height,
|
|
|
|
+ .pixel_format = DRM_FORMAT_ARGB8888,
|
|
|
|
+ .pitches = { req->width * 4 },
|
|
|
|
+ .handles = { req->handle },
|
|
|
|
+ };
|
|
|
|
+ int32_t crtc_x, crtc_y;
|
|
|
|
+ uint32_t crtc_w = 0, crtc_h = 0;
|
|
|
|
+ uint32_t src_w = 0, src_h = 0;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ BUG_ON(!crtc->cursor);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Obtain fb we'll be using (either new or existing) and take an extra
|
|
|
|
+ * reference to it if fb != null. setplane will take care of dropping
|
|
|
|
+ * the reference if the plane update fails.
|
|
|
|
+ */
|
|
|
|
+ if (req->flags & DRM_MODE_CURSOR_BO) {
|
|
|
|
+ if (req->handle) {
|
|
|
|
+ fb = add_framebuffer_internal(dev, &fbreq, file_priv);
|
|
|
|
+ if (IS_ERR(fb)) {
|
|
|
|
+ DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
|
|
|
|
+ return PTR_ERR(fb);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ drm_framebuffer_reference(fb);
|
|
|
|
+ } else {
|
|
|
|
+ fb = NULL;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ mutex_lock(&dev->mode_config.mutex);
|
|
|
|
+ fb = crtc->cursor->fb;
|
|
|
|
+ if (fb)
|
|
|
|
+ drm_framebuffer_reference(fb);
|
|
|
|
+ mutex_unlock(&dev->mode_config.mutex);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (req->flags & DRM_MODE_CURSOR_MOVE) {
|
|
|
|
+ crtc_x = req->x;
|
|
|
|
+ crtc_y = req->y;
|
|
|
|
+ } else {
|
|
|
|
+ crtc_x = crtc->cursor_x;
|
|
|
|
+ crtc_y = crtc->cursor_y;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (fb) {
|
|
|
|
+ crtc_w = fb->width;
|
|
|
|
+ crtc_h = fb->height;
|
|
|
|
+ src_w = fb->width << 16;
|
|
|
|
+ src_h = fb->height << 16;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * setplane_internal will take care of deref'ing either the old or new
|
|
|
|
+ * framebuffer depending on success.
|
|
|
|
+ */
|
|
|
|
+ ret = setplane_internal(crtc, crtc->cursor, fb,
|
|
|
|
+ crtc_x, crtc_y, crtc_w, crtc_h,
|
|
|
|
+ 0, 0, src_w, src_h);
|
|
|
|
+
|
|
|
|
+ /* Update successful; save new cursor position, if necessary */
|
|
|
|
+ if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
|
|
|
|
+ crtc->cursor_x = req->x;
|
|
|
|
+ crtc->cursor_y = req->y;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
static int drm_mode_cursor_common(struct drm_device *dev,
|
|
static int drm_mode_cursor_common(struct drm_device *dev,
|
|
struct drm_mode_cursor2 *req,
|
|
struct drm_mode_cursor2 *req,
|
|
struct drm_file *file_priv)
|
|
struct drm_file *file_priv)
|
|
@@ -2560,6 +2660,13 @@ static int drm_mode_cursor_common(struct drm_device *dev,
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If this crtc has a universal cursor plane, call that plane's update
|
|
|
|
+ * handler rather than using legacy cursor handlers.
|
|
|
|
+ */
|
|
|
|
+ if (crtc->cursor)
|
|
|
|
+ return drm_mode_cursor_universal(crtc, req, file_priv);
|
|
|
|
+
|
|
drm_modeset_lock(&crtc->mutex, NULL);
|
|
drm_modeset_lock(&crtc->mutex, NULL);
|
|
if (req->flags & DRM_MODE_CURSOR_BO) {
|
|
if (req->flags & DRM_MODE_CURSOR_BO) {
|
|
if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
|
|
if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
|