staging: comedi: add ioctls to set per-file read and write subdevice
authorIan Abbott <abbotti@mev.co.uk>
Tue, 4 Nov 2014 18:09:01 +0000 (18:09 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Nov 2014 22:52:18 +0000 (14:52 -0800)
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>
drivers/staging/comedi/comedi.h
drivers/staging/comedi/comedi_compat32.c
drivers/staging/comedi/comedi_fops.c

index f302ce6c93de571c8eb10df3e4c50072b6001652..7455740773527c56e002ed04a4e358b20f95fddd 100644 (file)
@@ -367,6 +367,8 @@ enum comedi_support_level {
 #define COMEDI_BUFCONFIG _IOR(CIO, 13, struct comedi_bufconfig)
 #define COMEDI_BUFINFO _IOWR(CIO, 14, struct comedi_bufinfo)
 #define COMEDI_POLL _IO(CIO, 15)
+#define COMEDI_SETRSUBD _IO(CIO, 16)
+#define COMEDI_SETWSUBD _IO(CIO, 17)
 
 /* structures */
 
index 9b6f96f1591cb2c9f1bcbe420b34fc17ee6abd95..5a4c74f703b3bdff5de1f3129630ba2c86de9668 100644 (file)
@@ -416,6 +416,8 @@ static inline int raw_ioctl(struct file *file, unsigned int cmd,
        case COMEDI_UNLOCK:
        case COMEDI_CANCEL:
        case COMEDI_POLL:
+       case COMEDI_SETRSUBD:
+       case COMEDI_SETWSUBD:
                /* No translation needed. */
                rc = translated_ioctl(file, cmd, arg);
                break;
index 79b852c6d868c81dbcf454e0a241ec3fce98f012..f143cb64d69e347d531254b9897b5e01a0b1401b 100644 (file)
@@ -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;