diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 69 |
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 | |||
2482 | int 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 | |||
2546 | out: | ||
2547 | mutex_unlock(&dev->mode_config.mutex); | ||
2548 | return ret; | ||
2549 | } | ||