[media] rcar_vin: helper function for streaming stop
authorIan Molton <ian.molton@codethink.co.uk>
Mon, 26 Jan 2015 17:08:39 +0000 (14:08 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Mon, 2 Feb 2015 12:41:23 +0000 (10:41 -0200)
The code that tests that capture from a stream has stopped is
presently insufficient and the potential for a race condition
exists where frame capture may generate an interrupt between
requesting the capture process halt and freeing buffers.

This patch refactors code out of rcar_vin_videobuf_release() and
into rcar_vin_wait_stop_streaming(), and ensures there are calls
in places where we need to know that capturing has finished.

Signed-off-by: Ian Molton <ian.molton@codethink.co.uk>
Signed-off-by: William Towle <william.towle@codethink.co.uk>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/platform/soc_camera/rcar_vin.c

index 9c9d5e2bd34e3fad05a0fc5e5915603026b47455..30dc707b794607e7a07da0a0ca7978b33b413176 100644 (file)
@@ -804,6 +804,28 @@ error:
        vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
 }
 
+/*
+ * Wait for capture to stop and all in-flight buffers to be finished with by
+ * the video hardware. This must be called under &priv->lock
+ *
+ */
+static void rcar_vin_wait_stop_streaming(struct rcar_vin_priv *priv)
+{
+       while (priv->state != STOPPED) {
+               /* issue stop if running */
+               if (priv->state == RUNNING)
+                       rcar_vin_request_capture_stop(priv);
+
+               /* wait until capturing has been stopped */
+               if (priv->state == STOPPING) {
+                       priv->request_to_stop = true;
+                       spin_unlock_irq(&priv->lock);
+                       wait_for_completion(&priv->capture_stop);
+                       spin_lock_irq(&priv->lock);
+               }
+       }
+}
+
 static void rcar_vin_videobuf_release(struct vb2_buffer *vb)
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
@@ -823,20 +845,8 @@ static void rcar_vin_videobuf_release(struct vb2_buffer *vb)
        }
 
        if (buf_in_use) {
-               while (priv->state != STOPPED) {
-
-                       /* issue stop if running */
-                       if (priv->state == RUNNING)
-                               rcar_vin_request_capture_stop(priv);
-
-                       /* wait until capturing has been stopped */
-                       if (priv->state == STOPPING) {
-                               priv->request_to_stop = true;
-                               spin_unlock_irq(&priv->lock);
-                               wait_for_completion(&priv->capture_stop);
-                               spin_lock_irq(&priv->lock);
-                       }
-               }
+               rcar_vin_wait_stop_streaming(priv);
+
                /*
                 * Capturing has now stopped. The buffer we have been asked
                 * to release could be any of the current buffers in use, so
@@ -870,8 +880,11 @@ static void rcar_vin_stop_streaming(struct vb2_queue *vq)
        struct list_head *buf_head, *tmp;
 
        spin_lock_irq(&priv->lock);
+
+       rcar_vin_wait_stop_streaming(priv);
        list_for_each_safe(buf_head, tmp, &priv->capture)
                list_del_init(buf_head);
+
        spin_unlock_irq(&priv->lock);
 }