Commit a065729d authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

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