Merge remote-tracking branch 'torvalds/master' into perf/urgent
[linux-2.6-microblaze.git] / drivers / remoteproc / remoteproc_cdev.c
index b19ea30..0b8a84c 100644 (file)
@@ -32,15 +32,22 @@ static ssize_t rproc_cdev_write(struct file *filp, const char __user *buf, size_
                return -EFAULT;
 
        if (!strncmp(cmd, "start", len)) {
-               if (rproc->state == RPROC_RUNNING)
+               if (rproc->state == RPROC_RUNNING ||
+                   rproc->state == RPROC_ATTACHED)
                        return -EBUSY;
 
                ret = rproc_boot(rproc);
        } else if (!strncmp(cmd, "stop", len)) {
-               if (rproc->state != RPROC_RUNNING)
+               if (rproc->state != RPROC_RUNNING &&
+                   rproc->state != RPROC_ATTACHED)
                        return -EINVAL;
 
                rproc_shutdown(rproc);
+       } else if (!strncmp(cmd, "detach", len)) {
+               if (rproc->state != RPROC_ATTACHED)
+                       return -EINVAL;
+
+               ret = rproc_detach(rproc);
        } else {
                dev_err(&rproc->dev, "Unrecognized option\n");
                ret = -EINVAL;
@@ -79,11 +86,17 @@ static long rproc_device_ioctl(struct file *filp, unsigned int ioctl, unsigned l
 static int rproc_cdev_release(struct inode *inode, struct file *filp)
 {
        struct rproc *rproc = container_of(inode->i_cdev, struct rproc, cdev);
+       int ret = 0;
 
-       if (rproc->cdev_put_on_release && rproc->state == RPROC_RUNNING)
+       if (!rproc->cdev_put_on_release)
+               return 0;
+
+       if (rproc->state == RPROC_RUNNING)
                rproc_shutdown(rproc);
+       else if (rproc->state == RPROC_ATTACHED)
+               ret = rproc_detach(rproc);
 
-       return 0;
+       return ret;
 }
 
 static const struct file_operations rproc_fops = {