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.c112
1 files changed, 110 insertions, 2 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 251bc0e3b5ec..08d14df3bb42 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);
@@ -297,6 +300,18 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
297 goto out_free; 300 goto out_free;
298 } 301 }
299 } 302 }
303 mutex_lock(&dev->struct_mutex);
304 if (dev->driver->master_set) {
305 ret = dev->driver->master_set(dev, priv, true);
306 if (ret) {
307 /* drop both references if this fails */
308 drm_master_put(&priv->minor->master);
309 drm_master_put(&priv->master);
310 mutex_unlock(&dev->struct_mutex);
311 goto out_free;
312 }
313 }
314 mutex_unlock(&dev->struct_mutex);
300 } else { 315 } else {
301 /* get a reference to the master */ 316 /* get a reference to the master */
302 priv->master = drm_master_get(priv->minor->master); 317 priv->master = drm_master_get(priv->minor->master);
@@ -413,6 +428,30 @@ static void drm_master_release(struct drm_device *dev, struct file *filp)
413 } 428 }
414} 429}
415 430
431static void drm_events_release(struct drm_file *file_priv)
432{
433 struct drm_device *dev = file_priv->minor->dev;
434 struct drm_pending_event *e, *et;
435 struct drm_pending_vblank_event *v, *vt;
436 unsigned long flags;
437
438 spin_lock_irqsave(&dev->event_lock, flags);
439
440 /* Remove pending flips */
441 list_for_each_entry_safe(v, vt, &dev->vblank_event_list, base.link)
442 if (v->base.file_priv == file_priv) {
443 list_del(&v->base.link);
444 drm_vblank_put(dev, v->pipe);
445 v->base.destroy(&v->base);
446 }
447
448 /* Remove unconsumed events */
449 list_for_each_entry_safe(e, et, &file_priv->event_list, link)
450 e->destroy(e);
451
452 spin_unlock_irqrestore(&dev->event_lock, flags);
453}
454
416/** 455/**
417 * Release file. 456 * Release file.
418 * 457 *
@@ -451,6 +490,8 @@ int drm_release(struct inode *inode, struct file *filp)
451 if (file_priv->minor->master) 490 if (file_priv->minor->master)
452 drm_master_release(dev, filp); 491 drm_master_release(dev, filp);
453 492
493 drm_events_release(file_priv);
494
454 if (dev->driver->driver_features & DRIVER_GEM) 495 if (dev->driver->driver_features & DRIVER_GEM)
455 drm_gem_release(dev, file_priv); 496 drm_gem_release(dev, file_priv);
456 497
@@ -504,6 +545,8 @@ int drm_release(struct inode *inode, struct file *filp)
504 545
505 if (file_priv->minor->master == file_priv->master) { 546 if (file_priv->minor->master == file_priv->master) {
506 /* drop the reference held my the minor */ 547 /* drop the reference held my the minor */
548 if (dev->driver->master_drop)
549 dev->driver->master_drop(dev, file_priv, true);
507 drm_master_put(&file_priv->minor->master); 550 drm_master_put(&file_priv->minor->master);
508 } 551 }
509 } 552 }
@@ -544,9 +587,74 @@ int drm_release(struct inode *inode, struct file *filp)
544} 587}
545EXPORT_SYMBOL(drm_release); 588EXPORT_SYMBOL(drm_release);
546 589
547/** No-op. */ 590static bool
591drm_dequeue_event(struct drm_file *file_priv,
592 size_t total, size_t max, struct drm_pending_event **out)
593{
594 struct drm_device *dev = file_priv->minor->dev;
595 struct drm_pending_event *e;
596 unsigned long flags;
597 bool ret = false;
598
599 spin_lock_irqsave(&dev->event_lock, flags);
600
601 *out = NULL;
602 if (list_empty(&file_priv->event_list))
603 goto out;
604 e = list_first_entry(&file_priv->event_list,
605 struct drm_pending_event, link);
606 if (e->event->length + total > max)
607 goto out;
608
609 file_priv->event_space += e->event->length;
610 list_del(&e->link);
611 *out = e;
612 ret = true;
613
614out:
615 spin_unlock_irqrestore(&dev->event_lock, flags);
616 return ret;
617}
618
619ssize_t drm_read(struct file *filp, char __user *buffer,
620 size_t count, loff_t *offset)
621{
622 struct drm_file *file_priv = filp->private_data;
623 struct drm_pending_event *e;
624 size_t total;
625 ssize_t ret;
626
627 ret = wait_event_interruptible(file_priv->event_wait,
628 !list_empty(&file_priv->event_list));
629 if (ret < 0)
630 return ret;
631
632 total = 0;
633 while (drm_dequeue_event(file_priv, total, count, &e)) {
634 if (copy_to_user(buffer + total,
635 e->event, e->event->length)) {
636 total = -EFAULT;
637 break;
638 }
639
640 total += e->event->length;
641 e->destroy(e);
642 }
643
644 return total;
645}
646EXPORT_SYMBOL(drm_read);
647
548unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) 648unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
549{ 649{
550 return 0; 650 struct drm_file *file_priv = filp->private_data;
651 unsigned int mask = 0;
652
653 poll_wait(filp, &file_priv->event_wait, wait);
654
655 if (!list_empty(&file_priv->event_list))
656 mask |= POLLIN | POLLRDNORM;
657
658 return mask;
551} 659}
552EXPORT_SYMBOL(drm_poll); 660EXPORT_SYMBOL(drm_poll);