aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_fops.c
diff options
context:
space:
mode:
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);