aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/comedi_fops.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi/comedi_fops.c')
-rw-r--r--drivers/staging/comedi/comedi_fops.c467
1 files changed, 262 insertions, 205 deletions
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index f143cb64d69e..727640e89c73 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1,20 +1,20 @@
/*
- comedi/comedi_fops.c
- comedi kernel module
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * comedi/comedi_fops.c
+ * comedi kernel module
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -113,6 +113,18 @@ static void comedi_dev_kref_release(struct kref *kref)
kfree(dev);
}
+/**
+ * comedi_dev_put - release a use of a comedi device structure
+ * @dev: comedi_device struct
+ *
+ * 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
+ * device is still valid if this function returns 0.
+ */
int comedi_dev_put(struct comedi_device *dev)
{
if (dev)
@@ -220,6 +232,18 @@ static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor)
return dev;
}
+/**
+ * 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
+ * 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
+ * specified minor device number.
+ */
struct comedi_device *comedi_dev_get_from_minor(unsigned minor)
{
if (minor < COMEDI_NUM_BOARD_MINORS)
@@ -323,8 +347,7 @@ static int resize_async_buffer(struct comedi_device *dev,
return -EBUSY;
}
- /* make sure buffer is an integral number of pages
- * (we round up) */
+ /* make sure buffer is an integral number of pages (we round up) */
new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
retval = comedi_buf_alloc(dev, s, new_size);
@@ -600,11 +623,18 @@ static unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
return runflags;
}
+/**
+ * comedi_is_subdevice_running - check if async command running on subdevice
+ * @s: comedi_subdevice struct
+ *
+ * Return true if an asynchronous comedi command is active on the comedi
+ * subdevice, else return false.
+ */
bool comedi_is_subdevice_running(struct comedi_subdevice *s)
{
unsigned runflags = comedi_get_subdevice_runflags(s);
- return (runflags & SRF_RUNNING) ? true : false;
+ return (runflags & COMEDI_SRF_RUNNING) ? true : false;
}
EXPORT_SYMBOL_GPL(comedi_is_subdevice_running);
@@ -612,14 +642,14 @@ static bool comedi_is_subdevice_in_error(struct comedi_subdevice *s)
{
unsigned runflags = comedi_get_subdevice_runflags(s);
- return (runflags & SRF_ERROR) ? true : false;
+ return (runflags & COMEDI_SRF_ERROR) ? true : false;
}
static bool comedi_is_subdevice_idle(struct comedi_subdevice *s)
{
unsigned runflags = comedi_get_subdevice_runflags(s);
- return (runflags & (SRF_ERROR | SRF_RUNNING)) ? false : true;
+ return (runflags & COMEDI_SRF_BUSY_MASK) ? false : true;
}
/**
@@ -634,20 +664,20 @@ void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size)
{
s->private = kzalloc(size, GFP_KERNEL);
if (s->private)
- s->runflags |= SRF_FREE_SPRIV;
+ s->runflags |= COMEDI_SRF_FREE_SPRIV;
return s->private;
}
EXPORT_SYMBOL_GPL(comedi_alloc_spriv);
/*
- This function restores a subdevice to an idle state.
+ * This function restores a subdevice to an idle state.
*/
static void do_become_nonbusy(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct comedi_async *async = s->async;
- comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
+ comedi_set_subdevice_runflags(s, COMEDI_SRF_RUNNING, 0);
if (async) {
comedi_buf_reset(s);
async->inttrig = NULL;
@@ -709,18 +739,18 @@ static int is_device_busy(struct comedi_device *dev)
}
/*
- COMEDI_DEVCONFIG
- device config ioctl
-
- arg:
- pointer to devconfig structure
-
- reads:
- devconfig structure at arg
-
- writes:
- none
-*/
+ * COMEDI_DEVCONFIG ioctl
+ * attaches (and configures) or detaches a legacy device
+ *
+ * arg:
+ * pointer to comedi_devconfig structure (NULL if detaching)
+ *
+ * reads:
+ * comedi_devconfig structure (if attaching)
+ *
+ * writes:
+ * nothing
+ */
static int do_devconfig_ioctl(struct comedi_device *dev,
struct comedi_devconfig __user *arg)
{
@@ -761,19 +791,18 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
}
/*
- COMEDI_BUFCONFIG
- buffer configuration ioctl
-
- arg:
- pointer to bufconfig structure
-
- reads:
- bufconfig at arg
-
- writes:
- modified bufconfig at arg
-
-*/
+ * COMEDI_BUFCONFIG ioctl
+ * buffer configuration
+ *
+ * arg:
+ * pointer to comedi_bufconfig structure
+ *
+ * reads:
+ * comedi_bufconfig structure
+ *
+ * writes:
+ * modified comedi_bufconfig structure
+ */
static int do_bufconfig_ioctl(struct comedi_device *dev,
struct comedi_bufconfig __user *arg)
{
@@ -823,19 +852,18 @@ copyback:
}
/*
- COMEDI_DEVINFO
- device info ioctl
-
- arg:
- pointer to devinfo structure
-
- reads:
- none
-
- writes:
- devinfo structure
-
-*/
+ * COMEDI_DEVINFO ioctl
+ * device info
+ *
+ * arg:
+ * pointer to comedi_devinfo structure
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * comedi_devinfo structure
+ */
static int do_devinfo_ioctl(struct comedi_device *dev,
struct comedi_devinfo __user *arg,
struct file *file)
@@ -870,19 +898,18 @@ static int do_devinfo_ioctl(struct comedi_device *dev,
}
/*
- COMEDI_SUBDINFO
- subdevice info ioctl
-
- arg:
- pointer to array of subdevice info structures
-
- reads:
- none
-
- writes:
- array of subdevice info structures at arg
-
-*/
+ * COMEDI_SUBDINFO ioctl
+ * subdevices info
+ *
+ * arg:
+ * pointer to array of comedi_subdinfo structures
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * array of comedi_subdinfo structures
+ */
static int do_subdinfo_ioctl(struct comedi_device *dev,
struct comedi_subdinfo __user *arg, void *file)
{
@@ -944,19 +971,19 @@ static int do_subdinfo_ioctl(struct comedi_device *dev,
}
/*
- COMEDI_CHANINFO
- subdevice info ioctl
-
- arg:
- pointer to chaninfo structure
-
- reads:
- chaninfo structure at arg
-
- writes:
- arrays at elements of chaninfo structure
-
-*/
+ * COMEDI_CHANINFO ioctl
+ * subdevice channel info
+ *
+ * arg:
+ * pointer to comedi_chaninfo structure
+ *
+ * reads:
+ * comedi_chaninfo structure
+ *
+ * writes:
+ * array of maxdata values to chaninfo->maxdata_list if requested
+ * array of range table lengths to chaninfo->range_table_list if requested
+ */
static int do_chaninfo_ioctl(struct comedi_device *dev,
struct comedi_chaninfo __user *arg)
{
@@ -1004,20 +1031,19 @@ static int do_chaninfo_ioctl(struct comedi_device *dev,
return 0;
}
- /*
- COMEDI_BUFINFO
- buffer information ioctl
-
- arg:
- pointer to bufinfo structure
-
- reads:
- bufinfo at arg
-
- writes:
- modified bufinfo at arg
-
- */
+/*
+ * COMEDI_BUFINFO ioctl
+ * buffer information
+ *
+ * arg:
+ * pointer to comedi_bufinfo structure
+ *
+ * reads:
+ * comedi_bufinfo structure
+ *
+ * writes:
+ * modified comedi_bufinfo structure
+ */
static int do_bufinfo_ioctl(struct comedi_device *dev,
struct comedi_bufinfo __user *arg, void *file)
{
@@ -1135,8 +1161,10 @@ static int check_insn_config_length(struct comedi_insn *insn,
if (insn->n == 6)
return 0;
break;
- /* by default we allow the insn since we don't have checks for
- * all possible cases yet */
+ /*
+ * by default we allow the insn since we don't have checks for
+ * all possible cases yet
+ */
default:
pr_warn("No check for data length of config insn id %i is implemented\n",
data[0]);
@@ -1287,9 +1315,11 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
if (insn->n != 2) {
ret = -EINVAL;
} else {
- /* Most drivers ignore the base channel in
+ /*
+ * Most drivers ignore the base channel in
* insn->chanspec. Fix this here if
- * the subdevice has <= 32 channels. */
+ * the subdevice has <= 32 channels.
+ */
unsigned int orig_mask = data[0];
unsigned int shift = 0;
@@ -1326,19 +1356,19 @@ out:
}
/*
- * COMEDI_INSNLIST
- * synchronous instructions
+ * COMEDI_INSNLIST ioctl
+ * synchronous instruction list
*
- * arg:
- * pointer to sync cmd structure
+ * arg:
+ * pointer to comedi_insnlist structure
*
- * reads:
- * sync cmd struct at arg
- * instruction list
- * data (for writes)
+ * reads:
+ * comedi_insnlist structure
+ * array of comedi_insn structures from insnlist->insns pointer
+ * data (for writes) from insns[].data pointers
*
- * writes:
- * data (for reads)
+ * writes:
+ * data (for reads) to insns[].data pointers
*/
/* arbitrary limits */
#define MAX_SAMPLES 256
@@ -1415,18 +1445,18 @@ error:
}
/*
- * COMEDI_INSN
- * synchronous instructions
+ * COMEDI_INSN ioctl
+ * synchronous instruction
*
- * arg:
- * pointer to insn
+ * arg:
+ * pointer to comedi_insn structure
*
- * reads:
- * struct comedi_insn struct at arg
- * data (for writes)
+ * reads:
+ * comedi_insn structure
+ * data (for writes) from insn->data pointer
*
- * writes:
- * data (for reads)
+ * writes:
+ * data (for reads) to insn->data pointer
*/
static int do_insn_ioctl(struct comedi_device *dev,
struct comedi_insn __user *arg, void *file)
@@ -1558,6 +1588,20 @@ static int __comedi_get_user_chanlist(struct comedi_device *dev,
return 0;
}
+/*
+ * COMEDI_CMD ioctl
+ * asynchronous acquisition command set-up
+ *
+ * arg:
+ * pointer to comedi_cmd structure
+ *
+ * reads:
+ * comedi_cmd structure
+ * channel/range list from cmd->chanlist pointer
+ *
+ * writes:
+ * possibly modified comedi_cmd structure (when -EAGAIN returned)
+ */
static int do_cmd_ioctl(struct comedi_device *dev,
struct comedi_cmd __user *arg, void *file)
{
@@ -1634,10 +1678,13 @@ static int do_cmd_ioctl(struct comedi_device *dev,
if (async->cmd.flags & CMDF_WAKE_EOS)
async->cb_mask |= COMEDI_CB_EOS;
- comedi_set_subdevice_runflags(s, SRF_ERROR | SRF_RUNNING, SRF_RUNNING);
+ comedi_set_subdevice_runflags(s, COMEDI_SRF_BUSY_MASK,
+ COMEDI_SRF_RUNNING);
- /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with
- * comedi_read() or comedi_write() */
+ /*
+ * Set s->busy _after_ setting COMEDI_SRF_RUNNING flag to avoid
+ * race with comedi_read() or comedi_write().
+ */
s->busy = file;
ret = s->do_cmd(dev, s);
if (ret == 0)
@@ -1650,20 +1697,19 @@ cleanup:
}
/*
- COMEDI_CMDTEST
- command testing ioctl
-
- arg:
- pointer to cmd structure
-
- reads:
- cmd structure at arg
- channel/range list
-
- writes:
- modified cmd structure at arg
-
-*/
+ * COMEDI_CMDTEST ioctl
+ * asynchronous aquisition command testing
+ *
+ * arg:
+ * pointer to comedi_cmd structure
+ *
+ * reads:
+ * comedi_cmd structure
+ * channel/range list from cmd->chanlist pointer
+ *
+ * writes:
+ * possibly modified comedi_cmd structure
+ */
static int do_cmdtest_ioctl(struct comedi_device *dev,
struct comedi_cmd __user *arg, void *file)
{
@@ -1706,20 +1752,18 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
}
/*
- COMEDI_LOCK
- lock subdevice
-
- arg:
- subdevice number
-
- reads:
- none
-
- writes:
- none
-
-*/
-
+ * COMEDI_LOCK ioctl
+ * lock subdevice
+ *
+ * arg:
+ * subdevice number
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * nothing
+ */
static int do_lock_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
@@ -1742,21 +1786,18 @@ static int do_lock_ioctl(struct comedi_device *dev, unsigned long arg,
}
/*
- COMEDI_UNLOCK
- unlock subdevice
-
- arg:
- subdevice number
-
- reads:
- none
-
- writes:
- none
-
- This function isn't protected by the semaphore, since
- we already own the lock.
-*/
+ * COMEDI_UNLOCK ioctl
+ * unlock subdevice
+ *
+ * arg:
+ * subdevice number
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * nothing
+ */
static int do_unlock_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
@@ -1779,19 +1820,18 @@ static int do_unlock_ioctl(struct comedi_device *dev, unsigned long arg,
}
/*
- COMEDI_CANCEL
- cancel acquisition ioctl
-
- arg:
- subdevice number
-
- reads:
- nothing
-
- writes:
- nothing
-
-*/
+ * COMEDI_CANCEL ioctl
+ * cancel asynchronous acquisition
+ *
+ * arg:
+ * subdevice number
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * nothing
+ */
static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
@@ -1813,19 +1853,18 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg,
}
/*
- COMEDI_POLL ioctl
- instructs driver to synchronize buffers
-
- arg:
- subdevice number
-
- reads:
- nothing
-
- writes:
- nothing
-
-*/
+ * COMEDI_POLL ioctl
+ * instructs driver to synchronize buffers
+ *
+ * arg:
+ * subdevice number
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * nothing
+ */
static int do_poll_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
@@ -1941,8 +1980,10 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
mutex_lock(&dev->mutex);
- /* Device config is special, because it must work on
- * an unconfigured device. */
+ /*
+ * 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. */
@@ -1954,8 +1995,10 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
if (rc == 0) {
if (arg == 0 &&
dev->minor >= comedi_num_legacy_minors) {
- /* Successfully unconfigured a dynamically
- * allocated device. Try and remove it. */
+ /*
+ * Successfully unconfigured a dynamically
+ * allocated device. Try and remove it.
+ */
if (comedi_clear_board_dev(dev)) {
mutex_unlock(&dev->mutex);
comedi_free_board_dev(dev);
@@ -2581,6 +2624,17 @@ static const struct file_operations comedi_fops = {
.llseek = noop_llseek,
};
+/**
+ * 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
+ *
+ * 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.
+ */
void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct comedi_async *async = s->async;
@@ -2591,18 +2645,21 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
return;
if (s->async->events & COMEDI_CB_CANCEL_MASK)
- runflags_mask |= SRF_RUNNING;
+ runflags_mask |= COMEDI_SRF_RUNNING;
/*
* Remember if an error event has occurred, so an error
* can be returned the next time the user does a read().
*/
if (s->async->events & COMEDI_CB_ERROR_MASK) {
- runflags_mask |= SRF_ERROR;
- runflags |= SRF_ERROR;
+ runflags_mask |= COMEDI_SRF_ERROR;
+ runflags |= COMEDI_SRF_ERROR;
}
if (runflags_mask) {
- /*sets SRF_ERROR and SRF_RUNNING together atomically */
+ /*
+ * Sets COMEDI_SRF_ERROR and COMEDI_SRF_RUNNING together
+ * atomically.
+ */
comedi_set_subdevice_runflags(s, runflags_mask, runflags);
}