aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_fops.c
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@bitplanet.net>2009-09-11 14:33:34 -0400
committerDave Airlie <airlied@redhat.com>2009-11-17 19:02:47 -0500
commitc9a9c5e02aedc1a2815877b0268f886d2640b771 (patch)
tree51f69f2ec6dcebb019cd6aa22b9e29ee48c397c1 /drivers/gpu/drm/drm_fops.c
parent799dd75b1a8380a967c929a4551895788c374b31 (diff)
drm: Add async event synchronization for drmWaitVblank
This patch adds a new flag to the drmWaitVblank ioctl, which asks the drm to return immediately and notify userspace when the specified vblank sequence happens by sending an event back on the drm fd. The event mechanism works with the other flags supported by the ioctls, specifically, the vblank sequence can be specified relatively or absolutely, and works for primary and seconday crtc. The signal field of the vblank request is used to provide user data, which will be sent back to user space in the vblank event. Signed-off-by: Kristian Høgsberg <krh@redhat.com> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_fops.c')
-rw-r--r--drivers/gpu/drm/drm_fops.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 251bc0e3b5ec..8ac7fbf6b2b7 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -257,6 +257,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
257 257
258 INIT_LIST_HEAD(&priv->lhead); 258 INIT_LIST_HEAD(&priv->lhead);
259 INIT_LIST_HEAD(&priv->fbs); 259 INIT_LIST_HEAD(&priv->fbs);
260 INIT_LIST_HEAD(&priv->event_list);
261 init_waitqueue_head(&priv->event_wait);
262 priv->event_space = 4096; /* set aside 4k for event buffer */
260 263
261 if (dev->driver->driver_features & DRIVER_GEM) 264 if (dev->driver->driver_features & DRIVER_GEM)
262 drm_gem_open(dev, priv); 265 drm_gem_open(dev, priv);
@@ -413,6 +416,30 @@ static void drm_master_release(struct drm_device *dev, struct file *filp)
413 } 416 }
414} 417}
415 418
419static void drm_events_release(struct drm_file *file_priv)
420{
421 struct drm_device *dev = file_priv->minor->dev;
422 struct drm_pending_event *e, *et;
423 struct drm_pending_vblank_event *v, *vt;
424 unsigned long flags;
425
426 spin_lock_irqsave(&dev->event_lock, flags);
427
428 /* Remove pending flips */
429 list_for_each_entry_safe(v, vt, &dev->vblank_event_list, base.link)
430 if (v->base.file_priv == file_priv) {
431 list_del(&v->base.link);
432 drm_vblank_put(dev, v->pipe);
433 v->base.destroy(&v->base);
434 }
435
436 /* Remove unconsumed events */
437 list_for_each_entry_safe(e, et, &file_priv->event_list, link)
438 e->destroy(e);
439
440 spin_unlock_irqrestore(&dev->event_lock, flags);
441}
442
416/** 443/**
417 * Release file. 444 * Release file.
418 * 445 *
@@ -451,6 +478,8 @@ int drm_release(struct inode *inode, struct file *filp)
451 if (file_priv->minor->master) 478 if (file_priv->minor->master)
452 drm_master_release(dev, filp); 479 drm_master_release(dev, filp);
453 480
481 drm_events_release(file_priv);
482
454 if (dev->driver->driver_features & DRIVER_GEM) 483 if (dev->driver->driver_features & DRIVER_GEM)
455 drm_gem_release(dev, file_priv); 484 drm_gem_release(dev, file_priv);
456 485
@@ -544,9 +573,74 @@ int drm_release(struct inode *inode, struct file *filp)
544} 573}
545EXPORT_SYMBOL(drm_release); 574EXPORT_SYMBOL(drm_release);
546 575
547/** No-op. */ 576static bool
577drm_dequeue_event(struct drm_file *file_priv,
578 size_t total, size_t max, struct drm_pending_event **out)
579{
580 struct drm_device *dev = file_priv->minor->dev;
581 struct drm_pending_event *e;
582 unsigned long flags;
583 bool ret = false;
584
585 spin_lock_irqsave(&dev->event_lock, flags);
586
587 *out = NULL;
588 if (list_empty(&file_priv->event_list))
589 goto out;
590 e = list_first_entry(&file_priv->event_list,
591 struct drm_pending_event, link);
592 if (e->event->length + total > max)
593 goto out;
594
595 file_priv->event_space += e->event->length;
596 list_del(&e->link);
597 *out = e;
598 ret = true;
599
600out:
601 spin_unlock_irqrestore(&dev->event_lock, flags);
602 return ret;
603}
604
605ssize_t drm_read(struct file *filp, char __user *buffer,
606 size_t count, loff_t *offset)
607{
608 struct drm_file *file_priv = filp->private_data;
609 struct drm_pending_event *e;
610 size_t total;
611 ssize_t ret;
612
613 ret = wait_event_interruptible(file_priv->event_wait,
614 !list_empty(&file_priv->event_list));
615 if (ret < 0)
616 return ret;
617
618 total = 0;
619 while (drm_dequeue_event(file_priv, total, count, &e)) {
620 if (copy_to_user(buffer + total,
621 e->event, e->event->length)) {
622 total = -EFAULT;
623 break;
624 }
625
626 total += e->event->length;
627 e->destroy(e);
628 }
629
630 return total;
631}
632EXPORT_SYMBOL(drm_read);
633
548unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) 634unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
549{ 635{
550 return 0; 636 struct drm_file *file_priv = filp->private_data;
637 unsigned int mask = 0;
638
639 poll_wait(filp, &file_priv->event_wait, wait);
640
641 if (!list_empty(&file_priv->event_list))
642 mask |= POLLIN | POLLRDNORM;
643
644 return mask;
551} 645}
552EXPORT_SYMBOL(drm_poll); 646EXPORT_SYMBOL(drm_poll);