summaryrefslogtreecommitdiff
path: root/drivers/media/video/soc_camera.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2010-08-17 14:29:51 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-21 01:06:18 -0200
commit57bee29d6e8cf721864fa47a18366bee5ff24f21 (patch)
treeeec0e9a15386db2bbe041f9e39d60075614c5adc /drivers/media/video/soc_camera.c
parent79c6ff93c74e793ccceb464ee3698478c812ce79 (diff)
V4L/DVB: soc-camera: allow only one video queue per device
Multiple user-space application instances can open the same video device, but it only makes sense for one of them to manage the videobuffer queue and set video format of the device. Restrict soc-camera respectively. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/soc_camera.c')
-rw-r--r--drivers/media/video/soc_camera.c178
1 files changed, 88 insertions, 90 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index a55d6dc4c6b..6876fdcbf8d 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -92,8 +92,7 @@ EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
WARN_ON(priv != file->private_data);
@@ -105,8 +104,7 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
static int soc_camera_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
int ret = 0;
if (inp->index != 0)
@@ -141,8 +139,7 @@ static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
return v4l2_subdev_call(sd, core, s_std, *a);
@@ -152,47 +149,59 @@ static int soc_camera_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
int ret;
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
WARN_ON(priv != file->private_data);
- ret = videobuf_reqbufs(&icf->vb_vidq, p);
+ if (icd->streamer && icd->streamer != file)
+ return -EBUSY;
+
+ ret = videobuf_reqbufs(&icd->vb_vidq, p);
if (ret < 0)
return ret;
- return ici->ops->reqbufs(icf, p);
+ ret = ici->ops->reqbufs(icd, p);
+ if (!ret && !icd->streamer)
+ icd->streamer = file;
+
+ return ret;
}
static int soc_camera_querybuf(struct file *file, void *priv,
struct v4l2_buffer *p)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
WARN_ON(priv != file->private_data);
- return videobuf_querybuf(&icf->vb_vidq, p);
+ return videobuf_querybuf(&icd->vb_vidq, p);
}
static int soc_camera_qbuf(struct file *file, void *priv,
struct v4l2_buffer *p)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
WARN_ON(priv != file->private_data);
- return videobuf_qbuf(&icf->vb_vidq, p);
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ return videobuf_qbuf(&icd->vb_vidq, p);
}
static int soc_camera_dqbuf(struct file *file, void *priv,
struct v4l2_buffer *p)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
WARN_ON(priv != file->private_data);
- return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK);
}
/* Always entered with .video_lock held */
@@ -280,10 +289,9 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
((x) >> 24) & 0xff
/* Called with .vb_lock held, or from the first open(2), see comment there */
-static int soc_camera_set_fmt(struct soc_camera_file *icf,
+static int soc_camera_set_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
- struct soc_camera_device *icd = icf->icd;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct v4l2_pix_format *pix = &f->fmt.pix;
int ret;
@@ -309,7 +317,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
icd->user_width = pix->width;
icd->user_height = pix->height;
icd->colorspace = pix->colorspace;
- icf->vb_vidq.field =
+ icd->vb_vidq.field =
icd->field = pix->field;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -331,7 +339,6 @@ static int soc_camera_open(struct file *file)
dev);
struct soc_camera_link *icl = to_soc_camera_link(icd);
struct soc_camera_host *ici;
- struct soc_camera_file *icf;
int ret;
if (!icd->ops)
@@ -340,14 +347,9 @@ static int soc_camera_open(struct file *file)
ici = to_soc_camera_host(icd->dev.parent);
- icf = vmalloc(sizeof(*icf));
- if (!icf)
- return -ENOMEM;
-
if (!try_module_get(ici->ops->owner)) {
dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
- ret = -EINVAL;
- goto emgi;
+ return -EINVAL;
}
/*
@@ -356,7 +358,6 @@ static int soc_camera_open(struct file *file)
*/
mutex_lock(&icd->video_lock);
- icf->icd = icd;
icd->use_count++;
/* Now we really have to activate the camera */
@@ -401,15 +402,15 @@ static int soc_camera_open(struct file *file)
* apart from someone else calling open() simultaneously, but
* .video_lock is protecting us against it.
*/
- ret = soc_camera_set_fmt(icf, &f);
+ ret = soc_camera_set_fmt(icd, &f);
if (ret < 0)
goto esfmt;
}
- file->private_data = icf;
+ file->private_data = icd;
dev_dbg(&icd->dev, "camera device open\n");
- ici->ops->init_videobuf(&icf->vb_vidq, icd);
+ ici->ops->init_videobuf(&icd->vb_vidq, icd);
mutex_unlock(&icd->video_lock);
@@ -430,15 +431,13 @@ epower:
icd->use_count--;
mutex_unlock(&icd->video_lock);
module_put(ici->ops->owner);
-emgi:
- vfree(icf);
+
return ret;
}
static int soc_camera_close(struct file *file)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
mutex_lock(&icd->video_lock);
@@ -455,12 +454,13 @@ static int soc_camera_close(struct file *file)
icl->power(icd->pdev, 0);
}
+ if (icd->streamer == file)
+ icd->streamer = NULL;
+
mutex_unlock(&icd->video_lock);
module_put(ici->ops->owner);
- vfree(icf);
-
dev_dbg(&icd->dev, "camera device close\n");
return 0;
@@ -469,8 +469,7 @@ static int soc_camera_close(struct file *file)
static ssize_t soc_camera_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
int err = -EINVAL;
dev_err(&icd->dev, "camera device read not implemented\n");
@@ -480,13 +479,15 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf,
static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
int err;
dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
- err = videobuf_mmap_mapper(&icf->vb_vidq, vma);
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ err = videobuf_mmap_mapper(&icd->vb_vidq, vma);
dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
(unsigned long)vma->vm_start,
@@ -498,11 +499,13 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- if (list_empty(&icf->vb_vidq.stream)) {
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ if (list_empty(&icd->vb_vidq.stream)) {
dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
return POLLERR;
}
@@ -523,24 +526,29 @@ static struct v4l2_file_operations soc_camera_fops = {
static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
int ret;
WARN_ON(priv != file->private_data);
- mutex_lock(&icf->vb_vidq.vb_lock);
+ if (icd->streamer && icd->streamer != file)
+ return -EBUSY;
- if (icf->vb_vidq.bufs[0]) {
+ mutex_lock(&icd->vb_vidq.vb_lock);
+
+ if (icd->vb_vidq.bufs[0]) {
dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
ret = -EBUSY;
goto unlock;
}
- ret = soc_camera_set_fmt(icf, f);
+ ret = soc_camera_set_fmt(icd, f);
+
+ if (!ret && !icd->streamer)
+ icd->streamer = file;
unlock:
- mutex_unlock(&icf->vb_vidq.vb_lock);
+ mutex_unlock(&icd->vb_vidq.vb_lock);
return ret;
}
@@ -548,8 +556,7 @@ unlock:
static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
const struct soc_mbus_pixelfmt *format;
WARN_ON(priv != file->private_data);
@@ -568,15 +575,14 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_pix_format *pix = &f->fmt.pix;
WARN_ON(priv != file->private_data);
pix->width = icd->user_width;
pix->height = icd->user_height;
- pix->field = icf->vb_vidq.field;
+ pix->field = icd->vb_vidq.field;
pix->pixelformat = icd->current_fmt->host_fmt->fourcc;
pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
icd->current_fmt->host_fmt);
@@ -592,8 +598,7 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
static int soc_camera_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
WARN_ON(priv != file->private_data);
@@ -605,8 +610,7 @@ static int soc_camera_querycap(struct file *file, void *priv,
static int soc_camera_streamon(struct file *file, void *priv,
enum v4l2_buf_type i)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
int ret;
@@ -615,12 +619,15 @@ static int soc_camera_streamon(struct file *file, void *priv,
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ if (icd->streamer != file)
+ return -EBUSY;
+
mutex_lock(&icd->video_lock);
v4l2_subdev_call(sd, video, s_stream, 1);
/* This calls buf_queue from host driver's videobuf_queue_ops */
- ret = videobuf_streamon(&icf->vb_vidq);
+ ret = videobuf_streamon(&icd->vb_vidq);
mutex_unlock(&icd->video_lock);
@@ -630,8 +637,7 @@ static int soc_camera_streamon(struct file *file, void *priv,
static int soc_camera_streamoff(struct file *file, void *priv,
enum v4l2_buf_type i)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
WARN_ON(priv != file->private_data);
@@ -639,13 +645,16 @@ static int soc_camera_streamoff(struct file *file, void *priv,
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ if (icd->streamer != file)
+ return -EBUSY;
+
mutex_lock(&icd->video_lock);
/*
* This calls buf_release from host driver's videobuf_queue_ops for all
* remaining buffers. When the last buffer is freed, stop capture
*/
- videobuf_streamoff(&icf->vb_vidq);
+ videobuf_streamoff(&icd->vb_vidq);
v4l2_subdev_call(sd, video, s_stream, 0);
@@ -657,8 +666,7 @@ static int soc_camera_streamoff(struct file *file, void *priv,
static int soc_camera_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int i;
@@ -689,8 +697,7 @@ static int soc_camera_queryctrl(struct file *file, void *priv,
static int soc_camera_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
int ret;
@@ -709,8 +716,7 @@ static int soc_camera_g_ctrl(struct file *file, void *priv,
static int soc_camera_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
int ret;
@@ -729,8 +735,7 @@ static int soc_camera_s_ctrl(struct file *file, void *priv,
static int soc_camera_cropcap(struct file *file, void *fh,
struct v4l2_cropcap *a)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
return ici->ops->cropcap(icd, a);
@@ -739,14 +744,13 @@ static int soc_camera_cropcap(struct file *file, void *fh,
static int soc_camera_g_crop(struct file *file, void *fh,
struct v4l2_crop *a)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int ret;
- mutex_lock(&icf->vb_vidq.vb_lock);
+ mutex_lock(&icd->vb_vidq.vb_lock);
ret = ici->ops->get_crop(icd, a);
- mutex_unlock(&icf->vb_vidq.vb_lock);
+ mutex_unlock(&icd->vb_vidq.vb_lock);
return ret;
}
@@ -759,8 +763,7 @@ static int soc_camera_g_crop(struct file *file, void *fh,
static int soc_camera_s_crop(struct file *file, void *fh,
struct v4l2_crop *a)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct v4l2_rect *rect = &a->c;
struct v4l2_crop current_crop;
@@ -773,7 +776,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
rect->width, rect->height, rect->left, rect->top);
/* Cropping is allowed during a running capture, guard consistency */
- mutex_lock(&icf->vb_vidq.vb_lock);
+ mutex_lock(&icd->vb_vidq.vb_lock);
/* If get_crop fails, we'll let host and / or client drivers decide */
ret = ici->ops->get_crop(icd, &current_crop);
@@ -782,7 +785,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
if (ret < 0) {
dev_err(&icd->dev,
"S_CROP denied: getting current crop failed\n");
- } else if (icf->vb_vidq.bufs[0] &&
+ } else if (icd->vb_vidq.bufs[0] &&
(a->c.width != current_crop.c.width ||
a->c.height != current_crop.c.height)) {
dev_err(&icd->dev,
@@ -792,7 +795,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
ret = ici->ops->set_crop(icd, a);
}
- mutex_unlock(&icf->vb_vidq.vb_lock);
+ mutex_unlock(&icd->vb_vidq.vb_lock);
return ret;
}
@@ -800,8 +803,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
static int soc_camera_g_parm(struct file *file, void *fh,
struct v4l2_streamparm *a)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
if (ici->ops->get_parm)
@@ -813,8 +815,7 @@ static int soc_camera_g_parm(struct file *file, void *fh,
static int soc_camera_s_parm(struct file *file, void *fh,
struct v4l2_streamparm *a)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
if (ici->ops->set_parm)
@@ -826,8 +827,7 @@ static int soc_camera_s_parm(struct file *file, void *fh,
static int soc_camera_g_chip_ident(struct file *file, void *fh,
struct v4l2_dbg_chip_ident *id)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
return v4l2_subdev_call(sd, core, g_chip_ident, id);
@@ -837,8 +837,7 @@ static int soc_camera_g_chip_ident(struct file *file, void *fh,
static int soc_camera_g_register(struct file *file, void *fh,
struct v4l2_dbg_register *reg)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
return v4l2_subdev_call(sd, core, g_register, reg);
@@ -847,8 +846,7 @@ static int soc_camera_g_register(struct file *file, void *fh,
static int soc_camera_s_register(struct file *file, void *fh,
struct v4l2_dbg_register *reg)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
return v4l2_subdev_call(sd, core, s_register, reg);