diff options
author | Ian Molton <ian.molton@codethink.co.uk> | 2015-01-26 14:08:39 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-02-02 10:41:23 -0200 |
commit | 4abec46833c923c1be8dfee1d4eb1fff12cceb21 (patch) | |
tree | 3b90fb5171d7abcdbce783688f63e530fe1a49ee | |
parent | 650b1815ffa7b39947cdc33568d3113134d999ec (diff) | |
download | linux-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.c | 41 |
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); } |