From b4b7ff4b08e691656c9d77c758fc355833128ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fabian=20Silva=20Delgado?= Date: Wed, 20 Jan 2016 14:01:31 -0300 Subject: Linux-libre 4.4-gnu --- drivers/staging/comedi/comedi_fops.c | 180 ++++++++++++++++++----------------- 1 file changed, 91 insertions(+), 89 deletions(-) (limited to 'drivers/staging/comedi/comedi_fops.c') diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 0e8a45102..7b4af519e 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -43,15 +43,15 @@ #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 + * 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_RUNNING: command is running + * COMEDI_SRF_FREE_SPRIV: free s->private on detach * - * @COMEDI_SRF_BUSY_MASK: runflags that indicate the subdevice is "busy" + * COMEDI_SRF_BUSY_MASK: runflags that indicate the subdevice is "busy" */ #define COMEDI_SRF_RT BIT(1) #define COMEDI_SRF_ERROR BIT(2) @@ -61,12 +61,12 @@ #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; @@ -131,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) @@ -247,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) @@ -665,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) { @@ -701,11 +701,12 @@ bool comedi_can_auto_free_spriv(struct comedi_subdevice *s) } /** - * comedi_set_spriv_auto_free - mark subdevice private data as freeable - * @s: comedi_subdevice struct + * 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 by the comedi core during the detach. + * automatically freed when the COMEDI device is detached from the low-level + * driver. */ void comedi_set_spriv_auto_free(struct comedi_subdevice *s) { @@ -714,12 +715,16 @@ void comedi_set_spriv_auto_free(struct comedi_subdevice *s) 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) { @@ -1141,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); } } @@ -1336,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); @@ -2257,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"); @@ -2267,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; @@ -2279,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; } @@ -2444,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; @@ -2470,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); @@ -2499,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; @@ -2513,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; @@ -2541,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; /* @@ -2561,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: @@ -2686,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) { -- cgit v1.2.3