[media] zr364xx: allow multiple opens
authorHans Verkuil <hans.verkuil@cisco.com>
Sat, 2 Jun 2012 11:50:31 +0000 (08:50 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 21 Jun 2012 14:27:21 +0000 (11:27 -0300)
This driver allowed only one open filehandle. This is against the spec, so
fix the driver by assigning proper ownership when streaming.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/zr364xx.c

index bdf562dbaf02ab88a0ca883bb401ce97eacb67d4..333f696e7fcf03d9fcd52852b613d5694906e69e 100644 (file)
@@ -175,6 +175,7 @@ struct zr364xx_camera {
        struct v4l2_device v4l2_dev;
        struct v4l2_ctrl_handler ctrl_handler;
        struct video_device vdev;       /* v4l video device */
+       struct v4l2_fh *owner;          /* owns the streaming */
        int nb;
        struct zr364xx_bufferi          buffer;
        int skip;
@@ -182,11 +183,9 @@ struct zr364xx_camera {
        int height;
        int method;
        struct mutex lock;
-       int users;
 
        spinlock_t              slock;
        struct zr364xx_dmaqueue vidq;
-       int                     resources;
        int                     last_frame;
        int                     cur_frame;
        unsigned long           frame_count;
@@ -474,9 +473,11 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count,
        if (mutex_lock_interruptible(&cam->lock))
                return -ERESTARTSYS;
 
-       if (zr364xx_vidioc_streamon(file, cam, V4L2_BUF_TYPE_VIDEO_CAPTURE) == 0) {
-               DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count,
-                   (int) *ppos);
+       err = zr364xx_vidioc_streamon(file, file->private_data,
+                               V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       if (err == 0) {
+               DBG("%s: reading %d bytes at pos %d.\n", __func__,
+                               (int) count, (int) *ppos);
 
                /* NoMan Sux ! */
                err = videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
@@ -698,30 +699,6 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
        return 0;
 }
 
-static int res_get(struct zr364xx_camera *cam)
-{
-       /* is it free? */
-       if (cam->resources) {
-               /* no, someone else uses it */
-               return 0;
-       }
-       /* it's free, grab it */
-       cam->resources = 1;
-       _DBG("res: get\n");
-       return 1;
-}
-
-static inline int res_check(struct zr364xx_camera *cam)
-{
-       return cam->resources;
-}
-
-static void res_free(struct zr364xx_camera *cam)
-{
-       cam->resources = 0;
-       _DBG("res: put\n");
-}
-
 static int zr364xx_vidioc_querycap(struct file *file, void *priv,
                                   struct v4l2_capability *cap)
 {
@@ -877,7 +854,7 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                goto out;
        }
 
-       if (res_check(cam)) {
+       if (cam->owner) {
                DBG("%s can't change format after started\n", __func__);
                ret = -EBUSY;
                goto out;
@@ -885,7 +862,7 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 
        cam->width = f->fmt.pix.width;
        cam->height = f->fmt.pix.height;
-       dev_info(&cam->udev->dev, "%s: %dx%d mode selected\n", __func__,
+       DBG("%s: %dx%d mode selected\n", __func__,
                 cam->width, cam->height);
        f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
        f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
@@ -955,10 +932,11 @@ out:
 static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
                          struct v4l2_requestbuffers *p)
 {
-       int rc;
        struct zr364xx_camera *cam = video_drvdata(file);
-       rc = videobuf_reqbufs(&cam->vb_vidq, p);
-       return rc;
+
+       if (cam->owner && cam->owner != priv)
+               return -EBUSY;
+       return videobuf_reqbufs(&cam->vb_vidq, p);
 }
 
 static int zr364xx_vidioc_querybuf(struct file *file,
@@ -978,6 +956,8 @@ static int zr364xx_vidioc_qbuf(struct file *file,
        int rc;
        struct zr364xx_camera *cam = video_drvdata(file);
        _DBG("%s\n", __func__);
+       if (cam->owner && cam->owner != priv)
+               return -EBUSY;
        rc = videobuf_qbuf(&cam->vb_vidq, p);
        return rc;
 }
@@ -989,6 +969,8 @@ static int zr364xx_vidioc_dqbuf(struct file *file,
        int rc;
        struct zr364xx_camera *cam = video_drvdata(file);
        _DBG("%s\n", __func__);
+       if (cam->owner && cam->owner != priv)
+               return -EBUSY;
        rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
        return rc;
 }
@@ -1141,7 +1123,7 @@ static int zr364xx_vidioc_streamon(struct file *file, void *priv,
                                   enum v4l2_buf_type type)
 {
        struct zr364xx_camera *cam = video_drvdata(file);
-       int j;
+       int i, j;
        int res;
 
        DBG("%s\n", __func__);
@@ -1149,11 +1131,21 @@ static int zr364xx_vidioc_streamon(struct file *file, void *priv,
        if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       if (!res_get(cam)) {
-               dev_err(&cam->udev->dev, "stream busy\n");
+       if (cam->owner && cam->owner != priv)
                return -EBUSY;
+
+       for (i = 0; init[cam->method][i].size != -1; i++) {
+               res = send_control_msg(cam->udev, 1, init[cam->method][i].value,
+                                    0, init[cam->method][i].bytes,
+                                    init[cam->method][i].size);
+               if (res < 0) {
+                       dev_err(&cam->udev->dev,
+                               "error during open sequence: %d\n", i);
+                       return res;
+               }
        }
 
+       cam->skip = 2;
        cam->last_frame = -1;
        cam->cur_frame = 0;
        cam->frame_count = 0;
@@ -1164,8 +1156,7 @@ static int zr364xx_vidioc_streamon(struct file *file, void *priv,
        res = videobuf_streamon(&cam->vb_vidq);
        if (res == 0) {
                zr364xx_start_acquire(cam);
-       } else {
-               res_free(cam);
+               cam->owner = file->private_data;
        }
        return res;
 }
@@ -1173,18 +1164,15 @@ static int zr364xx_vidioc_streamon(struct file *file, void *priv,
 static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
                                    enum v4l2_buf_type type)
 {
-       int res;
        struct zr364xx_camera *cam = video_drvdata(file);
 
        DBG("%s\n", __func__);
        if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
+       if (cam->owner && cam->owner != priv)
+               return -EBUSY;
        zr364xx_stop_acquire(cam);
-       res = videobuf_streamoff(&cam->vb_vidq);
-       if (res < 0)
-               return res;
-       res_free(cam);
-       return 0;
+       return videobuf_streamoff(&cam->vb_vidq);
 }
 
 
@@ -1192,46 +1180,17 @@ static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
 static int zr364xx_open(struct file *file)
 {
        struct zr364xx_camera *cam = video_drvdata(file);
-       struct usb_device *udev = cam->udev;
-       int i, err;
+       int err;
 
        DBG("%s\n", __func__);
 
        if (mutex_lock_interruptible(&cam->lock))
                return -ERESTARTSYS;
 
-       if (cam->users) {
-               err = -EBUSY;
-               goto out;
-       }
-
        err = v4l2_fh_open(file);
        if (err)
                goto out;
 
-       for (i = 0; init[cam->method][i].size != -1; i++) {
-               err =
-                   send_control_msg(udev, 1, init[cam->method][i].value,
-                                    0, init[cam->method][i].bytes,
-                                    init[cam->method][i].size);
-               if (err < 0) {
-                       dev_err(&cam->udev->dev,
-                               "error during open sequence: %d\n", i);
-                       v4l2_fh_release(file);
-                       goto out;
-               }
-       }
-
-       cam->skip = 2;
-       cam->users++;
-       cam->fmt = formats;
-
-       videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
-                                   NULL, &cam->slock,
-                                   V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                                   V4L2_FIELD_NONE,
-                                   sizeof(struct zr364xx_buffer), cam, &cam->lock);
-
        /* Added some delay here, since opening/closing the camera quickly,
         * like Ekiga does during its startup, can crash the webcam
         */
@@ -1282,20 +1241,18 @@ static int zr364xx_close(struct file *file)
        mutex_lock(&cam->lock);
        udev = cam->udev;
 
-       /* turn off stream */
-       if (res_check(cam)) {
+       if (file->private_data == cam->owner) {
+               /* turn off stream */
                if (cam->b_acquire)
                        zr364xx_stop_acquire(cam);
                videobuf_streamoff(&cam->vb_vidq);
-               res_free(cam);
-       }
 
-       cam->users--;
-
-       for (i = 0; i < 2; i++) {
-               send_control_msg(udev, 1, init[cam->method][i].value,
-                                    0, init[cam->method][i].bytes,
-                                    init[cam->method][i].size);
+               for (i = 0; i < 2; i++) {
+                       send_control_msg(udev, 1, init[cam->method][i].value,
+                                       0, init[cam->method][i].bytes,
+                                       init[cam->method][i].size);
+               }
+               cam->owner = NULL;
        }
 
        /* Added some delay here, since opening/closing the camera quickly,
@@ -1490,6 +1447,7 @@ static int zr364xx_probe(struct usb_interface *intf,
        cam->vdev.lock = &cam->lock;
        cam->vdev.v4l2_dev = &cam->v4l2_dev;
        cam->vdev.ctrl_handler = &cam->ctrl_handler;
+       set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
        video_set_drvdata(&cam->vdev, cam);
        if (debug)
                cam->vdev.debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
@@ -1538,7 +1496,6 @@ static int zr364xx_probe(struct usb_interface *intf,
        header2[439] = cam->width / 256;
        header2[440] = cam->width % 256;
 
-       cam->users = 0;
        cam->nb = 0;
 
        DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
@@ -1575,6 +1532,14 @@ static int zr364xx_probe(struct usb_interface *intf,
 
        spin_lock_init(&cam->slock);
 
+       cam->fmt = formats;
+
+       videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
+                                   NULL, &cam->slock,
+                                   V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                                   V4L2_FIELD_NONE,
+                                   sizeof(struct zr364xx_buffer), cam, &cam->lock);
+
        err = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
        if (err) {
                dev_err(&udev->dev, "video_register_device failed\n");