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)
 {
        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;