staging: comedi: check s->async for poll(), read() and write()
[pandora-kernel.git] / drivers / staging / comedi / comedi_fops.c
index 5e78c77..a023f52 100644 (file)
@@ -136,6 +136,11 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
        /* Device config is special, because it must work on
         * an unconfigured device. */
        if (cmd == COMEDI_DEVCONFIG) {
+               if (minor >= COMEDI_NUM_BOARD_MINORS) {
+                       /* Device config not appropriate on non-board minors. */
+                       rc = -ENOTTY;
+                       goto done;
+               }
                rc = do_devconfig_ioctl(dev,
                                        (struct comedi_devconfig __user *)arg);
                goto done;
@@ -280,7 +285,7 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
        if (ret == 0) {
                if (!try_module_get(dev->driver->module)) {
                        comedi_device_detach(dev);
-                       return -ENOSYS;
+                       ret = -ENOSYS;
                }
        }
 
@@ -843,7 +848,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
                                ret = -EAGAIN;
                                break;
                        }
-                       ret = s->async->inttrig(dev, s, insn->data[0]);
+                       ret = s->async->inttrig(dev, s, data[0]);
                        if (ret >= 0)
                                ret = 1;
                        break;
@@ -1088,7 +1093,6 @@ static int do_cmd_ioctl(struct comedi_device *dev,
                goto cleanup;
        }
 
-       kfree(async->cmd.chanlist);
        async->cmd = user_cmd;
        async->cmd.data = NULL;
        /* load channel/gain list */
@@ -1570,7 +1574,7 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait)
 
        mask = 0;
        read_subdev = comedi_get_read_subdevice(dev_file_info);
-       if (read_subdev) {
+       if (read_subdev && read_subdev->async) {
                poll_wait(file, &read_subdev->async->wait_head, wait);
                if (!read_subdev->busy
                    || comedi_buf_read_n_available(read_subdev->async) > 0
@@ -1580,7 +1584,7 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait)
                }
        }
        write_subdev = comedi_get_write_subdevice(dev_file_info);
-       if (write_subdev) {
+       if (write_subdev && write_subdev->async) {
                poll_wait(file, &write_subdev->async->wait_head, wait);
                comedi_buf_write_alloc(write_subdev->async,
                                       write_subdev->async->prealloc_bufsz);
@@ -1622,7 +1626,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
        }
 
        s = comedi_get_write_subdevice(dev_file_info);
-       if (s == NULL) {
+       if (s == NULL || s->async == NULL) {
                retval = -EIO;
                goto done;
        }
@@ -1733,7 +1737,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
        }
 
        s = comedi_get_read_subdevice(dev_file_info);
-       if (s == NULL) {
+       if (s == NULL || s->async == NULL) {
                retval = -EIO;
                goto done;
        }
@@ -1833,6 +1837,8 @@ void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
        if (async) {
                comedi_reset_async_buf(async);
                async->inttrig = NULL;
+               kfree(async->cmd.chanlist);
+               async->cmd.chanlist = NULL;
        } else {
                printk(KERN_ERR
                       "BUG: (?) do_become_nonbusy called with async=0\n");
@@ -2206,6 +2212,7 @@ int comedi_alloc_board_minor(struct device *hardware_device)
                kfree(info);
                return -ENOMEM;
        }
+       info->hardware_device = hardware_device;
        comedi_device_init(info->device);
        spin_lock_irqsave(&comedi_file_info_table_lock, flags);
        for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
@@ -2294,6 +2301,23 @@ void comedi_free_board_minor(unsigned minor)
        }
 }
 
+int comedi_find_board_minor(struct device *hardware_device)
+{
+       int minor;
+       struct comedi_device_file_info *info;
+
+       for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) {
+               spin_lock(&comedi_file_info_table_lock);
+               info = comedi_file_info_table[minor];
+               if (info && info->hardware_device == hardware_device) {
+                       spin_unlock(&comedi_file_info_table_lock);
+                       return minor;
+               }
+               spin_unlock(&comedi_file_info_table_lock);
+       }
+       return -ENODEV;
+}
+
 int comedi_alloc_subdevice_minor(struct comedi_device *dev,
                                 struct comedi_subdevice *s)
 {