linux/drivers/gpu/drm/drm_plane.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2016 Intel Corporation
   3 *
   4 * Permission to use, copy, modify, distribute, and sell this software and its
   5 * documentation for any purpose is hereby granted without fee, provided that
   6 * the above copyright notice appear in all copies and that both that copyright
   7 * notice and this permission notice appear in supporting documentation, and
   8 * that the name of the copyright holders not be used in advertising or
   9 * publicity pertaining to distribution of the software without specific,
  10 * written prior permission.  The copyright holders make no representations
  11 * about the suitability of this software for any purpose.  It is provided "as
  12 * is" without express or implied warranty.
  13 *
  14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  20 * OF THIS SOFTWARE.
  21 */
  22
  23#include <drm/drmP.h>
  24#include <drm/drm_plane.h>
  25
  26#include "drm_crtc_internal.h"
  27
  28/**
  29 * DOC: overview
  30 *
  31 * A plane represents an image source that can be blended with or overlayed on
  32 * top of a CRTC during the scanout process. Planes take their input data from a
  33 * &drm_framebuffer object. The plane itself specifies the cropping and scaling
  34 * of that image, and where it is placed on the visible are of a display
  35 * pipeline, represented by &drm_crtc. A plane can also have additional
  36 * properties that specify how the pixels are positioned and blended, like
  37 * rotation or Z-position. All these properties are stored in &drm_plane_state.
  38 *
  39 * To create a plane, a KMS drivers allocates and zeroes an instances of
  40 * struct &drm_plane (possibly as part of a larger structure) and registers it
  41 * with a call to drm_universal_plane_init().
  42 *
  43 * Cursor and overlay planes are optional. All drivers should provide one
  44 * primary plane per CRTC to avoid surprising userspace too much. See enum
  45 * &drm_plane_type for a more in-depth discussion of these special uapi-relevant
  46 * plane types. Special planes are associated with their CRTC by calling
  47 * drm_crtc_init_with_planes().
  48 *
  49 * The type of a plane is exposed in the immutable "type" enumeration property,
  50 * which has one of the following values: "Overlay", "Primary", "Cursor".
  51 */
  52
  53static unsigned int drm_num_planes(struct drm_device *dev)
  54{
  55        unsigned int num = 0;
  56        struct drm_plane *tmp;
  57
  58        drm_for_each_plane(tmp, dev) {
  59                num++;
  60        }
  61
  62        return num;
  63}
  64
  65/**
  66 * drm_universal_plane_init - Initialize a new universal plane object
  67 * @dev: DRM device
  68 * @plane: plane object to init
  69 * @possible_crtcs: bitmask of possible CRTCs
  70 * @funcs: callbacks for the new plane
  71 * @formats: array of supported formats (DRM_FORMAT\_\*)
  72 * @format_count: number of elements in @formats
  73 * @type: type of plane (overlay, primary, cursor)
  74 * @name: printf style format string for the plane name, or NULL for default name
  75 *
  76 * Initializes a plane object of type @type.
  77 *
  78 * Returns:
  79 * Zero on success, error code on failure.
  80 */
  81int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
  82                             unsigned long possible_crtcs,
  83                             const struct drm_plane_funcs *funcs,
  84                             const uint32_t *formats, unsigned int format_count,
  85                             enum drm_plane_type type,
  86                             const char *name, ...)
  87{
  88        struct drm_mode_config *config = &dev->mode_config;
  89        int ret;
  90
  91        ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
  92        if (ret)
  93                return ret;
  94
  95        drm_modeset_lock_init(&plane->mutex);
  96
  97        plane->base.properties = &plane->properties;
  98        plane->dev = dev;
  99        plane->funcs = funcs;
 100        plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
 101                                            GFP_KERNEL);
 102        if (!plane->format_types) {
 103                DRM_DEBUG_KMS("out of memory when allocating plane\n");
 104                drm_mode_object_unregister(dev, &plane->base);
 105                return -ENOMEM;
 106        }
 107
 108        if (name) {
 109                va_list ap;
 110
 111                va_start(ap, name);
 112                plane->name = kvasprintf(GFP_KERNEL, name, ap);
 113                va_end(ap);
 114        } else {
 115                plane->name = kasprintf(GFP_KERNEL, "plane-%d",
 116                                        drm_num_planes(dev));
 117        }
 118        if (!plane->name) {
 119                kfree(plane->format_types);
 120                drm_mode_object_unregister(dev, &plane->base);
 121                return -ENOMEM;
 122        }
 123
 124        memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
 125        plane->format_count = format_count;
 126        plane->possible_crtcs = possible_crtcs;
 127        plane->type = type;
 128
 129        list_add_tail(&plane->head, &config->plane_list);
 130        plane->index = config->num_total_plane++;
 131        if (plane->type == DRM_PLANE_TYPE_OVERLAY)
 132                config->num_overlay_plane++;
 133
 134        drm_object_attach_property(&plane->base,
 135                                   config->plane_type_property,
 136                                   plane->type);
 137
 138        if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
 139                drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
 140                drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
 141                drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
 142                drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
 143                drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
 144                drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
 145                drm_object_attach_property(&plane->base, config->prop_src_x, 0);
 146                drm_object_attach_property(&plane->base, config->prop_src_y, 0);
 147                drm_object_attach_property(&plane->base, config->prop_src_w, 0);
 148                drm_object_attach_property(&plane->base, config->prop_src_h, 0);
 149        }
 150
 151        return 0;
 152}
 153EXPORT_SYMBOL(drm_universal_plane_init);
 154
 155int drm_plane_register_all(struct drm_device *dev)
 156{
 157        struct drm_plane *plane;
 158        int ret = 0;
 159
 160        drm_for_each_plane(plane, dev) {
 161                if (plane->funcs->late_register)
 162                        ret = plane->funcs->late_register(plane);
 163                if (ret)
 164                        return ret;
 165        }
 166
 167        return 0;
 168}
 169
 170void drm_plane_unregister_all(struct drm_device *dev)
 171{
 172        struct drm_plane *plane;
 173
 174        drm_for_each_plane(plane, dev) {
 175                if (plane->funcs->early_unregister)
 176                        plane->funcs->early_unregister(plane);
 177        }
 178}
 179
 180/**
 181 * drm_plane_init - Initialize a legacy plane
 182 * @dev: DRM device
 183 * @plane: plane object to init
 184 * @possible_crtcs: bitmask of possible CRTCs
 185 * @funcs: callbacks for the new plane
 186 * @formats: array of supported formats (DRM_FORMAT\_\*)
 187 * @format_count: number of elements in @formats
 188 * @is_primary: plane type (primary vs overlay)
 189 *
 190 * Legacy API to initialize a DRM plane.
 191 *
 192 * New drivers should call drm_universal_plane_init() instead.
 193 *
 194 * Returns:
 195 * Zero on success, error code on failure.
 196 */
 197int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 198                   unsigned long possible_crtcs,
 199                   const struct drm_plane_funcs *funcs,
 200                   const uint32_t *formats, unsigned int format_count,
 201                   bool is_primary)
 202{
 203        enum drm_plane_type type;
 204
 205        type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
 206        return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
 207                                        formats, format_count, type, NULL);
 208}
 209EXPORT_SYMBOL(drm_plane_init);
 210
 211/**
 212 * drm_plane_cleanup - Clean up the core plane usage
 213 * @plane: plane to cleanup
 214 *
 215 * This function cleans up @plane and removes it from the DRM mode setting
 216 * core. Note that the function does *not* free the plane structure itself,
 217 * this is the responsibility of the caller.
 218 */
 219void drm_plane_cleanup(struct drm_plane *plane)
 220{
 221        struct drm_device *dev = plane->dev;
 222
 223        drm_modeset_lock_all(dev);
 224        kfree(plane->format_types);
 225        drm_mode_object_unregister(dev, &plane->base);
 226
 227        BUG_ON(list_empty(&plane->head));
 228
 229        /* Note that the plane_list is considered to be static; should we
 230         * remove the drm_plane at runtime we would have to decrement all
 231         * the indices on the drm_plane after us in the plane_list.
 232         */
 233
 234        list_del(&plane->head);
 235        dev->mode_config.num_total_plane--;
 236        if (plane->type == DRM_PLANE_TYPE_OVERLAY)
 237                dev->mode_config.num_overlay_plane--;
 238        drm_modeset_unlock_all(dev);
 239
 240        WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
 241        if (plane->state && plane->funcs->atomic_destroy_state)
 242                plane->funcs->atomic_destroy_state(plane, plane->state);
 243
 244        kfree(plane->name);
 245
 246        memset(plane, 0, sizeof(*plane));
 247}
 248EXPORT_SYMBOL(drm_plane_cleanup);
 249
 250/**
 251 * drm_plane_from_index - find the registered plane at an index
 252 * @dev: DRM device
 253 * @idx: index of registered plane to find for
 254 *
 255 * Given a plane index, return the registered plane from DRM device's
 256 * list of planes with matching index.
 257 */
 258struct drm_plane *
 259drm_plane_from_index(struct drm_device *dev, int idx)
 260{
 261        struct drm_plane *plane;
 262
 263        drm_for_each_plane(plane, dev)
 264                if (idx == plane->index)
 265                        return plane;
 266
 267        return NULL;
 268}
 269EXPORT_SYMBOL(drm_plane_from_index);
 270
 271/**
 272 * drm_plane_force_disable - Forcibly disable a plane
 273 * @plane: plane to disable
 274 *
 275 * Forces the plane to be disabled.
 276 *
 277 * Used when the plane's current framebuffer is destroyed,
 278 * and when restoring fbdev mode.
 279 */
 280void drm_plane_force_disable(struct drm_plane *plane)
 281{
 282        int ret;
 283
 284        if (!plane->fb)
 285                return;
 286
 287        plane->old_fb = plane->fb;
 288        ret = plane->funcs->disable_plane(plane);
 289        if (ret) {
 290                DRM_ERROR("failed to disable plane with busy fb\n");
 291                plane->old_fb = NULL;
 292                return;
 293        }
 294        /* disconnect the plane from the fb and crtc: */
 295        drm_framebuffer_unreference(plane->old_fb);
 296        plane->old_fb = NULL;
 297        plane->fb = NULL;
 298        plane->crtc = NULL;
 299}
 300EXPORT_SYMBOL(drm_plane_force_disable);
 301
 302/**
 303 * drm_mode_plane_set_obj_prop - set the value of a property
 304 * @plane: drm plane object to set property value for
 305 * @property: property to set
 306 * @value: value the property should be set to
 307 *
 308 * This functions sets a given property on a given plane object. This function
 309 * calls the driver's ->set_property callback and changes the software state of
 310 * the property if the callback succeeds.
 311 *
 312 * Returns:
 313 * Zero on success, error code on failure.
 314 */
 315int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 316                                struct drm_property *property,
 317                                uint64_t value)
 318{
 319        int ret = -EINVAL;
 320        struct drm_mode_object *obj = &plane->base;
 321
 322        if (plane->funcs->set_property)
 323                ret = plane->funcs->set_property(plane, property, value);
 324        if (!ret)
 325                drm_object_property_set_value(obj, property, value);
 326
 327        return ret;
 328}
 329EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
 330
 331int drm_mode_getplane_res(struct drm_device *dev, void *data,
 332                          struct drm_file *file_priv)
 333{
 334        struct drm_mode_get_plane_res *plane_resp = data;
 335        struct drm_mode_config *config;
 336        struct drm_plane *plane;
 337        uint32_t __user *plane_ptr;
 338        int copied = 0;
 339        unsigned num_planes;
 340
 341        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 342                return -EINVAL;
 343
 344        config = &dev->mode_config;
 345
 346        if (file_priv->universal_planes)
 347                num_planes = config->num_total_plane;
 348        else
 349                num_planes = config->num_overlay_plane;
 350
 351        /*
 352         * This ioctl is called twice, once to determine how much space is
 353         * needed, and the 2nd time to fill it.
 354         */
 355        if (num_planes &&
 356            (plane_resp->count_planes >= num_planes)) {
 357                plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
 358
 359                /* Plane lists are invariant, no locking needed. */
 360                drm_for_each_plane(plane, dev) {
 361                        /*
 362                         * Unless userspace set the 'universal planes'
 363                         * capability bit, only advertise overlays.
 364                         */
 365                        if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
 366                            !file_priv->universal_planes)
 367                                continue;
 368
 369                        if (put_user(plane->base.id, plane_ptr + copied))
 370                                return -EFAULT;
 371                        copied++;
 372                }
 373        }
 374        plane_resp->count_planes = num_planes;
 375
 376        return 0;
 377}
 378
 379int drm_mode_getplane(struct drm_device *dev, void *data,
 380                      struct drm_file *file_priv)
 381{
 382        struct drm_mode_get_plane *plane_resp = data;
 383        struct drm_plane *plane;
 384        uint32_t __user *format_ptr;
 385
 386        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 387                return -EINVAL;
 388
 389        plane = drm_plane_find(dev, plane_resp->plane_id);
 390        if (!plane)
 391                return -ENOENT;
 392
 393        drm_modeset_lock(&plane->mutex, NULL);
 394        if (plane->crtc)
 395                plane_resp->crtc_id = plane->crtc->base.id;
 396        else
 397                plane_resp->crtc_id = 0;
 398
 399        if (plane->fb)
 400                plane_resp->fb_id = plane->fb->base.id;
 401        else
 402                plane_resp->fb_id = 0;
 403        drm_modeset_unlock(&plane->mutex);
 404
 405        plane_resp->plane_id = plane->base.id;
 406        plane_resp->possible_crtcs = plane->possible_crtcs;
 407        plane_resp->gamma_size = 0;
 408
 409        /*
 410         * This ioctl is called twice, once to determine how much space is
 411         * needed, and the 2nd time to fill it.
 412         */
 413        if (plane->format_count &&
 414            (plane_resp->count_format_types >= plane->format_count)) {
 415                format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
 416                if (copy_to_user(format_ptr,
 417                                 plane->format_types,
 418                                 sizeof(uint32_t) * plane->format_count)) {
 419                        return -EFAULT;
 420                }
 421        }
 422        plane_resp->count_format_types = plane->format_count;
 423
 424        return 0;
 425}
 426
 427int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format)
 428{
 429        unsigned int i;
 430
 431        for (i = 0; i < plane->format_count; i++) {
 432                if (format == plane->format_types[i])
 433                        return 0;
 434        }
 435
 436        return -EINVAL;
 437}
 438
 439/*
 440 * setplane_internal - setplane handler for internal callers
 441 *
 442 * Note that we assume an extra reference has already been taken on fb.  If the
 443 * update fails, this reference will be dropped before return; if it succeeds,
 444 * the previous framebuffer (if any) will be unreferenced instead.
 445 *
 446 * src_{x,y,w,h} are provided in 16.16 fixed point format
 447 */
 448static int __setplane_internal(struct drm_plane *plane,
 449                               struct drm_crtc *crtc,
 450                               struct drm_framebuffer *fb,
 451                               int32_t crtc_x, int32_t crtc_y,
 452                               uint32_t crtc_w, uint32_t crtc_h,
 453                               /* src_{x,y,w,h} values are 16.16 fixed point */
 454                               uint32_t src_x, uint32_t src_y,
 455                               uint32_t src_w, uint32_t src_h)
 456{
 457        int ret = 0;
 458
 459        /* No fb means shut it down */
 460        if (!fb) {
 461                plane->old_fb = plane->fb;
 462                ret = plane->funcs->disable_plane(plane);
 463                if (!ret) {
 464                        plane->crtc = NULL;
 465                        plane->fb = NULL;
 466                } else {
 467                        plane->old_fb = NULL;
 468                }
 469                goto out;
 470        }
 471
 472        /* Check whether this plane is usable on this CRTC */
 473        if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
 474                DRM_DEBUG_KMS("Invalid crtc for plane\n");
 475                ret = -EINVAL;
 476                goto out;
 477        }
 478
 479        /* Check whether this plane supports the fb pixel format. */
 480        ret = drm_plane_check_pixel_format(plane, fb->pixel_format);
 481        if (ret) {
 482                char *format_name = drm_get_format_name(fb->pixel_format);
 483                DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name);
 484                kfree(format_name);
 485                goto out;
 486        }
 487
 488        /* Give drivers some help against integer overflows */
 489        if (crtc_w > INT_MAX ||
 490            crtc_x > INT_MAX - (int32_t) crtc_w ||
 491            crtc_h > INT_MAX ||
 492            crtc_y > INT_MAX - (int32_t) crtc_h) {
 493                DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
 494                              crtc_w, crtc_h, crtc_x, crtc_y);
 495                ret = -ERANGE;
 496                goto out;
 497        }
 498
 499        ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb);
 500        if (ret)
 501                goto out;
 502
 503        plane->old_fb = plane->fb;
 504        ret = plane->funcs->update_plane(plane, crtc, fb,
 505                                         crtc_x, crtc_y, crtc_w, crtc_h,
 506                                         src_x, src_y, src_w, src_h);
 507        if (!ret) {
 508                plane->crtc = crtc;
 509                plane->fb = fb;
 510                fb = NULL;
 511        } else {
 512                plane->old_fb = NULL;
 513        }
 514
 515out:
 516        if (fb)
 517                drm_framebuffer_unreference(fb);
 518        if (plane->old_fb)
 519                drm_framebuffer_unreference(plane->old_fb);
 520        plane->old_fb = NULL;
 521
 522        return ret;
 523}
 524
 525static int setplane_internal(struct drm_plane *plane,
 526                             struct drm_crtc *crtc,
 527                             struct drm_framebuffer *fb,
 528                             int32_t crtc_x, int32_t crtc_y,
 529                             uint32_t crtc_w, uint32_t crtc_h,
 530                             /* src_{x,y,w,h} values are 16.16 fixed point */
 531                             uint32_t src_x, uint32_t src_y,
 532                             uint32_t src_w, uint32_t src_h)
 533{
 534        int ret;
 535
 536        drm_modeset_lock_all(plane->dev);
 537        ret = __setplane_internal(plane, crtc, fb,
 538                                  crtc_x, crtc_y, crtc_w, crtc_h,
 539                                  src_x, src_y, src_w, src_h);
 540        drm_modeset_unlock_all(plane->dev);
 541
 542        return ret;
 543}
 544
 545int drm_mode_setplane(struct drm_device *dev, void *data,
 546                      struct drm_file *file_priv)
 547{
 548        struct drm_mode_set_plane *plane_req = data;
 549        struct drm_plane *plane;
 550        struct drm_crtc *crtc = NULL;
 551        struct drm_framebuffer *fb = NULL;
 552
 553        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 554                return -EINVAL;
 555
 556        /*
 557         * First, find the plane, crtc, and fb objects.  If not available,
 558         * we don't bother to call the driver.
 559         */
 560        plane = drm_plane_find(dev, plane_req->plane_id);
 561        if (!plane) {
 562                DRM_DEBUG_KMS("Unknown plane ID %d\n",
 563                              plane_req->plane_id);
 564                return -ENOENT;
 565        }
 566
 567        if (plane_req->fb_id) {
 568                fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
 569                if (!fb) {
 570                        DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
 571                                      plane_req->fb_id);
 572                        return -ENOENT;
 573                }
 574
 575                crtc = drm_crtc_find(dev, plane_req->crtc_id);
 576                if (!crtc) {
 577                        DRM_DEBUG_KMS("Unknown crtc ID %d\n",
 578                                      plane_req->crtc_id);
 579                        return -ENOENT;
 580                }
 581        }
 582
 583        /*
 584         * setplane_internal will take care of deref'ing either the old or new
 585         * framebuffer depending on success.
 586         */
 587        return setplane_internal(plane, crtc, fb,
 588                                 plane_req->crtc_x, plane_req->crtc_y,
 589                                 plane_req->crtc_w, plane_req->crtc_h,
 590                                 plane_req->src_x, plane_req->src_y,
 591                                 plane_req->src_w, plane_req->src_h);
 592}
 593
 594static int drm_mode_cursor_universal(struct drm_crtc *crtc,
 595                                     struct drm_mode_cursor2 *req,
 596                                     struct drm_file *file_priv)
 597{
 598        struct drm_device *dev = crtc->dev;
 599        struct drm_framebuffer *fb = NULL;
 600        struct drm_mode_fb_cmd2 fbreq = {
 601                .width = req->width,
 602                .height = req->height,
 603                .pixel_format = DRM_FORMAT_ARGB8888,
 604                .pitches = { req->width * 4 },
 605                .handles = { req->handle },
 606        };
 607        int32_t crtc_x, crtc_y;
 608        uint32_t crtc_w = 0, crtc_h = 0;
 609        uint32_t src_w = 0, src_h = 0;
 610        int ret = 0;
 611
 612        BUG_ON(!crtc->cursor);
 613        WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL);
 614
 615        /*
 616         * Obtain fb we'll be using (either new or existing) and take an extra
 617         * reference to it if fb != null.  setplane will take care of dropping
 618         * the reference if the plane update fails.
 619         */
 620        if (req->flags & DRM_MODE_CURSOR_BO) {
 621                if (req->handle) {
 622                        fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv);
 623                        if (IS_ERR(fb)) {
 624                                DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
 625                                return PTR_ERR(fb);
 626                        }
 627                        fb->hot_x = req->hot_x;
 628                        fb->hot_y = req->hot_y;
 629                } else {
 630                        fb = NULL;
 631                }
 632        } else {
 633                fb = crtc->cursor->fb;
 634                if (fb)
 635                        drm_framebuffer_reference(fb);
 636        }
 637
 638        if (req->flags & DRM_MODE_CURSOR_MOVE) {
 639                crtc_x = req->x;
 640                crtc_y = req->y;
 641        } else {
 642                crtc_x = crtc->cursor_x;
 643                crtc_y = crtc->cursor_y;
 644        }
 645
 646        if (fb) {
 647                crtc_w = fb->width;
 648                crtc_h = fb->height;
 649                src_w = fb->width << 16;
 650                src_h = fb->height << 16;
 651        }
 652
 653        /*
 654         * setplane_internal will take care of deref'ing either the old or new
 655         * framebuffer depending on success.
 656         */
 657        ret = __setplane_internal(crtc->cursor, crtc, fb,
 658                                crtc_x, crtc_y, crtc_w, crtc_h,
 659                                0, 0, src_w, src_h);
 660
 661        /* Update successful; save new cursor position, if necessary */
 662        if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
 663                crtc->cursor_x = req->x;
 664                crtc->cursor_y = req->y;
 665        }
 666
 667        return ret;
 668}
 669
 670static int drm_mode_cursor_common(struct drm_device *dev,
 671                                  struct drm_mode_cursor2 *req,
 672                                  struct drm_file *file_priv)
 673{
 674        struct drm_crtc *crtc;
 675        int ret = 0;
 676
 677        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 678                return -EINVAL;
 679
 680        if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
 681                return -EINVAL;
 682
 683        crtc = drm_crtc_find(dev, req->crtc_id);
 684        if (!crtc) {
 685                DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
 686                return -ENOENT;
 687        }
 688
 689        /*
 690         * If this crtc has a universal cursor plane, call that plane's update
 691         * handler rather than using legacy cursor handlers.
 692         */
 693        drm_modeset_lock_crtc(crtc, crtc->cursor);
 694        if (crtc->cursor) {
 695                ret = drm_mode_cursor_universal(crtc, req, file_priv);
 696                goto out;
 697        }
 698
 699        if (req->flags & DRM_MODE_CURSOR_BO) {
 700                if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
 701                        ret = -ENXIO;
 702                        goto out;
 703                }
 704                /* Turns off the cursor if handle is 0 */
 705                if (crtc->funcs->cursor_set2)
 706                        ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
 707                                                      req->width, req->height, req->hot_x, req->hot_y);
 708                else
 709                        ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
 710                                                      req->width, req->height);
 711        }
 712
 713        if (req->flags & DRM_MODE_CURSOR_MOVE) {
 714                if (crtc->funcs->cursor_move) {
 715                        ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
 716                } else {
 717                        ret = -EFAULT;
 718                        goto out;
 719                }
 720        }
 721out:
 722        drm_modeset_unlock_crtc(crtc);
 723
 724        return ret;
 725
 726}
 727
 728
 729int drm_mode_cursor_ioctl(struct drm_device *dev,
 730                          void *data, struct drm_file *file_priv)
 731{
 732        struct drm_mode_cursor *req = data;
 733        struct drm_mode_cursor2 new_req;
 734
 735        memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
 736        new_req.hot_x = new_req.hot_y = 0;
 737
 738        return drm_mode_cursor_common(dev, &new_req, file_priv);
 739}
 740
 741/*
 742 * Set the cursor configuration based on user request. This implements the 2nd
 743 * version of the cursor ioctl, which allows userspace to additionally specify
 744 * the hotspot of the pointer.
 745 */
 746int drm_mode_cursor2_ioctl(struct drm_device *dev,
 747                           void *data, struct drm_file *file_priv)
 748{
 749        struct drm_mode_cursor2 *req = data;
 750
 751        return drm_mode_cursor_common(dev, req, file_priv);
 752}
 753
 754int drm_mode_page_flip_ioctl(struct drm_device *dev,
 755                             void *data, struct drm_file *file_priv)
 756{
 757        struct drm_mode_crtc_page_flip_target *page_flip = data;
 758        struct drm_crtc *crtc;
 759        struct drm_framebuffer *fb = NULL;
 760        struct drm_pending_vblank_event *e = NULL;
 761        u32 target_vblank = page_flip->sequence;
 762        int ret = -EINVAL;
 763
 764        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 765                return -EINVAL;
 766
 767        if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)
 768                return -EINVAL;
 769
 770        if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
 771                return -EINVAL;
 772
 773        /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags
 774         * can be specified
 775         */
 776        if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)
 777                return -EINVAL;
 778
 779        if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
 780                return -EINVAL;
 781
 782        crtc = drm_crtc_find(dev, page_flip->crtc_id);
 783        if (!crtc)
 784                return -ENOENT;
 785
 786        if (crtc->funcs->page_flip_target) {
 787                u32 current_vblank;
 788                int r;
 789
 790                r = drm_crtc_vblank_get(crtc);
 791                if (r)
 792                        return r;
 793
 794                current_vblank = drm_crtc_vblank_count(crtc);
 795
 796                switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
 797                case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
 798                        if ((int)(target_vblank - current_vblank) > 1) {
 799                                DRM_DEBUG("Invalid absolute flip target %u, "
 800                                          "must be <= %u\n", target_vblank,
 801                                          current_vblank + 1);
 802                                drm_crtc_vblank_put(crtc);
 803                                return -EINVAL;
 804                        }
 805                        break;
 806                case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
 807                        if (target_vblank != 0 && target_vblank != 1) {
 808                                DRM_DEBUG("Invalid relative flip target %u, "
 809                                          "must be 0 or 1\n", target_vblank);
 810                                drm_crtc_vblank_put(crtc);
 811                                return -EINVAL;
 812                        }
 813                        target_vblank += current_vblank;
 814                        break;
 815                default:
 816                        target_vblank = current_vblank +
 817                                !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
 818                        break;
 819                }
 820        } else if (crtc->funcs->page_flip == NULL ||
 821                   (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
 822                return -EINVAL;
 823        }
 824
 825        drm_modeset_lock_crtc(crtc, crtc->primary);
 826        if (crtc->primary->fb == NULL) {
 827                /* The framebuffer is currently unbound, presumably
 828                 * due to a hotplug event, that userspace has not
 829                 * yet discovered.
 830                 */
 831                ret = -EBUSY;
 832                goto out;
 833        }
 834
 835        fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
 836        if (!fb) {
 837                ret = -ENOENT;
 838                goto out;
 839        }
 840
 841        if (crtc->state) {
 842                const struct drm_plane_state *state = crtc->primary->state;
 843
 844                ret = drm_framebuffer_check_src_coords(state->src_x,
 845                                                       state->src_y,
 846                                                       state->src_w,
 847                                                       state->src_h,
 848                                                       fb);
 849        } else {
 850                ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
 851        }
 852        if (ret)
 853                goto out;
 854
 855        if (crtc->primary->fb->pixel_format != fb->pixel_format) {
 856                DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
 857                ret = -EINVAL;
 858                goto out;
 859        }
 860
 861        if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
 862                e = kzalloc(sizeof *e, GFP_KERNEL);
 863                if (!e) {
 864                        ret = -ENOMEM;
 865                        goto out;
 866                }
 867                e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
 868                e->event.base.length = sizeof(e->event);
 869                e->event.user_data = page_flip->user_data;
 870                ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
 871                if (ret) {
 872                        kfree(e);
 873                        goto out;
 874                }
 875        }
 876
 877        crtc->primary->old_fb = crtc->primary->fb;
 878        if (crtc->funcs->page_flip_target)
 879                ret = crtc->funcs->page_flip_target(crtc, fb, e,
 880                                                    page_flip->flags,
 881                                                    target_vblank);
 882        else
 883                ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
 884        if (ret) {
 885                if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
 886                        drm_event_cancel_free(dev, &e->base);
 887                /* Keep the old fb, don't unref it. */
 888                crtc->primary->old_fb = NULL;
 889        } else {
 890                crtc->primary->fb = fb;
 891                /* Unref only the old framebuffer. */
 892                fb = NULL;
 893        }
 894
 895out:
 896        if (ret && crtc->funcs->page_flip_target)
 897                drm_crtc_vblank_put(crtc);
 898        if (fb)
 899                drm_framebuffer_unreference(fb);
 900        if (crtc->primary->old_fb)
 901                drm_framebuffer_unreference(crtc->primary->old_fb);
 902        crtc->primary->old_fb = NULL;
 903        drm_modeset_unlock_crtc(crtc);
 904
 905        return ret;
 906}
 907