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

[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
Loading
Loading
Loading
Loading
+51 −86
Original line number Diff line number Diff line
@@ -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 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
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,21 +1241,19 @@ static int zr364xx_close(struct file *file)
	mutex_lock(&cam->lock);
	udev = cam->udev;

	if (file->private_data == cam->owner) {
		/* turn off stream */
	if (res_check(cam)) {
		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);
		}
		cam->owner = NULL;
	}

	/* Added some delay here, since opening/closing the camera quickly,
	 * like Ekiga does during its startup, can crash the webcam
@@ -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");