include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / gpu / drm / drm_fops.c
index f228523..0d55552 100644 (file)
@@ -35,8 +35,8 @@
  */
 
 #include "drmP.h"
-#include "drm_sarea.h"
 #include <linux/poll.h>
+#include <linux/slab.h>
 #include <linux/smp_lock.h>
 
 static int drm_open_helper(struct inode *inode, struct file *filp,
@@ -55,10 +55,12 @@ static int drm_setup(struct drm_device * dev)
 
        atomic_set(&dev->ioctl_count, 0);
        atomic_set(&dev->vma_count, 0);
-       dev->buf_use = 0;
-       atomic_set(&dev->buf_alloc, 0);
 
-       if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) {
+       if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
+           !drm_core_check_feature(dev, DRIVER_MODESET)) {
+               dev->buf_use = 0;
+               atomic_set(&dev->buf_alloc, 0);
+
                i = drm_dma_setup(dev);
                if (i < 0)
                        return i;
@@ -133,10 +135,20 @@ int drm_open(struct inode *inode, struct file *filp)
                spin_lock(&dev->count_lock);
                if (!dev->open_count++) {
                        spin_unlock(&dev->count_lock);
-                       return drm_setup(dev);
+                       retcode = drm_setup(dev);
+                       goto out;
                }
                spin_unlock(&dev->count_lock);
        }
+out:
+       mutex_lock(&dev->struct_mutex);
+       if (minor->type == DRM_MINOR_LEGACY) {
+               BUG_ON((dev->dev_mapping != NULL) &&
+                       (dev->dev_mapping != inode->i_mapping));
+               if (dev->dev_mapping == NULL)
+                       dev->dev_mapping = inode->i_mapping;
+       }
+       mutex_unlock(&dev->struct_mutex);
 
        return retcode;
 }
@@ -172,6 +184,10 @@ int drm_stub_open(struct inode *inode, struct file *filp)
 
        old_fops = filp->f_op;
        filp->f_op = fops_get(&dev->driver->fops);
+       if (filp->f_op == NULL) {
+               filp->f_op = old_fops;
+               goto out;
+       }
        if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) {
                fops_put(filp->f_op);
                filp->f_op = fops_get(old_fops);
@@ -225,7 +241,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
 
        DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id);
 
-       priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
+       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
@@ -241,6 +257,10 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
        priv->lock_count = 0;
 
        INIT_LIST_HEAD(&priv->lhead);
+       INIT_LIST_HEAD(&priv->fbs);
+       INIT_LIST_HEAD(&priv->event_list);
+       init_waitqueue_head(&priv->event_wait);
+       priv->event_space = 4096; /* set aside 4k for event buffer */
 
        if (dev->driver->driver_features & DRIVER_GEM)
                drm_gem_open(dev, priv);
@@ -258,6 +278,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
                /* create a new master */
                priv->minor->master = drm_master_create(priv->minor);
                if (!priv->minor->master) {
+                       mutex_unlock(&dev->struct_mutex);
                        ret = -ENOMEM;
                        goto out_free;
                }
@@ -280,6 +301,18 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
                                goto out_free;
                        }
                }
+               mutex_lock(&dev->struct_mutex);
+               if (dev->driver->master_set) {
+                       ret = dev->driver->master_set(dev, priv, true);
+                       if (ret) {
+                               /* drop both references if this fails */
+                               drm_master_put(&priv->minor->master);
+                               drm_master_put(&priv->master);
+                               mutex_unlock(&dev->struct_mutex);
+                               goto out_free;
+                       }
+               }
+               mutex_unlock(&dev->struct_mutex);
        } else {
                /* get a reference to the master */
                priv->master = drm_master_get(priv->minor->master);
@@ -311,7 +344,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
 
        return 0;
       out_free:
-       drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+       kfree(priv);
        filp->private_data = NULL;
        return ret;
 }
@@ -321,14 +354,10 @@ int drm_fasync(int fd, struct file *filp, int on)
 {
        struct drm_file *priv = filp->private_data;
        struct drm_device *dev = priv->minor->dev;
-       int retcode;
 
        DRM_DEBUG("fd = %d, device = 0x%lx\n", fd,
                  (long)old_encode_dev(priv->minor->device));
-       retcode = fasync_helper(fd, filp, on, &dev->buf_async);
-       if (retcode < 0)
-               return retcode;
-       return 0;
+       return fasync_helper(fd, filp, on, &dev->buf_async);
 }
 EXPORT_SYMBOL(drm_fasync);
 
@@ -400,6 +429,30 @@ static void drm_master_release(struct drm_device *dev, struct file *filp)
        }
 }
 
+static void drm_events_release(struct drm_file *file_priv)
+{
+       struct drm_device *dev = file_priv->minor->dev;
+       struct drm_pending_event *e, *et;
+       struct drm_pending_vblank_event *v, *vt;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+
+       /* Remove pending flips */
+       list_for_each_entry_safe(v, vt, &dev->vblank_event_list, base.link)
+               if (v->base.file_priv == file_priv) {
+                       list_del(&v->base.link);
+                       drm_vblank_put(dev, v->pipe);
+                       v->base.destroy(&v->base);
+               }
+
+       /* Remove unconsumed events */
+       list_for_each_entry_safe(e, et, &file_priv->event_list, link)
+               e->destroy(e);
+
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
 /**
  * Release file.
  *
@@ -438,9 +491,14 @@ int drm_release(struct inode *inode, struct file *filp)
        if (file_priv->minor->master)
                drm_master_release(dev, filp);
 
+       drm_events_release(file_priv);
+
        if (dev->driver->driver_features & DRIVER_GEM)
                drm_gem_release(dev, file_priv);
 
+       if (dev->driver->driver_features & DRIVER_MODESET)
+               drm_fb_release(file_priv);
+
        mutex_lock(&dev->ctxlist_mutex);
        if (!list_empty(&dev->ctxlist)) {
                struct drm_ctx_list *pos, *n;
@@ -455,7 +513,7 @@ int drm_release(struct inode *inode, struct file *filp)
                                drm_ctxbitmap_free(dev, pos->handle);
 
                                list_del(&pos->head);
-                               drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST);
+                               kfree(pos);
                                --dev->ctx_count;
                        }
                }
@@ -465,6 +523,7 @@ int drm_release(struct inode *inode, struct file *filp)
        mutex_lock(&dev->struct_mutex);
 
        if (file_priv->is_master) {
+               struct drm_master *master = file_priv->master;
                struct drm_file *temp;
                list_for_each_entry(temp, &dev->filelist, lhead) {
                        if ((temp->master == file_priv->master) &&
@@ -472,8 +531,23 @@ int drm_release(struct inode *inode, struct file *filp)
                                temp->authenticated = 0;
                }
 
+               /**
+                * Since the master is disappearing, so is the
+                * possibility to lock.
+                */
+
+               if (master->lock.hw_lock) {
+                       if (dev->sigdata.lock == master->lock.hw_lock)
+                               dev->sigdata.lock = NULL;
+                       master->lock.hw_lock = NULL;
+                       master->lock.file_priv = NULL;
+                       wake_up_interruptible_all(&master->lock.lock_queue);
+               }
+
                if (file_priv->minor->master == file_priv->master) {
                        /* drop the reference held my the minor */
+                       if (dev->driver->master_drop)
+                               dev->driver->master_drop(dev, file_priv, true);
                        drm_master_put(&file_priv->minor->master);
                }
        }
@@ -486,7 +560,7 @@ int drm_release(struct inode *inode, struct file *filp)
 
        if (dev->driver->postclose)
                dev->driver->postclose(dev, file_priv);
-       drm_free(file_priv, sizeof(*file_priv), DRM_MEM_FILES);
+       kfree(file_priv);
 
        /* ========================================================
         * End inline drm_release
@@ -514,9 +588,74 @@ int drm_release(struct inode *inode, struct file *filp)
 }
 EXPORT_SYMBOL(drm_release);
 
-/** No-op. */
+static bool
+drm_dequeue_event(struct drm_file *file_priv,
+                 size_t total, size_t max, struct drm_pending_event **out)
+{
+       struct drm_device *dev = file_priv->minor->dev;
+       struct drm_pending_event *e;
+       unsigned long flags;
+       bool ret = false;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+
+       *out = NULL;
+       if (list_empty(&file_priv->event_list))
+               goto out;
+       e = list_first_entry(&file_priv->event_list,
+                            struct drm_pending_event, link);
+       if (e->event->length + total > max)
+               goto out;
+
+       file_priv->event_space += e->event->length;
+       list_del(&e->link);
+       *out = e;
+       ret = true;
+
+out:
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+       return ret;
+}
+
+ssize_t drm_read(struct file *filp, char __user *buffer,
+                size_t count, loff_t *offset)
+{
+       struct drm_file *file_priv = filp->private_data;
+       struct drm_pending_event *e;
+       size_t total;
+       ssize_t ret;
+
+       ret = wait_event_interruptible(file_priv->event_wait,
+                                      !list_empty(&file_priv->event_list));
+       if (ret < 0)
+               return ret;
+
+       total = 0;
+       while (drm_dequeue_event(file_priv, total, count, &e)) {
+               if (copy_to_user(buffer + total,
+                                e->event, e->event->length)) {
+                       total = -EFAULT;
+                       break;
+               }
+
+               total += e->event->length;
+               e->destroy(e);
+       }
+
+       return total;
+}
+EXPORT_SYMBOL(drm_read);
+
 unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
 {
-       return 0;
+       struct drm_file *file_priv = filp->private_data;
+       unsigned int mask = 0;
+
+       poll_wait(filp, &file_priv->event_wait, wait);
+
+       if (!list_empty(&file_priv->event_list))
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
 }
 EXPORT_SYMBOL(drm_poll);