summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Molton <ian.molton@codethink.co.uk>2015-01-26 14:08:39 -0300
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-02-02 10:41:23 -0200
commit4abec46833c923c1be8dfee1d4eb1fff12cceb21 (patch)
tree3b90fb5171d7abcdbce783688f63e530fe1a49ee
parent650b1815ffa7b39947cdc33568d3113134d999ec (diff)
downloadlinux-4abec46833c923c1be8dfee1d4eb1fff12cceb21.tar.gz
linux-4abec46833c923c1be8dfee1d4eb1fff12cceb21.tar.bz2
linux-4abec46833c923c1be8dfee1d4eb1fff12cceb21.zip
[media] rcar_vin: helper function for streaming stop
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>
-rw-r--r--drivers/media/platform/soc_camera/rcar_vin.c41
1 files changed, 27 insertions, 14 deletions
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index 9c9d5e2bd34e..30dc707b7946 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -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);
}