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.c129
1 files changed, 120 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 251bc0e3b5ec..9d532d7fdf59 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -36,6 +36,7 @@
36 36
37#include "drmP.h" 37#include "drmP.h"
38#include <linux/poll.h> 38#include <linux/poll.h>
39#include <linux/slab.h>
39#include <linux/smp_lock.h> 40#include <linux/smp_lock.h>
40 41
41static int drm_open_helper(struct inode *inode, struct file *filp, 42static int drm_open_helper(struct inode *inode, struct file *filp,
@@ -140,14 +141,16 @@ int drm_open(struct inode *inode, struct file *filp)
140 spin_unlock(&dev->count_lock); 141 spin_unlock(&dev->count_lock);
141 } 142 }
142out: 143out:
143 mutex_lock(&dev->struct_mutex); 144 if (!retcode) {
144 if (minor->type == DRM_MINOR_LEGACY) { 145 mutex_lock(&dev->struct_mutex);
145 BUG_ON((dev->dev_mapping != NULL) && 146 if (minor->type == DRM_MINOR_LEGACY) {
146 (dev->dev_mapping != inode->i_mapping)); 147 if (dev->dev_mapping == NULL)
147 if (dev->dev_mapping == NULL) 148 dev->dev_mapping = inode->i_mapping;
148 dev->dev_mapping = inode->i_mapping; 149 else if (dev->dev_mapping != inode->i_mapping)
150 retcode = -ENODEV;
151 }
152 mutex_unlock(&dev->struct_mutex);
149 } 153 }
150 mutex_unlock(&dev->struct_mutex);
151 154
152 return retcode; 155 return retcode;
153} 156}
@@ -257,6 +260,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
257 260
258 INIT_LIST_HEAD(&priv->lhead); 261 INIT_LIST_HEAD(&priv->lhead);
259 INIT_LIST_HEAD(&priv->fbs); 262 INIT_LIST_HEAD(&priv->fbs);
263 INIT_LIST_HEAD(&priv->event_list);
264 init_waitqueue_head(&priv->event_wait);
265 priv->event_space = 4096; /* set aside 4k for event buffer */
260 266
261 if (dev->driver->driver_features & DRIVER_GEM) 267 if (dev->driver->driver_features & DRIVER_GEM)
262 drm_gem_open(dev, priv); 268 drm_gem_open(dev, priv);
@@ -297,6 +303,18 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
297 goto out_free; 303 goto out_free;
298 } 304 }
299 } 305 }
306 mutex_lock(&dev->struct_mutex);
307 if (dev->driver->master_set) {
308 ret = dev->driver->master_set(dev, priv, true);
309 if (ret) {
310 /* drop both references if this fails */
311 drm_master_put(&priv->minor->master);
312 drm_master_put(&priv->master);
313 mutex_unlock(&dev->struct_mutex);
314 goto out_free;
315 }
316 }
317 mutex_unlock(&dev->struct_mutex);
300 } else { 318 } else {
301 /* get a reference to the master */ 319 /* get a reference to the master */
302 priv->master = drm_master_get(priv->minor->master); 320 priv->master = drm_master_get(priv->minor->master);
@@ -413,6 +431,30 @@ static void drm_master_release(struct drm_device *dev, struct file *filp)
413 } 431 }
414} 432}
415 433
434static void drm_events_release(struct drm_file *file_priv)
435{
436 struct drm_device *dev = file_priv->minor->dev;
437 struct drm_pending_event *e, *et;
438 struct drm_pending_vblank_event *v, *vt;
439 unsigned long flags;
440
441 spin_lock_irqsave(&dev->event_lock, flags);
442
443 /* Remove pending flips */
444 list_for_each_entry_safe(v, vt, &dev->vblank_event_list, base.link)
445 if (v->base.file_priv == file_priv) {
446 list_del(&v->base.link);
447 drm_vblank_put(dev, v->pipe);
448 v->base.destroy(&v->base);
449 }
450
451 /* Remove unconsumed events */
452 list_for_each_entry_safe(e, et, &file_priv->event_list, link)
453 e->destroy(e);
454
455 spin_unlock_irqrestore(&dev->event_lock, flags);
456}
457
416/** 458/**
417 * Release file. 459 * Release file.
418 * 460 *
@@ -451,6 +493,8 @@ int drm_release(struct inode *inode, struct file *filp)
451 if (file_priv->minor->master) 493 if (file_priv->minor->master)
452 drm_master_release(dev, filp); 494 drm_master_release(dev, filp);
453 495
496 drm_events_release(file_priv);
497
454 if (dev->driver->driver_features & DRIVER_GEM) 498 if (dev->driver->driver_features & DRIVER_GEM)
455 drm_gem_release(dev, file_priv); 499 drm_gem_release(dev, file_priv);
456 500
@@ -504,6 +548,8 @@ int drm_release(struct inode *inode, struct file *filp)
504 548
505 if (file_priv->minor->master == file_priv->master) { 549 if (file_priv->minor->master == file_priv->master) {
506 /* drop the reference held my the minor */ 550 /* drop the reference held my the minor */
551 if (dev->driver->master_drop)
552 dev->driver->master_drop(dev, file_priv, true);
507 drm_master_put(&file_priv->minor->master); 553 drm_master_put(&file_priv->minor->master);
508 } 554 }
509 } 555 }
@@ -544,9 +590,74 @@ int drm_release(struct inode *inode, struct file *filp)
544} 590}
545EXPORT_SYMBOL(drm_release); 591EXPORT_SYMBOL(drm_release);
546 592
547/** No-op. */ 593static bool
594drm_dequeue_event(struct drm_file *file_priv,
595 size_t total, size_t max, struct drm_pending_event **out)
596{
597 struct drm_device *dev = file_priv->minor->dev;
598 struct drm_pending_event *e;
599 unsigned long flags;
600 bool ret = false;
601
602 spin_lock_irqsave(&dev->event_lock, flags);
603
604 *out = NULL;
605 if (list_empty(&file_priv->event_list))
606 goto out;
607 e = list_first_entry(&file_priv->event_list,
608 struct drm_pending_event, link);
609 if (e->event->length + total > max)
610 goto out;
611
612 file_priv->event_space += e->event->length;
613 list_del(&e->link);
614 *out = e;
615 ret = true;
616
617out:
618 spin_unlock_irqrestore(&dev->event_lock, flags);
619 return ret;
620}
621
622ssize_t drm_read(struct file *filp, char __user *buffer,
623 size_t count, loff_t *offset)
624{
625 struct drm_file *file_priv = filp->private_data;
626 struct drm_pending_event *e;
627 size_t total;
628 ssize_t ret;
629
630 ret = wait_event_interruptible(file_priv->event_wait,
631 !list_empty(&file_priv->event_list));
632 if (ret < 0)
633 return ret;
634
635 total = 0;
636 while (drm_dequeue_event(file_priv, total, count, &e)) {
637 if (copy_to_user(buffer + total,
638 e->event, e->event->length)) {
639 total = -EFAULT;
640 break;
641 }
642
643 total += e->event->length;
644 e->destroy(e);
645 }
646
647 return total;
648}
649EXPORT_SYMBOL(drm_read);
650
548unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) 651unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
549{ 652{
550 return 0; 653 struct drm_file *file_priv = filp->private_data;
654 unsigned int mask = 0;
655
656 poll_wait(filp, &file_priv->event_wait, wait);
657
658 if (!list_empty(&file_priv->event_list))
659 mask |= POLLIN | POLLRDNORM;
660
661 return mask;
551} 662}
552EXPORT_SYMBOL(drm_poll); 663EXPORT_SYMBOL(drm_poll);