Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelv...
[pandora-kernel.git] / drivers / media / video / soc_camera.c
index a499cac..43848a7 100644 (file)
@@ -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;
+
+       mutex_lock(&icd->vb_vidq.vb_lock);
 
-       if (icf->vb_vidq.bufs[0]) {
+       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);
@@ -898,11 +896,11 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
        icl->board_info->platform_data = icd;
 
        subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
-                               icl->module_name, icl->board_info, NULL);
+                               NULL, icl->board_info, NULL);
        if (!subdev)
                goto ei2cnd;
 
-       client = subdev->priv;
+       client = v4l2_get_subdevdata(subdev);
 
        /* Use to_i2c_client(dev) to recover the i2c client */
        dev_set_drvdata(&icd->dev, &client->dev);
@@ -1148,6 +1146,20 @@ static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
        return v4l2_subdev_call(sd, video, s_crop, a);
 }
 
+static int default_g_parm(struct soc_camera_device *icd,
+                         struct v4l2_streamparm *parm)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       return v4l2_subdev_call(sd, video, g_parm, parm);
+}
+
+static int default_s_parm(struct soc_camera_device *icd,
+                         struct v4l2_streamparm *parm)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       return v4l2_subdev_call(sd, video, s_parm, parm);
+}
+
 static void soc_camera_device_init(struct device *dev, void *pdata)
 {
        dev->platform_data      = pdata;
@@ -1179,6 +1191,10 @@ int soc_camera_host_register(struct soc_camera_host *ici)
                ici->ops->get_crop = default_g_crop;
        if (!ici->ops->cropcap)
                ici->ops->cropcap = default_cropcap;
+       if (!ici->ops->set_parm)
+               ici->ops->set_parm = default_s_parm;
+       if (!ici->ops->get_parm)
+               ici->ops->get_parm = default_g_parm;
 
        mutex_lock(&list_lock);
        list_for_each_entry(ix, &hosts, list) {