Commit 1a0063a9 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab

V4L/DVB (7501): soc-camera: use a spinlock for videobuffer queue

All drivers should provide a spinlock to be used in videobuf operations.
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@pengutronix.de>
Reviewed-by: default avatarBrandon Philips <bphilips@suse.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent b8d9904c
...@@ -803,6 +803,15 @@ static int pxa_camera_querycap(struct soc_camera_host *ici, ...@@ -803,6 +803,15 @@ static int pxa_camera_querycap(struct soc_camera_host *ici,
return 0; 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 = { static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.add = pxa_camera_add_device, .add = pxa_camera_add_device,
...@@ -814,6 +823,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = { ...@@ -814,6 +823,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.querycap = pxa_camera_querycap, .querycap = pxa_camera_querycap,
.try_bus_param = pxa_camera_try_bus_param, .try_bus_param = pxa_camera_try_bus_param,
.set_bus_param = pxa_camera_set_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. */ /* Should be allocated dynamically too, but we have only one. */
......
...@@ -184,6 +184,7 @@ static int soc_camera_open(struct inode *inode, struct file *file) ...@@ -184,6 +184,7 @@ static int soc_camera_open(struct inode *inode, struct file *file)
struct soc_camera_device *icd; struct soc_camera_device *icd;
struct soc_camera_host *ici; struct soc_camera_host *ici;
struct soc_camera_file *icf; struct soc_camera_file *icf;
spinlock_t *lock;
int ret; int ret;
icf = vmalloc(sizeof(*icf)); icf = vmalloc(sizeof(*icf));
...@@ -209,10 +210,16 @@ static int soc_camera_open(struct inode *inode, struct file *file) ...@@ -209,10 +210,16 @@ static int soc_camera_open(struct inode *inode, struct file *file)
goto emgi; goto emgi;
} }
icd->use_count++;
icf->icd = icd; 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 */ /* Now we really have to activate the camera */
if (icd->use_count == 1) { if (icd->use_count == 1) {
ret = ici->ops->add(icd); ret = ici->ops->add(icd);
...@@ -229,8 +236,8 @@ static int soc_camera_open(struct inode *inode, struct file *file) ...@@ -229,8 +236,8 @@ static int soc_camera_open(struct inode *inode, struct file *file)
dev_dbg(&icd->dev, "camera device open\n"); dev_dbg(&icd->dev, "camera device open\n");
/* We must pass NULL as dev pointer, then all pci_* dma operations /* We must pass NULL as dev pointer, then all pci_* dma operations
* transform to normal dma_* ones. Do we need an irqlock? */ * transform to normal dma_* ones. */
videobuf_queue_sg_init(&icf->vb_vidq, ici->vbq_ops, NULL, NULL, videobuf_queue_sg_init(&icf->vb_vidq, ici->vbq_ops, NULL, icf->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
ici->msize, icd); ici->msize, icd);
...@@ -238,6 +245,11 @@ static int soc_camera_open(struct inode *inode, struct file *file) ...@@ -238,6 +245,11 @@ static int soc_camera_open(struct inode *inode, struct file *file)
/* All errors are entered with the video_lock held */ /* All errors are entered with the video_lock held */
eiciadd: eiciadd:
lock = icf->lock;
icf->lock = NULL;
if (ici->ops->spinlock_free)
ici->ops->spinlock_free(lock);
esla:
module_put(ici->ops->owner); module_put(ici->ops->owner);
emgi: emgi:
module_put(icd->ops->owner); module_put(icd->ops->owner);
...@@ -253,16 +265,20 @@ static int soc_camera_close(struct inode *inode, struct file *file) ...@@ -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_device *icd = icf->icd;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct video_device *vdev = icd->vdev; struct video_device *vdev = icd->vdev;
spinlock_t *lock = icf->lock;
mutex_lock(&video_lock); mutex_lock(&video_lock);
icd->use_count--; icd->use_count--;
if (!icd->use_count) if (!icd->use_count)
ici->ops->remove(icd); ici->ops->remove(icd);
icf->lock = NULL;
if (ici->ops->spinlock_free)
ici->ops->spinlock_free(lock);
module_put(icd->ops->owner); module_put(icd->ops->owner);
module_put(ici->ops->owner); module_put(ici->ops->owner);
mutex_unlock(&video_lock); mutex_unlock(&video_lock);
vfree(file->private_data); vfree(icf);
dev_dbg(vdev->dev, "camera device close\n"); dev_dbg(vdev->dev, "camera device close\n");
...@@ -762,6 +778,21 @@ static void dummy_release(struct device *dev) ...@@ -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 soc_camera_host_register(struct soc_camera_host *ici)
{ {
int ret; int ret;
...@@ -792,6 +823,11 @@ int soc_camera_host_register(struct soc_camera_host *ici) ...@@ -792,6 +823,11 @@ int soc_camera_host_register(struct soc_camera_host *ici)
if (ret) if (ret)
goto edevr; goto edevr;
if (!ici->ops->spinlock_alloc) {
ici->ops->spinlock_alloc = spinlock_alloc;
ici->ops->spinlock_free = spinlock_free;
}
scan_add_host(ici); scan_add_host(ici);
return 0; return 0;
......
...@@ -48,6 +48,7 @@ struct soc_camera_device { ...@@ -48,6 +48,7 @@ struct soc_camera_device {
struct soc_camera_file { struct soc_camera_file {
struct soc_camera_device *icd; struct soc_camera_device *icd;
struct videobuf_queue vb_vidq; struct videobuf_queue vb_vidq;
spinlock_t *lock;
}; };
struct soc_camera_host { struct soc_camera_host {
...@@ -73,6 +74,8 @@ struct soc_camera_host_ops { ...@@ -73,6 +74,8 @@ struct soc_camera_host_ops {
int (*try_bus_param)(struct soc_camera_device *, __u32); int (*try_bus_param)(struct soc_camera_device *, __u32);
int (*set_bus_param)(struct soc_camera_device *, __u32); int (*set_bus_param)(struct soc_camera_device *, __u32);
unsigned int (*poll)(struct file *, poll_table *); unsigned int (*poll)(struct file *, poll_table *);
spinlock_t* (*spinlock_alloc)(struct soc_camera_file *);
void (*spinlock_free)(spinlock_t *);
}; };
struct soc_camera_link { struct soc_camera_link {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment