|
@@ -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;
|