Skip to content

Commit

Permalink
[media] zr364xx: allow multiple opens
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Hans Verkuil authored and Mauro Carvalho Chehab committed Jun 21, 2012
1 parent 5d317ab commit a065729
Showing 1 changed file with 51 additions and 86 deletions.
137 changes: 51 additions & 86 deletions drivers/media/video/zr364xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,18 +175,17 @@ 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;
int width;
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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -877,15 +854,15 @@ 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;
}

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;
Expand Down Expand Up @@ -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,
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -1141,19 +1123,29 @@ 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__);

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;
Expand All @@ -1164,74 +1156,41 @@ 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;
}

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);
}


/* open the camera */
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
*/
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit a065729

Please sign in to comment.