V4L/DVB: videobuf: add queue argument to videobuf_waiton()
authorHans Verkuil <hverkuil@xs4all.nl>
Sun, 26 Sep 2010 12:01:26 +0000 (09:01 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 21 Oct 2010 03:06:14 +0000 (01:06 -0200)
videobuf_waiton() must unlock and relock ext_lock if it has to wait.
For that to happen it needs the videobuf_queue pointer.

Don't attempt to unlock/relock q->ext_lock unless it was locked in the
first place.

vb->state has to be protected by a spinlock to be safe.

This patch is based on code from Mauro Carvalho Chehab <mchehab@redhat.com>.

[mchehab@redhat.com: add extra argument to a few missing places]
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
20 files changed:
drivers/media/common/saa7146_fops.c
drivers/media/video/bt8xx/bttv-risc.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/fsl-viu.c
drivers/media/video/mem2mem_testdev.c
drivers/media/video/mx1_camera.c
drivers/media/video/mx2_camera.c
drivers/media/video/mx3_camera.c
drivers/media/video/omap24xxcam.c
drivers/media/video/pxa_camera.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sh_vou.c
drivers/media/video/tlg2300/pd-video.c
drivers/media/video/videobuf-core.c
drivers/media/video/videobuf-dvb.c
drivers/staging/cx25821/cx25821-core.c
drivers/staging/dt3155v4l/dt3155v4l.c
include/media/videobuf-core.h

index 4da2a54cb8bde6b1a9052df74300418432f9a7f3..e3fedc60fe7775bb0586492061ef63a50c0e0d27 100644 (file)
@@ -56,7 +56,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
 
        BUG_ON(in_interrupt());
 
-       videobuf_waiton(&buf->vb,0,0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
index 0fa9f39f37a32be9303993b3e4f31835c6042ebf..9b57d091da48cede48cf7eca3e1976a96521a854 100644 (file)
@@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf
        struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
        BUG_ON(in_interrupt());
-       videobuf_waiton(&buf->vb,0,0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(btv->c.pci,&buf->bottom);
index f6b62e7398afaf1f0e704059ce95aac5c36848d3..2a34e955dad265e392d93b71b313d6101d1eb992 100644 (file)
@@ -1221,7 +1221,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
 
        BUG_ON(in_interrupt());
-       videobuf_waiton(&buf->vb, 0, 0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
index e46dd7ed63ce7cec573d03cf2332d18cfe5be6c4..2e145f0a5fd99d7c3077c1ab47828db497737663 100644 (file)
@@ -217,7 +217,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
        struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
        BUG_ON(in_interrupt());
-       videobuf_waiton(&buf->vb,0,0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
index 0b318bed4d5243c21e37dced876395ff15f52d95..211e83963a466eaa4ad76770c341335df4312540 100644 (file)
@@ -426,7 +426,7 @@ static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf)
 
        BUG_ON(in_interrupt());
 
-       videobuf_waiton(&buf->vb, 0, 0);
+       videobuf_waiton(vq, &buf->vb, 0, 0);
 
        if (vq->int_ops && vq->int_ops->vaddr)
                vaddr = vq->int_ops->vaddr(vb);
index a7210d981388e8c4724f524e3fd5c77bbd672dca..3b19f5b25a729aea08509df0be067f177d3de4e4 100644 (file)
@@ -848,7 +848,7 @@ static void queue_init(void *priv, struct videobuf_queue *vq,
 
        videobuf_queue_vmalloc_init(vq, &m2mtest_qops, ctx->dev->v4l2_dev.dev,
                                    &ctx->dev->irqlock, type, V4L2_FIELD_NONE,
-                                   sizeof(struct m2mtest_buffer), priv);
+                                   sizeof(struct m2mtest_buffer), priv, NULL);
 }
 
 
index 5c17f9ec3d7c641583f95235f96f28df356f163f..e8a5ffcb6f06f9eb7011709e29487ad0bd398cfb 100644 (file)
@@ -161,7 +161,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf)
         * This waits until this buffer is out of danger, i.e., until it is no
         * longer in STATE_QUEUED or STATE_ACTIVE
         */
-       videobuf_waiton(vb, 0, 0);
+       videobuf_waiton(vq, vb, 0, 0);
        videobuf_dma_contig_free(vq, vb);
 
        vb->state = VIDEOBUF_NEEDS_INIT;
index b6ea67221d1d5fc64594348f49715539c19f9840..38d09474da13fb71a10b654f01f329f2552d5428 100644 (file)
@@ -463,7 +463,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
         * This waits until this buffer is out of danger, i.e., until it is no
         * longer in STATE_QUEUED or STATE_ACTIVE
         */
-       videobuf_waiton(vb, 0, 0);
+       videobuf_waiton(vq, vb, 0, 0);
 
        videobuf_dma_contig_free(vq, vb);
        dev_dbg(&icd->dev, "%s freed\n", __func__);
index a9be14c239124a06185c3ff6c43af44bb47d4f83..a13076969e5aecf161db355bc7a0e91832436e15 100644 (file)
@@ -185,7 +185,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf
         * This waits until this buffer is out of danger, i.e., until it is no
         * longer in STATE_QUEUED or STATE_ACTIVE
         */
-       videobuf_waiton(vb, 0, 0);
+       videobuf_waiton(vq, vb, 0, 0);
        if (txd) {
                ichan = to_idmac_chan(txd->chan);
                async_tx_ack(txd);
index 926a5aa6f7f81951ac639c534a05ea0e4c5ac914..13c09f5fa87575232e812036ba597fa83347be99 100644 (file)
@@ -420,7 +420,7 @@ static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
        struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
 
        /* wait for buffer, especially to get out of the sgdma queue */
-       videobuf_waiton(vb, 0, 0);
+       videobuf_waiton(vbq, vb, 0, 0);
        if (vb->memory == V4L2_MEMORY_MMAP) {
                dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen,
                             dma->direction);
index 9de7d59916bda188c767d42f592f3d1f9b8b8d27..109ba99ae121c609768188db44a7b1ef1979c8b2 100644 (file)
@@ -275,7 +275,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
         * This waits until this buffer is out of danger, i.e., until it is no
         * longer in STATE_QUEUED or STATE_ACTIVE
         */
-       videobuf_waiton(&buf->vb, 0, 0);
+       videobuf_waiton(vq, &buf->vb, 0, 0);
        videobuf_dma_unmap(vq->dev, dma);
        videobuf_dma_free(dma);
 
index 40bc635e8a3f45f82608c3fbfd9be92042e76819..c424c4574d49bba39d16392f4475144077a30aff 100644 (file)
@@ -255,7 +255,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
        struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
        BUG_ON(in_interrupt());
 
-       videobuf_waiton(&buf->vb,0,0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
index 2b24bd0de3ad47257752ea69a1e3619d229de108..39211628d427ef4cf880839618057646b19b971e 100644 (file)
@@ -245,7 +245,7 @@ static void free_buffer(struct videobuf_queue *vq,
        if (in_interrupt())
                BUG();
 
-       videobuf_waiton(&buf->vb, 0, 0);
+       videobuf_waiton(vq, &buf->vb, 0, 0);
        videobuf_dma_contig_free(vq, &buf->vb);
        dev_dbg(dev, "%s freed\n", __func__);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
index d394187eb701d04aa81ebe4a4aff4966e5e63257..d3acd02a163261434f947dd27fb477ba70da38d2 100644 (file)
@@ -230,7 +230,7 @@ static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb)
        BUG_ON(in_interrupt());
 
        /* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */
-       videobuf_waiton(vb, 0, 0);
+       videobuf_waiton(vq, vb, 0, 0);
        videobuf_dma_contig_free(vq, vb);
        vb->state = VIDEOBUF_NEEDS_INIT;
 }
index d0cc012f7ae6105a5bd0a0a4d7d1d170c1d9a875..a1ffe18640fe95778a6a1feca3e35aaa4d17416c 100644 (file)
@@ -1434,7 +1434,7 @@ static int pd_video_open(struct file *file)
                                V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                V4L2_FIELD_INTERLACED,/* video is interlacd */
                                sizeof(struct videobuf_buffer),/*it's enough*/
-                               front);
+                               front, NULL);
        } else if (vfd->vfl_type == VFL_TYPE_VBI
                && !(pd->state & POSEIDON_STATE_VBI)) {
                front = kzalloc(sizeof(struct front_face), GFP_KERNEL);
@@ -1451,7 +1451,7 @@ static int pd_video_open(struct file *file)
                                V4L2_BUF_TYPE_VBI_CAPTURE,
                                V4L2_FIELD_NONE, /* vbi is NONE mode */
                                sizeof(struct videobuf_buffer),
-                               front);
+                               front, NULL);
        } else {
                /* maybe add FM support here */
                log("other ");
index a32ef8eafc0176669d1bd3f8644714b709bdbe7d..8979f91fa8e595422b3d72cc06a69266039d5f2c 100644 (file)
@@ -73,25 +73,46 @@ struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q)
 }
 EXPORT_SYMBOL_GPL(videobuf_alloc_vb);
 
-#define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\
-                               vb->state != VIDEOBUF_QUEUED)
-int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
+static int is_state_active_or_queued(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
+       unsigned long flags;
+       bool rc;
+
+       spin_lock_irqsave(q->irqlock, flags);
+       rc = vb->state != VIDEOBUF_ACTIVE && vb->state != VIDEOBUF_QUEUED;
+       spin_unlock_irqrestore(q->irqlock, flags);
+       return rc;
+};
+
+int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb,
+               int non_blocking, int intr)
+{
+       bool is_ext_locked;
+       int ret = 0;
+
        MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
 
        if (non_blocking) {
-               if (WAITON_CONDITION)
+               if (is_state_active_or_queued(q, vb))
                        return 0;
-               else
-                       return -EAGAIN;
+               return -EAGAIN;
        }
 
+       is_ext_locked = q->ext_lock && mutex_is_locked(q->ext_lock);
+
+       /* Release vdev lock to prevent this wait from blocking outside access to
+          the device. */
+       if (is_ext_locked)
+               mutex_unlock(q->ext_lock);
        if (intr)
-               return wait_event_interruptible(vb->done, WAITON_CONDITION);
+               ret = wait_event_interruptible(vb->done, is_state_active_or_queued(q, vb));
        else
-               wait_event(vb->done, WAITON_CONDITION);
+               wait_event(vb->done, is_state_active_or_queued(q, vb));
+       /* Relock */
+       if (is_ext_locked)
+               mutex_lock(q->ext_lock);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(videobuf_waiton);
 
@@ -671,7 +692,7 @@ static int stream_next_buffer(struct videobuf_queue *q,
                goto done;
 
        buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
-       retval = videobuf_waiton(buf, nonblocking, 1);
+       retval = videobuf_waiton(q, buf, nonblocking, 1);
        if (retval < 0)
                goto done;
 
@@ -799,7 +820,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
        spin_lock_irqsave(q->irqlock, flags);
        q->ops->buf_queue(q, q->read_buf);
        spin_unlock_irqrestore(q->irqlock, flags);
-       retval = videobuf_waiton(q->read_buf, 0, 0);
+       retval = videobuf_waiton(q, q->read_buf, 0, 0);
        if (0 == retval) {
                CALL(q, sync, q, q->read_buf);
                if (VIDEOBUF_ERROR == q->read_buf->state)
@@ -911,7 +932,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        }
 
        /* wait until capture is done */
-       retval = videobuf_waiton(q->read_buf, nonblocking, 1);
+       retval = videobuf_waiton(q, q->read_buf, nonblocking, 1);
        if (0 != retval)
                goto done;
 
@@ -1061,7 +1082,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
                        list_del(&q->read_buf->stream);
                        q->read_off = 0;
                }
-               rc = videobuf_waiton(q->read_buf, nonblocking, 1);
+               rc = videobuf_waiton(q, q->read_buf, nonblocking, 1);
                if (rc < 0) {
                        if (0 == retval)
                                retval = rc;
index 3f76398968b8e00eab33776bb5400bdfeab0b56b..3de7c7e4402de7f461c1eb4a41bde553f9062ada 100644 (file)
@@ -57,7 +57,7 @@ static int videobuf_dvb_thread(void *data)
                buf = list_entry(dvb->dvbq.stream.next,
                                 struct videobuf_buffer, stream);
                list_del(&buf->stream);
-               err = videobuf_waiton(buf,0,1);
+               err = videobuf_waiton(&dvb->dvbq, buf, 0, 1);
 
                /* no more feeds left or stop_feed() asked us to quit */
                if (0 == dvb->nfeeds)
index c487c19256b94af7710db77d41ff9f5d850fa9f2..03391f41339786190e22797584cfabbf6b402f1a 100644 (file)
@@ -1319,7 +1319,7 @@ void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf)
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
 
        BUG_ON(in_interrupt());
-       videobuf_waiton(&buf->vb, 0, 0);
+       videobuf_waiton(q, &buf->vb, 0, 0);
        videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
index fd48b38e797c7c76965f3dc21695e84b6c56db55..b996697e7eb2095cb2eafa3abe4dd8ee87745b60 100644 (file)
@@ -293,7 +293,7 @@ static void
 dt3155_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
        if (vb->state == VIDEOBUF_ACTIVE)
-               videobuf_waiton(vb, 0, 0); /* FIXME: cannot be interrupted */
+               videobuf_waiton(q, vb, 0, 0); /* FIXME: cannot be interrupted */
        videobuf_dma_contig_free(q, vb);
        vb->state = VIDEOBUF_NEEDS_INIT;
 }
@@ -440,7 +440,7 @@ dt3155_open(struct file *filp)
                videobuf_queue_dma_contig_init(pd->vidq, &vbq_ops,
                                &pd->pdev->dev, &pd->lock,
                                V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
-                               sizeof(struct videobuf_buffer), pd);
+                               sizeof(struct videobuf_buffer), pd, NULL);
                /* disable all irqs, clear all irq flags */
                iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
                                                pd->regs + INT_CSR);
@@ -494,7 +494,7 @@ dt3155_release(struct file *filp)
                tmp = pd->curr_buf;
                spin_unlock_irqrestore(&pd->lock, flags);
                if (tmp)
-                       videobuf_waiton(tmp, 0, 1); /* block, interruptible */
+                       videobuf_waiton(pd->vidq, tmp, 0, 1); /* block, interruptible */
                dt3155_stop_acq(pd);
                videobuf_stop(pd->vidq);
                pd->acq_fp = NULL;
@@ -603,7 +603,7 @@ dt3155_ioc_streamoff(struct file *filp, void *p, enum v4l2_buf_type type)
        tmp = pd->curr_buf;
        spin_unlock_irqrestore(&pd->lock, flags);
        if (tmp)
-               videobuf_waiton(tmp, 0, 1); /* block, interruptible */
+               videobuf_waiton(pd->vidq, tmp, 0, 1); /* block, interruptible */
        return ret;
 }
 
index 9a4194557e4a499cdcefe0c6143825b54984d0c2..1d3835fc26be0d4a7e20408fb9b242f70f30a459 100644 (file)
@@ -180,7 +180,8 @@ static inline void videobuf_queue_unlock(struct videobuf_queue *q)
                mutex_unlock(&q->vb_lock);
 }
 
-int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr);
+int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb,
+               int non_blocking, int intr);
 int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
                struct v4l2_framebuffer *fbuf);