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