Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[deliverable/linux.git] / drivers / media / IR / lirc_dev.c
index 560c35609ca4a8be6b2ad4e7bb8e9e461e98d82c..8418b14ee4d2244ee3b6528549d0d22f35c85159 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/completion.h>
-#include <linux/errno.h>
 #include <linux/mutex.h>
 #include <linux/wait.h>
 #include <linux/unistd.h>
@@ -58,13 +57,12 @@ struct irctl {
 
        struct task_struct *task;
        long jiffies_to_wait;
-
-       struct cdev cdev;
 };
 
 static DEFINE_MUTEX(lirc_dev_lock);
 
 static struct irctl *irctls[MAX_IRCTL_DEVICES];
+static struct cdev cdevs[MAX_IRCTL_DEVICES];
 
 /* Only used for sysfs but defined to void otherwise */
 static struct class *lirc_class;
@@ -74,8 +72,6 @@ static struct class *lirc_class;
  */
 static void lirc_irctl_init(struct irctl *ir)
 {
-       dev_dbg(ir->d.dev, LOGHEAD "initializing irctl\n",
-               ir->d.name, ir->d.minor);
        mutex_init(&ir->irctl_lock);
        ir->d.minor = NOPLUG;
 }
@@ -166,25 +162,27 @@ static struct file_operations lirc_dev_fops = {
 #endif
        .open           = lirc_dev_fop_open,
        .release        = lirc_dev_fop_close,
+       .llseek         = noop_llseek,
 };
 
 static int lirc_cdev_add(struct irctl *ir)
 {
        int retval;
        struct lirc_driver *d = &ir->d;
+       struct cdev *cdev = &cdevs[d->minor];
 
        if (d->fops) {
-               cdev_init(&ir->cdev, d->fops);
-               ir->cdev.owner = d->owner;
+               cdev_init(cdev, d->fops);
+               cdev->owner = d->owner;
        } else {
-               cdev_init(&ir->cdev, &lirc_dev_fops);
-               ir->cdev.owner = THIS_MODULE;
+               cdev_init(cdev, &lirc_dev_fops);
+               cdev->owner = THIS_MODULE;
        }
-       kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor);
+       kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
 
-       retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
+       retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
        if (retval)
-               kobject_put(&ir->cdev.kobj);
+               kobject_put(&cdev->kobj);
 
        return retval;
 }
@@ -205,6 +203,12 @@ int lirc_register_driver(struct lirc_driver *d)
                goto out;
        }
 
+       if (!d->dev) {
+               printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__);
+               err = -EINVAL;
+               goto out;
+       }
+
        if (MAX_IRCTL_DEVICES <= d->minor) {
                dev_err(d->dev, "lirc_dev: lirc_register_driver: "
                        "\"minor\" must be between 0 and %d (%d)!\n",
@@ -319,7 +323,6 @@ int lirc_register_driver(struct lirc_driver *d)
                d->features = LIRC_CAN_REC_LIRCCODE;
 
        ir->d = *d;
-       ir->d.minor = minor;
 
        device_create(lirc_class, ir->d.dev,
                      MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL,
@@ -360,6 +363,7 @@ EXPORT_SYMBOL(lirc_register_driver);
 int lirc_unregister_driver(int minor)
 {
        struct irctl *ir;
+       struct cdev *cdev;
 
        if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
                printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between "
@@ -374,6 +378,8 @@ int lirc_unregister_driver(int minor)
                return -ENOENT;
        }
 
+       cdev = &cdevs[minor];
+
        mutex_lock(&lirc_dev_lock);
 
        if (ir->d.minor != minor) {
@@ -397,12 +403,11 @@ int lirc_unregister_driver(int minor)
                wake_up_interruptible(&ir->buf->wait_poll);
                mutex_lock(&ir->irctl_lock);
                ir->d.set_use_dec(ir->d.data);
-               module_put(ir->d.owner);
+               module_put(cdev->owner);
                mutex_unlock(&ir->irctl_lock);
-               cdev_del(&ir->cdev);
        } else {
                lirc_irctl_cleanup(ir);
-               cdev_del(&ir->cdev);
+               cdev_del(cdev);
                kfree(ir);
                irctls[minor] = NULL;
        }
@@ -416,6 +421,7 @@ EXPORT_SYMBOL(lirc_unregister_driver);
 int lirc_dev_fop_open(struct inode *inode, struct file *file)
 {
        struct irctl *ir;
+       struct cdev *cdev;
        int retval = 0;
 
        if (iminor(inode) >= MAX_IRCTL_DEVICES) {
@@ -432,7 +438,6 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
                retval = -ENODEV;
                goto error;
        }
-       file->private_data = ir;
 
        dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
 
@@ -446,13 +451,14 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
                goto error;
        }
 
-       if (try_module_get(ir->d.owner)) {
-               ++ir->open;
+       cdev = &cdevs[iminor(inode)];
+       if (try_module_get(cdev->owner)) {
+               ir->open++;
                retval = ir->d.set_use_inc(ir->d.data);
 
                if (retval) {
-                       module_put(ir->d.owner);
-                       --ir->open;
+                       module_put(cdev->owner);
+                       ir->open--;
                } else {
                        lirc_buffer_clear(ir->buf);
                }
@@ -467,6 +473,8 @@ error:
 
        mutex_unlock(&lirc_dev_lock);
 
+       nonseekable_open(inode, file);
+
        return retval;
 }
 EXPORT_SYMBOL(lirc_dev_fop_open);
@@ -474,17 +482,24 @@ EXPORT_SYMBOL(lirc_dev_fop_open);
 int lirc_dev_fop_close(struct inode *inode, struct file *file)
 {
        struct irctl *ir = irctls[iminor(inode)];
+       struct cdev *cdev = &cdevs[iminor(inode)];
+
+       if (!ir) {
+               printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+               return -EINVAL;
+       }
 
        dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
 
        WARN_ON(mutex_lock_killable(&lirc_dev_lock));
 
-       --ir->open;
+       ir->open--;
        if (ir->attached) {
                ir->d.set_use_dec(ir->d.data);
-               module_put(ir->d.owner);
+               module_put(cdev->owner);
        } else {
                lirc_irctl_cleanup(ir);
+               cdev_del(cdev);
                irctls[ir->d.minor] = NULL;
                kfree(ir);
        }
@@ -500,6 +515,11 @@ unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
        struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
        unsigned int ret;
 
+       if (!ir) {
+               printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+               return POLLERR;
+       }
+
        dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
 
        if (!ir->attached) {
@@ -528,7 +548,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        __u32 mode;
        int result = 0;
-       struct irctl *ir = file->private_data;
+       struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
 
        if (!ir) {
                printk(KERN_ERR "lirc_dev: %s: no irctl found!\n", __func__);
@@ -614,12 +634,21 @@ ssize_t lirc_dev_fop_read(struct file *file,
                          loff_t *ppos)
 {
        struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
-       unsigned char buf[ir->chunk_size];
+       unsigned char *buf;
        int ret = 0, written = 0;
        DECLARE_WAITQUEUE(wait, current);
 
+       if (!ir) {
+               printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+               return -ENODEV;
+       }
+
        dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
 
+       buf = kzalloc(ir->chunk_size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
        if (mutex_lock_interruptible(&ir->irctl_lock))
                return -ERESTARTSYS;
        if (!ir->attached) {
@@ -691,6 +720,7 @@ ssize_t lirc_dev_fop_read(struct file *file,
        mutex_unlock(&ir->irctl_lock);
 
 out_unlocked:
+       kfree(buf);
        dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
                ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret);
 
@@ -719,6 +749,11 @@ ssize_t lirc_dev_fop_write(struct file *file, const char *buffer,
 {
        struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
 
+       if (!ir) {
+               printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+               return -ENODEV;
+       }
+
        dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor);
 
        if (!ir->attached)
This page took 0.04361 seconds and 5 git commands to generate.