V4L/DVB (7501): soc-camera: use a spinlock for videobuffer queue
authorGuennadi Liakhovetski <g.liakhovetski@pengutronix.de>
Fri, 4 Apr 2008 16:46:34 +0000 (13:46 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Thu, 24 Apr 2008 17:07:57 +0000 (14:07 -0300)
All drivers should provide a spinlock to be used in videobuf operations.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de>
Reviewed-by: Brandon Philips <bphilips@suse.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/pxa_camera.c
drivers/media/video/soc_camera.c
include/media/soc_camera.h

index 9758f7eb59321f32c5e65122e3a8f637ca65110e..bef3c9c7902aae4b8ed5ec7f1835aea216999ab6 100644 (file)
@@ -803,6 +803,15 @@ static int pxa_camera_querycap(struct soc_camera_host *ici,
        return 0;
 }
 
+static spinlock_t *pxa_camera_spinlock_alloc(struct soc_camera_file *icf)
+{
+       struct soc_camera_host *ici =
+               to_soc_camera_host(icf->icd->dev.parent);
+       struct pxa_camera_dev *pcdev = ici->priv;
+
+       return &pcdev->lock;
+}
+
 static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .owner          = THIS_MODULE,
        .add            = pxa_camera_add_device,
@@ -814,6 +823,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .querycap       = pxa_camera_querycap,
        .try_bus_param  = pxa_camera_try_bus_param,
        .set_bus_param  = pxa_camera_set_bus_param,
+       .spinlock_alloc = pxa_camera_spinlock_alloc,
 };
 
 /* Should be allocated dynamically too, but we have only one. */
index 43c8110599e8c2a063d8f7f0688fe0e8793a7c7d..1e921578804fec7262a85a112b2130eb665f096e 100644 (file)
@@ -184,6 +184,7 @@ static int soc_camera_open(struct inode *inode, struct file *file)
        struct soc_camera_device *icd;
        struct soc_camera_host *ici;
        struct soc_camera_file *icf;
+       spinlock_t *lock;
        int ret;
 
        icf = vmalloc(sizeof(*icf));
@@ -209,10 +210,16 @@ static int soc_camera_open(struct inode *inode, struct file *file)
                goto emgi;
        }
 
-       icd->use_count++;
-
        icf->icd = icd;
 
+       icf->lock = ici->ops->spinlock_alloc(icf);
+       if (!icf->lock) {
+               ret = -ENOMEM;
+               goto esla;
+       }
+
+       icd->use_count++;
+
        /* Now we really have to activate the camera */
        if (icd->use_count == 1) {
                ret = ici->ops->add(icd);
@@ -229,8 +236,8 @@ static int soc_camera_open(struct inode *inode, struct file *file)
        dev_dbg(&icd->dev, "camera device open\n");
 
        /* We must pass NULL as dev pointer, then all pci_* dma operations
-        * transform to normal dma_* ones. Do we need an irqlock? */
-       videobuf_queue_sg_init(&icf->vb_vidq, ici->vbq_ops, NULL, NULL,
+        * transform to normal dma_* ones. */
+       videobuf_queue_sg_init(&icf->vb_vidq, ici->vbq_ops, NULL, icf->lock,
                                V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
                                ici->msize, icd);
 
@@ -238,6 +245,11 @@ static int soc_camera_open(struct inode *inode, struct file *file)
 
        /* All errors are entered with the video_lock held */
 eiciadd:
+       lock = icf->lock;
+       icf->lock = NULL;
+       if (ici->ops->spinlock_free)
+               ici->ops->spinlock_free(lock);
+esla:
        module_put(ici->ops->owner);
 emgi:
        module_put(icd->ops->owner);
@@ -253,16 +265,20 @@ static int soc_camera_close(struct inode *inode, struct file *file)
        struct soc_camera_device *icd = icf->icd;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct video_device *vdev = icd->vdev;
+       spinlock_t *lock = icf->lock;
 
        mutex_lock(&video_lock);
        icd->use_count--;
        if (!icd->use_count)
                ici->ops->remove(icd);
+       icf->lock = NULL;
+       if (ici->ops->spinlock_free)
+               ici->ops->spinlock_free(lock);
        module_put(icd->ops->owner);
        module_put(ici->ops->owner);
        mutex_unlock(&video_lock);
 
-       vfree(file->private_data);
+       vfree(icf);
 
        dev_dbg(vdev->dev, "camera device close\n");
 
@@ -762,6 +778,21 @@ static void dummy_release(struct device *dev)
 {
 }
 
+static spinlock_t *spinlock_alloc(struct soc_camera_file *icf)
+{
+       spinlock_t *lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+
+       if (lock)
+               spin_lock_init(lock);
+
+       return lock;
+}
+
+static void spinlock_free(spinlock_t *lock)
+{
+       kfree(lock);
+}
+
 int soc_camera_host_register(struct soc_camera_host *ici)
 {
        int ret;
@@ -792,6 +823,11 @@ int soc_camera_host_register(struct soc_camera_host *ici)
        if (ret)
                goto edevr;
 
+       if (!ici->ops->spinlock_alloc) {
+               ici->ops->spinlock_alloc = spinlock_alloc;
+               ici->ops->spinlock_free = spinlock_free;
+       }
+
        scan_add_host(ici);
 
        return 0;
index 80e1193c07d5fea9c936ac92ff90935526c406a3..6a8c8be7a1aed7694aac8148b605a3f8448f1a59 100644 (file)
@@ -48,6 +48,7 @@ struct soc_camera_device {
 struct soc_camera_file {
        struct soc_camera_device *icd;
        struct videobuf_queue vb_vidq;
+       spinlock_t *lock;
 };
 
 struct soc_camera_host {
@@ -73,6 +74,8 @@ struct soc_camera_host_ops {
        int (*try_bus_param)(struct soc_camera_device *, __u32);
        int (*set_bus_param)(struct soc_camera_device *, __u32);
        unsigned int (*poll)(struct file *, poll_table *);
+       spinlock_t* (*spinlock_alloc)(struct soc_camera_file *);
+       void (*spinlock_free)(spinlock_t *);
 };
 
 struct soc_camera_link {