These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / comedi / comedi_fops.c
index e78ddbe..7b4af51 100644 (file)
 
 #include "comedi_internal.h"
 
+/*
+ * comedi_subdevice "runflags"
+ * COMEDI_SRF_RT:              DEPRECATED: command is running real-time
+ * COMEDI_SRF_ERROR:           indicates an COMEDI_CB_ERROR event has occurred
+ *                             since the last command was started
+ * COMEDI_SRF_RUNNING:         command is running
+ * COMEDI_SRF_FREE_SPRIV:      free s->private on detach
+ *
+ * COMEDI_SRF_BUSY_MASK:       runflags that indicate the subdevice is "busy"
+ */
+#define COMEDI_SRF_RT          BIT(1)
+#define COMEDI_SRF_ERROR       BIT(2)
+#define COMEDI_SRF_RUNNING     BIT(27)
+#define COMEDI_SRF_FREE_SPRIV  BIT(31)
+
+#define COMEDI_SRF_BUSY_MASK   (COMEDI_SRF_ERROR | COMEDI_SRF_RUNNING)
+
 /**
- * struct comedi_file - per-file private data for comedi device
- * @dev: comedi_device struct
- * @read_subdev: current "read" subdevice
- * @write_subdev: current "write" subdevice
- * @last_detach_count: last known detach count
- * @last_attached: last known attached/detached state
+ * struct comedi_file - Per-file private data for COMEDI device
+ * @dev: COMEDI device.
+ * @read_subdev: Current "read" subdevice.
+ * @write_subdev: Current "write" subdevice.
+ * @last_detach_count: Last known detach count.
+ * @last_attached: Last known attached/detached state.
  */
 struct comedi_file {
        struct comedi_device *dev;
@@ -114,15 +131,15 @@ static void comedi_dev_kref_release(struct kref *kref)
 }
 
 /**
- * comedi_dev_put - release a use of a comedi device structure
- * @dev: comedi_device struct
+ * comedi_dev_put() - Release a use of a COMEDI device
+ * @dev: COMEDI device.
  *
- * Must be called when a user of a comedi device is finished with it.
- * When the last user of the comedi device calls this function, the
- * comedi device is destroyed.
+ * Must be called when a user of a COMEDI device is finished with it.
+ * When the last user of the COMEDI device calls this function, the
+ * COMEDI device is destroyed.
  *
- * Return 1 if the comedi device is destroyed by this call or dev is
- * NULL, otherwise return 0.  Callers must not assume the comedi
+ * Return: 1 if the COMEDI device is destroyed by this call or @dev is
+ * NULL, otherwise return 0.  Callers must not assume the COMEDI
  * device is still valid if this function returns 0.
  */
 int comedi_dev_put(struct comedi_device *dev)
@@ -198,7 +215,6 @@ static struct comedi_subdevice
        struct comedi_subdevice *s;
        unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
 
-       BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS);
        mutex_lock(&comedi_subdevice_minor_table_lock);
        s = comedi_subdevice_minor_table[i];
        if (s && s->device != dev)
@@ -211,7 +227,6 @@ static struct comedi_device *comedi_dev_get_from_board_minor(unsigned minor)
 {
        struct comedi_device *dev;
 
-       BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
        mutex_lock(&comedi_board_minor_table_lock);
        dev = comedi_dev_get(comedi_board_minor_table[minor]);
        mutex_unlock(&comedi_board_minor_table_lock);
@@ -224,7 +239,6 @@ static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor)
        struct comedi_subdevice *s;
        unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
 
-       BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS);
        mutex_lock(&comedi_subdevice_minor_table_lock);
        s = comedi_subdevice_minor_table[i];
        dev = comedi_dev_get(s ? s->device : NULL);
@@ -233,15 +247,15 @@ static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor)
 }
 
 /**
- * comedi_dev_get_from_minor - get comedi device by minor device number
- * @minor: minor device number
+ * comedi_dev_get_from_minor() - Get COMEDI device by minor device number
+ * @minor: Minor device number.
  *
- * Finds the comedi device associated by the minor device number, if any,
- * and increments its reference count.  The comedi device is prevented from
+ * Finds the COMEDI device associated with the minor device number, if any,
+ * and increments its reference count.  The COMEDI device is prevented from
  * being freed until a matching call is made to comedi_dev_put().
  *
- * Return a pointer to the comedi device if it exists, with its usage
- * reference incremented.  Return NULL if no comedi device exists with the
+ * Return: A pointer to the COMEDI device if it exists, with its usage
+ * reference incremented.  Return NULL if no COMEDI device exists with the
  * specified minor device number.
  */
 struct comedi_device *comedi_dev_get_from_minor(unsigned minor)
@@ -651,11 +665,11 @@ static bool comedi_is_runflags_in_error(unsigned runflags)
 }
 
 /**
- * comedi_is_subdevice_running - check if async command running on subdevice
- * @s: comedi_subdevice struct
+ * comedi_is_subdevice_running() - Check if async command running on subdevice
+ * @s: COMEDI subdevice.
  *
- * Return true if an asynchronous comedi command is active on the comedi
- * subdevice, else return false.
+ * Return: %true if an asynchronous COMEDI command is active on the
+ * subdevice, else %false.
  */
 bool comedi_is_subdevice_running(struct comedi_subdevice *s)
 {
@@ -679,19 +693,44 @@ static bool comedi_is_subdevice_idle(struct comedi_subdevice *s)
        return !(runflags & COMEDI_SRF_BUSY_MASK);
 }
 
+bool comedi_can_auto_free_spriv(struct comedi_subdevice *s)
+{
+       unsigned runflags = __comedi_get_subdevice_runflags(s);
+
+       return runflags & COMEDI_SRF_FREE_SPRIV;
+}
+
+/**
+ * comedi_set_spriv_auto_free() - Mark subdevice private data as freeable
+ * @s: COMEDI subdevice.
+ *
+ * Mark the subdevice as having a pointer to private data that can be
+ * automatically freed when the COMEDI device is detached from the low-level
+ * driver.
+ */
+void comedi_set_spriv_auto_free(struct comedi_subdevice *s)
+{
+       __comedi_set_subdevice_runflags(s, COMEDI_SRF_FREE_SPRIV);
+}
+EXPORT_SYMBOL_GPL(comedi_set_spriv_auto_free);
+
 /**
- * comedi_alloc_spriv() - Allocate memory for the subdevice private data.
- * @s: comedi_subdevice struct
- * @size: size of the memory to allocate
+ * comedi_alloc_spriv - Allocate memory for the subdevice private data
+ * @s: COMEDI subdevice.
+ * @size: Size of the memory to allocate.
+ *
+ * Allocate memory for the subdevice private data and point @s->private
+ * to it.  The memory will be freed automatically when the COMEDI device
+ * is detached from the low-level driver.
  *
- * This also sets the subdevice runflags to allow the core to automatically
- * free the private data during the detach.
+ * Return: A pointer to the allocated memory @s->private on success.
+ * Return NULL on failure.
  */
 void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size)
 {
        s->private = kzalloc(size, GFP_KERNEL);
        if (s->private)
-               s->runflags |= COMEDI_SRF_FREE_SPRIV;
+               comedi_set_spriv_auto_free(s);
        return s->private;
 }
 EXPORT_SYMBOL_GPL(comedi_alloc_spriv);
@@ -1048,11 +1087,6 @@ static int do_chaninfo_ioctl(struct comedi_device *dev,
                        if (put_user(x, it.rangelist + i))
                                return -EFAULT;
                }
-#if 0
-               if (copy_to_user(it.rangelist, s->range_type_list,
-                                s->n_chan * sizeof(unsigned int)))
-                       return -EFAULT;
-#endif
        }
 
        return 0;
@@ -1112,7 +1146,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
                comedi_buf_read_free(s, bi.bytes_read);
 
                if (comedi_is_subdevice_idle(s) &&
-                   comedi_buf_n_bytes_ready(s) == 0) {
+                   comedi_buf_read_n_available(s) == 0) {
                        do_become_nonbusy(dev, s);
                }
        }
@@ -1307,7 +1341,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
                        goto out;
                }
                /* This looks arbitrary.  It is. */
-               s->busy = &parse_insn;
+               s->busy = parse_insn;
                switch (insn->insn) {
                case INSN_READ:
                        ret = s->insn_read(dev, s, insn, data);
@@ -1725,7 +1759,7 @@ cleanup:
 
 /*
  * COMEDI_CMDTEST ioctl
- * asynchronous aquisition command testing
+ * asynchronous acquisition command testing
  *
  * arg:
  *     pointer to comedi_cmd structure
@@ -2127,7 +2161,7 @@ static void comedi_vm_close(struct vm_area_struct *area)
        comedi_buf_map_put(bm);
 }
 
-static struct vm_operations_struct comedi_vm_ops = {
+static const struct vm_operations_struct comedi_vm_ops = {
        .open = comedi_vm_open,
        .close = comedi_vm_close,
 };
@@ -2228,9 +2262,9 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
        unsigned int mask = 0;
        struct comedi_file *cfp = file->private_data;
        struct comedi_device *dev = cfp->dev;
-       struct comedi_subdevice *s;
+       struct comedi_subdevice *s, *s_read;
 
-       mutex_lock(&dev->mutex);
+       down_read(&dev->attach_lock);
 
        if (!dev->attached) {
                dev_dbg(dev->class_dev, "no driver attached\n");
@@ -2238,9 +2272,10 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
        }
 
        s = comedi_file_read_subdevice(file);
+       s_read = s;
        if (s && s->async) {
                poll_wait(file, &s->async->wait_head, wait);
-               if (!s->busy || !comedi_is_subdevice_running(s) ||
+               if (s->busy != file || !comedi_is_subdevice_running(s) ||
                    (s->async->cmd.flags & CMDF_WRITE) ||
                    comedi_buf_read_n_available(s) > 0)
                        mask |= POLLIN | POLLRDNORM;
@@ -2250,16 +2285,16 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
        if (s && s->async) {
                unsigned int bps = comedi_bytes_per_sample(s);
 
-               poll_wait(file, &s->async->wait_head, wait);
-               comedi_buf_write_alloc(s, s->async->prealloc_bufsz);
-               if (!s->busy || !comedi_is_subdevice_running(s) ||
+               if (s != s_read)
+                       poll_wait(file, &s->async->wait_head, wait);
+               if (s->busy != file || !comedi_is_subdevice_running(s) ||
                    !(s->async->cmd.flags & CMDF_WRITE) ||
-                   comedi_buf_write_n_allocated(s) >= bps)
+                   comedi_buf_write_n_available(s) >= bps)
                        mask |= POLLOUT | POLLWRNORM;
        }
 
 done:
-       mutex_unlock(&dev->mutex);
+       up_read(&dev->attach_lock);
        return mask;
 }
 
@@ -2415,7 +2450,9 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
 {
        struct comedi_subdevice *s;
        struct comedi_async *async;
-       int n, m, count = 0, retval = 0;
+       unsigned int n, m;
+       ssize_t count = 0;
+       int retval = 0;
        DECLARE_WAITQUEUE(wait, current);
        struct comedi_file *cfp = file->private_data;
        struct comedi_device *dev = cfp->dev;
@@ -2441,28 +2478,19 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
        }
 
        async = s->async;
-       if (!s->busy || !nbytes)
-               goto out;
-       if (s->busy != file) {
-               retval = -EACCES;
-               goto out;
-       }
-       if (async->cmd.flags & CMDF_WRITE) {
+       if (s->busy != file || (async->cmd.flags & CMDF_WRITE)) {
                retval = -EINVAL;
                goto out;
        }
 
        add_wait_queue(&async->wait_head, &wait);
-       while (nbytes > 0 && !retval) {
-               set_current_state(TASK_INTERRUPTIBLE);
+       while (count == 0 && !retval) {
+               unsigned int rp, n1, n2;
 
-               n = nbytes;
+               set_current_state(TASK_INTERRUPTIBLE);
 
                m = comedi_buf_read_n_available(s);
-               if (async->buf_read_ptr + m > async->prealloc_bufsz)
-                       m = async->prealloc_bufsz - async->buf_read_ptr;
-               if (m < n)
-                       n = m;
+               n = min_t(size_t, m, nbytes);
 
                if (n == 0) {
                        unsigned runflags = comedi_get_subdevice_runflags(s);
@@ -2470,11 +2498,12 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
                        if (!comedi_is_runflags_running(runflags)) {
                                if (comedi_is_runflags_in_error(runflags))
                                        retval = -EPIPE;
-                               else
-                                       retval = 0;
-                               become_nonbusy = true;
+                               if (retval || nbytes)
+                                       become_nonbusy = true;
                                break;
                        }
+                       if (nbytes == 0)
+                               break;
                        if (file->f_flags & O_NONBLOCK) {
                                retval = -EAGAIN;
                                break;
@@ -2484,22 +2513,21 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
                                retval = -ERESTARTSYS;
                                break;
                        }
-                       if (!s->busy) {
-                               retval = 0;
-                               break;
-                       }
-                       if (s->busy != file) {
-                               retval = -EACCES;
-                               break;
-                       }
-                       if (async->cmd.flags & CMDF_WRITE) {
+                       if (s->busy != file ||
+                           (async->cmd.flags & CMDF_WRITE)) {
                                retval = -EINVAL;
                                break;
                        }
                        continue;
                }
-               m = copy_to_user(buf, async->prealloc_buf +
-                                async->buf_read_ptr, n);
+               rp = async->buf_read_ptr;
+               n1 = min(n, async->prealloc_bufsz - rp);
+               n2 = n - n1;
+               m = copy_to_user(buf, async->prealloc_buf + rp, n1);
+               if (m)
+                       m += n2;
+               else if (n2)
+                       m = copy_to_user(buf + n1, async->prealloc_buf, n2);
                if (m) {
                        n -= m;
                        retval = -EFAULT;
@@ -2512,11 +2540,10 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
                nbytes -= n;
 
                buf += n;
-               break;          /* makes device work like a pipe */
        }
        remove_wait_queue(&async->wait_head, &wait);
        set_current_state(TASK_RUNNING);
-       if (become_nonbusy || comedi_is_subdevice_idle(s)) {
+       if (become_nonbusy && count == 0) {
                struct comedi_subdevice *new_s;
 
                /*
@@ -2532,13 +2559,17 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
                 * sufficient (unless there have been 2**32 detaches in the
                 * meantime!), but check the subdevice pointer as well just in
                 * case.
+                *
+                * Also check the subdevice is still in a suitable state to
+                * become non-busy in case it changed behind our back.
                 */
                new_s = comedi_file_read_subdevice(file);
                if (dev->attached && old_detach_count == dev->detach_count &&
-                   s == new_s && new_s->async == async) {
-                       if (become_nonbusy || comedi_buf_n_bytes_ready(s) == 0)
-                               do_become_nonbusy(dev, s);
-               }
+                   s == new_s && new_s->async == async && s->busy == file &&
+                   !(async->cmd.flags & CMDF_WRITE) &&
+                   !comedi_is_subdevice_running(s) &&
+                   comedi_buf_read_n_available(s) == 0)
+                       do_become_nonbusy(dev, s);
                mutex_unlock(&dev->mutex);
        }
 out:
@@ -2567,14 +2598,14 @@ static int comedi_open(struct inode *inode, struct file *file)
        cfp->dev = dev;
 
        mutex_lock(&dev->mutex);
-       if (!dev->attached && !capable(CAP_NET_ADMIN)) {
-               dev_dbg(dev->class_dev, "not attached and not CAP_NET_ADMIN\n");
+       if (!dev->attached && !capable(CAP_SYS_ADMIN)) {
+               dev_dbg(dev->class_dev, "not attached and not CAP_SYS_ADMIN\n");
                rc = -ENODEV;
                goto out;
        }
        if (dev->attached && dev->use_count == 0) {
                if (!try_module_get(dev->driver->module)) {
-                       rc = -ENOSYS;
+                       rc = -ENXIO;
                        goto out;
                }
                if (dev->open) {
@@ -2657,15 +2688,15 @@ static const struct file_operations comedi_fops = {
 };
 
 /**
- * comedi_event - handle events for asynchronous comedi command
- * @dev: comedi_device struct
- * @s: comedi_subdevice struct associated with dev
- * Context: interrupt (usually), s->spin_lock spin-lock not held
+ * comedi_event() - Handle events for asynchronous COMEDI command
+ * @dev: COMEDI device.
+ * @s: COMEDI subdevice.
+ * Context: in_interrupt() (usually), @s->spin_lock spin-lock not held.
  *
- * If an asynchronous comedi command is active on the subdevice, process
- * any COMEDI_CB_... event flags that have been set, usually by an
+ * If an asynchronous COMEDI command is active on the subdevice, process
+ * any %COMEDI_CB_... event flags that have been set, usually by an
  * interrupt handler.  These may change the run state of the asynchronous
- * command, wake a task, and/or send a SIGIO signal.
+ * command, wake a task, and/or send a %SIGIO signal.
  */
 void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
 {
@@ -2745,12 +2776,6 @@ struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
        return dev;
 }
 
-static void comedi_free_board_minor(unsigned minor)
-{
-       BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
-       comedi_free_board_dev(comedi_clear_board_minor(minor));
-}
-
 void comedi_release_hardware_device(struct device *hardware_device)
 {
        int minor;
@@ -2806,12 +2831,10 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s)
 
        if (!s)
                return;
-       if (s->minor < 0)
+       if (s->minor < COMEDI_NUM_BOARD_MINORS ||
+           s->minor >= COMEDI_NUM_MINORS)
                return;
 
-       BUG_ON(s->minor >= COMEDI_NUM_MINORS);
-       BUG_ON(s->minor < COMEDI_NUM_BOARD_MINORS);
-
        i = s->minor - COMEDI_NUM_BOARD_MINORS;
        mutex_lock(&comedi_subdevice_minor_table_lock);
        if (s == comedi_subdevice_minor_table[i])
@@ -2825,10 +2848,13 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s)
 
 static void comedi_cleanup_board_minors(void)
 {
+       struct comedi_device *dev;
        unsigned i;
 
-       for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++)
-               comedi_free_board_minor(i);
+       for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
+               dev = comedi_clear_board_minor(i);
+               comedi_free_board_dev(dev);
+       }
 }
 
 static int __init comedi_init(void)
@@ -2900,14 +2926,7 @@ module_init(comedi_init);
 
 static void __exit comedi_cleanup(void)
 {
-       int i;
-
        comedi_cleanup_board_minors();
-       for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i)
-               BUG_ON(comedi_board_minor_table[i]);
-       for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i)
-               BUG_ON(comedi_subdevice_minor_table[i]);
-
        class_destroy(comedi_class);
        cdev_del(&comedi_cdev);
        unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);