diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-06-02 08:50:31 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-06-21 11:27:21 -0300 |
commit | a065729d1224641f056688c57745fdd469714e22 (patch) | |
tree | 2b0389f8dfa321baaa693949b31cbdc00f3befca /drivers/media/video/zr364xx.c | |
parent | 5d317abe7bd1b448efaa4ad0813c19f866aa7a4b (diff) |
[media] zr364xx: allow multiple opens
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>
Diffstat (limited to 'drivers/media/video/zr364xx.c')
-rw-r--r-- | drivers/media/video/zr364xx.c | 137 |
1 files changed, 51 insertions, 86 deletions
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index bdf562dbaf0..333f696e7fc 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -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"); |