aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/sh_mobile_ceu_camera.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2009-08-25 10:46:51 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-18 23:18:51 -0400
commitcca0e54905259a456d97652d4f1e2fe8b188b6ad (patch)
tree82a0af7fadc341e4955628f45c2110439c9701e8 /drivers/media/video/sh_mobile_ceu_camera.c
parentfa48984e36ee73e964eeb994a45de6525114e871 (diff)
V4L/DVB (12520): sh-mobile-ceu-camera: do not wait for interrupt when releasing buffers
Patch [PATCH] video: use videobuf_waiton() in sh_mobile_ceu free_buffer() was not quite correct. It closed a race, but introduced a potential lock-up, if for some reason an interrupt does not come. This has been observed in tests with tw9910. This patch safely dequeues buffers without waiting for their completion. It also moves a buffer state assignment under a spinlock to make it atomic with queuing of the buffer. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/sh_mobile_ceu_camera.c')
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 4c4b60c3226..c0dc4a1e8e5 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -307,6 +307,27 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
307static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq, 307static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq,
308 struct videobuf_buffer *vb) 308 struct videobuf_buffer *vb)
309{ 309{
310 struct soc_camera_device *icd = vq->priv_data;
311 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
312 struct sh_mobile_ceu_dev *pcdev = ici->priv;
313 unsigned long flags;
314
315 spin_lock_irqsave(&pcdev->lock, flags);
316
317 if (pcdev->active == vb) {
318 /* disable capture (release DMA buffer), reset */
319 ceu_write(pcdev, CAPSR, 1 << 16);
320 pcdev->active = NULL;
321 }
322
323 if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
324 !list_empty(&vb->queue)) {
325 vb->state = VIDEOBUF_ERROR;
326 list_del_init(&vb->queue);
327 }
328
329 spin_unlock_irqrestore(&pcdev->lock, flags);
330
310 free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb)); 331 free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb));
311} 332}
312 333
@@ -326,6 +347,10 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
326 spin_lock_irqsave(&pcdev->lock, flags); 347 spin_lock_irqsave(&pcdev->lock, flags);
327 348
328 vb = pcdev->active; 349 vb = pcdev->active;
350 if (!vb)
351 /* Stale interrupt from a released buffer */
352 goto out;
353
329 list_del_init(&vb->queue); 354 list_del_init(&vb->queue);
330 355
331 if (!list_empty(&pcdev->capture)) 356 if (!list_empty(&pcdev->capture))
@@ -340,6 +365,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
340 do_gettimeofday(&vb->ts); 365 do_gettimeofday(&vb->ts);
341 vb->field_count++; 366 vb->field_count++;
342 wake_up(&vb->done); 367 wake_up(&vb->done);
368
369out:
343 spin_unlock_irqrestore(&pcdev->lock, flags); 370 spin_unlock_irqrestore(&pcdev->lock, flags);
344 371
345 return IRQ_HANDLED; 372 return IRQ_HANDLED;