diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/gpu/drm/drm_fops.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/gpu/drm/drm_fops.c')
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 129 |
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 | ||
41 | static int drm_open_helper(struct inode *inode, struct file *filp, | 42 | static 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 | } |
142 | out: | 143 | out: |
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 | ||
434 | static 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 | } |
545 | EXPORT_SYMBOL(drm_release); | 591 | EXPORT_SYMBOL(drm_release); |
546 | 592 | ||
547 | /** No-op. */ | 593 | static bool |
594 | drm_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 | |||
617 | out: | ||
618 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
619 | return ret; | ||
620 | } | ||
621 | |||
622 | ssize_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 | } | ||
649 | EXPORT_SYMBOL(drm_read); | ||
650 | |||
548 | unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) | 651 | unsigned 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 | } |
552 | EXPORT_SYMBOL(drm_poll); | 663 | EXPORT_SYMBOL(drm_poll); |