aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r--drivers/gpu/drm/drm_crtc.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5cae0b3eee9b..32756e67dd56 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2478,3 +2478,72 @@ out:
2478 mutex_unlock(&dev->mode_config.mutex); 2478 mutex_unlock(&dev->mode_config.mutex);
2479 return ret; 2479 return ret;
2480} 2480}
2481
2482int drm_mode_page_flip_ioctl(struct drm_device *dev,
2483 void *data, struct drm_file *file_priv)
2484{
2485 struct drm_mode_crtc_page_flip *page_flip = data;
2486 struct drm_mode_object *obj;
2487 struct drm_crtc *crtc;
2488 struct drm_framebuffer *fb;
2489 struct drm_pending_vblank_event *e = NULL;
2490 unsigned long flags;
2491 int ret = -EINVAL;
2492
2493 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
2494 page_flip->reserved != 0)
2495 return -EINVAL;
2496
2497 mutex_lock(&dev->mode_config.mutex);
2498 obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
2499 if (!obj)
2500 goto out;
2501 crtc = obj_to_crtc(obj);
2502
2503 if (crtc->funcs->page_flip == NULL)
2504 goto out;
2505
2506 obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB);
2507 if (!obj)
2508 goto out;
2509 fb = obj_to_fb(obj);
2510
2511 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
2512 ret = -ENOMEM;
2513 spin_lock_irqsave(&dev->event_lock, flags);
2514 if (file_priv->event_space < sizeof e->event) {
2515 spin_unlock_irqrestore(&dev->event_lock, flags);
2516 goto out;
2517 }
2518 file_priv->event_space -= sizeof e->event;
2519 spin_unlock_irqrestore(&dev->event_lock, flags);
2520
2521 e = kzalloc(sizeof *e, GFP_KERNEL);
2522 if (e == NULL) {
2523 spin_lock_irqsave(&dev->event_lock, flags);
2524 file_priv->event_space += sizeof e->event;
2525 spin_unlock_irqrestore(&dev->event_lock, flags);
2526 goto out;
2527 }
2528
2529 e->event.base.type = DRM_EVENT_VBLANK;
2530 e->event.base.length = sizeof e->event;
2531 e->event.user_data = page_flip->user_data;
2532 e->base.event = &e->event.base;
2533 e->base.file_priv = file_priv;
2534 e->base.destroy =
2535 (void (*) (struct drm_pending_event *)) kfree;
2536 }
2537
2538 ret = crtc->funcs->page_flip(crtc, fb, e);
2539 if (ret) {
2540 spin_lock_irqsave(&dev->event_lock, flags);
2541 file_priv->event_space += sizeof e->event;
2542 spin_unlock_irqrestore(&dev->event_lock, flags);
2543 kfree(e);
2544 }
2545
2546out:
2547 mutex_unlock(&dev->mode_config.mutex);
2548 return ret;
2549}