summaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/comedi_fops.c
diff options
context:
space:
mode:
authorIan Abbott2014-11-04 19:09:01 +0100
committerGreg Kroah-Hartman2014-11-05 23:52:18 +0100
commitc299a6789c35392dcd66f806013bab86969cf5c4 (patch)
tree7fe4aac56d9de920b0c2779ee1940bd793f1bf7c /drivers/staging/comedi/comedi_fops.c
parentstaging: comedi: prepare support for per-file read and write subdevices (diff)
downloadkernel-qcow2-linux-c299a6789c35392dcd66f806013bab86969cf5c4.tar.gz
kernel-qcow2-linux-c299a6789c35392dcd66f806013bab86969cf5c4.tar.xz
kernel-qcow2-linux-c299a6789c35392dcd66f806013bab86969cf5c4.zip
staging: comedi: add ioctls to set per-file read and write subdevice
Now that Comedi has the structures in place to support setting the current "read" and/or "write" subdevice on a per-file object basis, add new ioctls to set them. The newly chosen "read" ("write") subdevice needs to support "read" ("write") commands, and the file cannot be busy handling a "read" ("write") command on the previous subdevice (if any). Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Reviewed-by: H Hartley Sweeten <hsweeten@visionengravers.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/comedi/comedi_fops.c')
-rw-r--r--drivers/staging/comedi/comedi_fops.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 79b852c6d868..f143cb64d69e 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1847,6 +1847,90 @@ static int do_poll_ioctl(struct comedi_device *dev, unsigned long arg,
return -EINVAL;
}
+/*
+ * COMEDI_SETRSUBD ioctl
+ * sets the current "read" subdevice on a per-file basis
+ *
+ * arg:
+ * subdevice number
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * nothing
+ */
+static int do_setrsubd_ioctl(struct comedi_device *dev, unsigned long arg,
+ struct file *file)
+{
+ struct comedi_file *cfp = file->private_data;
+ struct comedi_subdevice *s_old, *s_new;
+
+ if (arg >= dev->n_subdevices)
+ return -EINVAL;
+
+ s_new = &dev->subdevices[arg];
+ s_old = comedi_file_read_subdevice(file);
+ if (s_old == s_new)
+ return 0; /* no change */
+
+ if (!(s_new->subdev_flags & SDF_CMD_READ))
+ return -EINVAL;
+
+ /*
+ * Check the file isn't still busy handling a "read" command on the
+ * old subdevice (if any).
+ */
+ if (s_old && s_old->busy == file && s_old->async &&
+ !(s_old->async->cmd.flags & CMDF_WRITE))
+ return -EBUSY;
+
+ ACCESS_ONCE(cfp->read_subdev) = s_new;
+ return 0;
+}
+
+/*
+ * COMEDI_SETWSUBD ioctl
+ * sets the current "write" subdevice on a per-file basis
+ *
+ * arg:
+ * subdevice number
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * nothing
+ */
+static int do_setwsubd_ioctl(struct comedi_device *dev, unsigned long arg,
+ struct file *file)
+{
+ struct comedi_file *cfp = file->private_data;
+ struct comedi_subdevice *s_old, *s_new;
+
+ if (arg >= dev->n_subdevices)
+ return -EINVAL;
+
+ s_new = &dev->subdevices[arg];
+ s_old = comedi_file_write_subdevice(file);
+ if (s_old == s_new)
+ return 0; /* no change */
+
+ if (!(s_new->subdev_flags & SDF_CMD_WRITE))
+ return -EINVAL;
+
+ /*
+ * Check the file isn't still busy handling a "write" command on the
+ * old subdevice (if any).
+ */
+ if (s_old && s_old->busy == file && s_old->async &&
+ (s_old->async->cmd.flags & CMDF_WRITE))
+ return -EBUSY;
+
+ ACCESS_ONCE(cfp->write_subdev) = s_new;
+ return 0;
+}
+
static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -1941,6 +2025,12 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
case COMEDI_POLL:
rc = do_poll_ioctl(dev, arg, file);
break;
+ case COMEDI_SETRSUBD:
+ rc = do_setrsubd_ioctl(dev, arg, file);
+ break;
+ case COMEDI_SETWSUBD:
+ rc = do_setwsubd_ioctl(dev, arg, file);
+ break;
default:
rc = -ENOTTY;
break;