diff options
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 52 |
1 files changed, 35 insertions, 17 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 50f5f4f..ecb23df 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -2146,9 +2146,12 @@ static int em28xx_v4l2_open(struct file *filp) dev->users); + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); if (!fh) { em28xx_errdev("em28xx-video.c: Out of memory?!\n"); + mutex_unlock(&dev->lock); return -ENOMEM; } fh->dev = dev; @@ -2189,6 +2192,7 @@ static int em28xx_v4l2_open(struct file *filp) V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, sizeof(struct em28xx_buffer), fh, &dev->lock); + mutex_unlock(&dev->lock); return errCode; } @@ -2243,6 +2247,7 @@ static int em28xx_v4l2_close(struct file *filp) em28xx_videodbg("users=%d\n", dev->users); + mutex_lock(&dev->lock); if (res_check(fh, EM28XX_RESOURCE_VIDEO)) { videobuf_stop(&fh->vb_vidq); res_free(fh, EM28XX_RESOURCE_VIDEO); @@ -2261,6 +2266,7 @@ static int em28xx_v4l2_close(struct file *filp) kfree(dev->alt_max_pkt_size); kfree(dev); kfree(fh); + mutex_unlock(&dev->lock); return 0; } @@ -2285,6 +2291,7 @@ static int em28xx_v4l2_close(struct file *filp) videobuf_mmap_free(&fh->vb_vbiq); kfree(fh); dev->users--; + mutex_unlock(&dev->lock); return 0; } @@ -2304,35 +2311,35 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count, if (rc < 0) return rc; + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; /* FIXME: read() is not prepared to allow changing the video resolution while streaming. Seems a bug at em28xx_set_fmt */ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (res_locked(dev, EM28XX_RESOURCE_VIDEO)) - return -EBUSY; - - return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, + rc = -EBUSY; + else + rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, filp->f_flags & O_NONBLOCK); - } - - - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { if (!res_get(fh, EM28XX_RESOURCE_VBI)) - return -EBUSY; - - return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, + rc = -EBUSY; + else + rc = videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, filp->f_flags & O_NONBLOCK); } + mutex_unlock(&dev->lock); - return 0; + return rc; } /* - * em28xx_v4l2_poll() + * em28xx_poll() * will allocate buffers when called for the first time */ -static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait) +static unsigned int em28xx_poll(struct file *filp, poll_table *wait) { struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; @@ -2355,6 +2362,18 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait) } } +static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait) +{ + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + unsigned int res; + + mutex_lock(&dev->lock); + res = em28xx_poll(filp, wait); + mutex_unlock(&dev->lock); + return res; +} + /* * em28xx_v4l2_mmap() */ @@ -2368,10 +2387,13 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) if (rc < 0) return rc; + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma); + mutex_unlock(&dev->lock); em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n", (unsigned long)vma->vm_start, @@ -2495,10 +2517,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, vfd->release = video_device_release; vfd->debug = video_debug; vfd->lock = &dev->lock; - /* Locking in file operations other than ioctl should be done - by the driver, not the V4L2 core. - This driver needs auditing so that this flag can be removed. */ - set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags); snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); |