@@ -296,8 +306,8 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
vb, vb->baddr, vb->bsize);
- vb->state = VIDEOBUF_QUEUED;
spin_lock_irqsave(&pcdev->lock, flags);
+ vb->state = VIDEOBUF_QUEUED;
list_add_tail(&vb->queue, &pcdev->capture);
if (!pcdev->active) {
@@ -311,6 +321,27 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ if (pcdev->active == vb) {
+ /* disable capture (release DMA buffer), reset */
+ ceu_write(pcdev, CAPSR, 1 << 16);
+ pcdev->active = NULL;
+ }
+
+ if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
+ !list_empty(&vb->queue)) {
+ vb->state = VIDEOBUF_ERROR;
+ list_del_init(&vb->queue);
+ }
+
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+
free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb));
}
@@ -330,6 +361,10 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
spin_lock_irqsave(&pcdev->lock, flags);
vb = pcdev->active;
+ if (!vb)
+ /* Stale interrupt from a released buffer */
+ goto out;
+
list_del_init(&vb->queue);
if (!list_empty(&pcdev->capture))
@@ -344,6 +379,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
do_gettimeofday(&vb->ts);
vb->field_count++;
wake_up(&vb->done);
+
+out:
spin_unlock_irqrestore(&pcdev->lock, flags);
return IRQ_HANDLED;
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> --- -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html