Verify that the request state is IDLE before queueing it. Also mark
requests queued when they're queued, and return the request to IDLE if
queueing it failed.

Signed-off-by: Sakari Ailus <sakari.ai...@linux.intel.com>
---
 drivers/media/media-device.c | 55 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 47 insertions(+), 8 deletions(-)

diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 7781c49..247587b 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -189,6 +189,47 @@ static void media_device_request_delete(struct 
media_device *mdev,
        media_device_request_put(req);
 }
 
+static int media_device_request_queue_apply(
+       struct media_device *mdev, struct media_device_request *req,
+       int (*fn)(struct media_device *mdev,
+                 struct media_device_request *req), bool queue)
+{
+       char *str = queue ? "queue" : "apply";
+       unsigned long flags;
+       int rval = 0;
+
+       if (!fn)
+               return -ENOSYS;
+
+       spin_lock_irqsave(&mdev->req_lock, flags);
+       if (req->state != MEDIA_DEVICE_REQUEST_STATE_IDLE) {
+               rval = -EINVAL;
+               dev_dbg(mdev->dev,
+                       "request: unable to %s %u, request in state %s\n",
+                       str, req->id, request_state(req->state));
+       } else {
+               req->state = MEDIA_DEVICE_REQUEST_STATE_QUEUED;
+       }
+       spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+       if (rval)
+               return rval;
+
+       rval = fn(mdev, req);
+       if (rval) {
+               spin_lock_irqsave(&mdev->req_lock, flags);
+               req->state = MEDIA_DEVICE_REQUEST_STATE_IDLE;
+               spin_unlock_irqrestore(&mdev->req_lock, flags);
+               dev_dbg(mdev->dev,
+                       "request: can't %s %u\n", str, req->id);
+       } else {
+               dev_dbg(mdev->dev,
+                       "request: %s %u\n", str, req->id);
+       }
+
+       return rval;
+}
+
 static long media_device_request_cmd(struct media_device *mdev,
                                     struct file *filp,
                                     struct media_request_cmd *cmd)
@@ -216,17 +257,15 @@ static long media_device_request_cmd(struct media_device 
*mdev,
                break;
 
        case MEDIA_REQ_CMD_APPLY:
-               if (!mdev->ops->req_apply)
-                       return -ENOSYS;
-
-               ret = mdev->ops->req_apply(mdev, req);
+               ret = media_device_request_queue_apply(mdev, req,
+                                                      mdev->ops->req_apply,
+                                                      false);
                break;
 
        case MEDIA_REQ_CMD_QUEUE:
-               if (!mdev->ops->req_queue)
-                       return -ENOSYS;
-
-               ret = mdev->ops->req_queue(mdev, req);
+               ret = media_device_request_queue_apply(mdev, req,
+                                                      mdev->ops->req_queue,
+                                                      true);
                break;
 
        default:
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to