diff options
author | Eric Anholt <eric@anholt.net> | 2009-12-01 12:01:54 -0500 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-12-01 12:01:54 -0500 |
commit | f40d6817a5c2bf84f5fe7b5d1a83f1e8f8669951 (patch) | |
tree | 1c515a34a60f65cbfd3cf1a387427d0a9fdf878f /drivers/gpu/drm/drm_crtc.c | |
parent | 103a196f4224dc6872081305cf7f82ebf67aa7bd (diff) | |
parent | 46557bef3f3834ac33031c7be27d39d90d507442 (diff) |
Merge remote branch 'airlied/drm-next' into drm-intel-next
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 ee0cde1ecca5..ac2fa193072b 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -2479,3 +2479,72 @@ out: | |||
2479 | mutex_unlock(&dev->mode_config.mutex); | 2479 | mutex_unlock(&dev->mode_config.mutex); |
2480 | return ret; | 2480 | return ret; |
2481 | } | 2481 | } |
2482 | |||
2483 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
2484 | void *data, struct drm_file *file_priv) | ||
2485 | { | ||
2486 | struct drm_mode_crtc_page_flip *page_flip = data; | ||
2487 | struct drm_mode_object *obj; | ||
2488 | struct drm_crtc *crtc; | ||
2489 | struct drm_framebuffer *fb; | ||
2490 | struct drm_pending_vblank_event *e = NULL; | ||
2491 | unsigned long flags; | ||
2492 | int ret = -EINVAL; | ||
2493 | |||
2494 | if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || | ||
2495 | page_flip->reserved != 0) | ||
2496 | return -EINVAL; | ||
2497 | |||
2498 | mutex_lock(&dev->mode_config.mutex); | ||
2499 | obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); | ||
2500 | if (!obj) | ||
2501 | goto out; | ||
2502 | crtc = obj_to_crtc(obj); | ||
2503 | |||
2504 | if (crtc->funcs->page_flip == NULL) | ||
2505 | goto out; | ||
2506 | |||
2507 | obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB); | ||
2508 | if (!obj) | ||
2509 | goto out; | ||
2510 | fb = obj_to_fb(obj); | ||
2511 | |||
2512 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { | ||
2513 | ret = -ENOMEM; | ||
2514 | spin_lock_irqsave(&dev->event_lock, flags); | ||
2515 | if (file_priv->event_space < sizeof e->event) { | ||
2516 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2517 | goto out; | ||
2518 | } | ||
2519 | file_priv->event_space -= sizeof e->event; | ||
2520 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2521 | |||
2522 | e = kzalloc(sizeof *e, GFP_KERNEL); | ||
2523 | if (e == NULL) { | ||
2524 | spin_lock_irqsave(&dev->event_lock, flags); | ||
2525 | file_priv->event_space += sizeof e->event; | ||
2526 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2527 | goto out; | ||
2528 | } | ||
2529 | |||
2530 | e->event.base.type = DRM_EVENT_VBLANK; | ||
2531 | e->event.base.length = sizeof e->event; | ||
2532 | e->event.user_data = page_flip->user_data; | ||
2533 | e->base.event = &e->event.base; | ||
2534 | e->base.file_priv = file_priv; | ||
2535 | e->base.destroy = | ||
2536 | (void (*) (struct drm_pending_event *)) kfree; | ||
2537 | } | ||
2538 | |||
2539 | ret = crtc->funcs->page_flip(crtc, fb, e); | ||
2540 | if (ret) { | ||
2541 | spin_lock_irqsave(&dev->event_lock, flags); | ||
2542 | file_priv->event_space += sizeof e->event; | ||
2543 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2544 | kfree(e); | ||
2545 | } | ||
2546 | |||
2547 | out: | ||
2548 | mutex_unlock(&dev->mode_config.mutex); | ||
2549 | return ret; | ||
2550 | } | ||