diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 5b17ca9cad11..f0191779a8e2 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -225,6 +225,44 @@ static void video_mux(struct em28xx *dev, int index) } } +/* Usage lock check functions */ +static int res_get(struct em28xx_fh *fh) +{ + struct em28xx *dev = fh->dev; + int rc = 0; + + /* This instance already has stream_on */ + if (fh->stream_on) + return rc; + + mutex_lock(&dev->lock); + + if (dev->stream_on) + rc = -EINVAL; + else { + dev->stream_on = 1; + fh->stream_on = 1; + } + + mutex_unlock(&dev->lock); + return rc; +} + +static int res_check(struct em28xx_fh *fh) +{ + return (fh->stream_on); +} + +static void res_free(struct em28xx_fh *fh) +{ + struct em28xx *dev = fh->dev; + + mutex_lock(&dev->lock); + fh->stream_on = 0; + dev->stream_on = 0; + mutex_unlock(&dev->lock); +} + /* * em28xx_v4l2_open() * inits the device and starts isoc transfer @@ -328,15 +366,16 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) em28xx_videodbg("users=%d\n", dev->users); + + if (res_check(fh)) + res_free(fh); + mutex_lock(&dev->lock); - if (fh->reader == 1) - fh->reader = 0; if (dev->users == 1) { - dev->reader = 0; - em28xx_uninit_isoc(dev); em28xx_release_buffers(dev); + dev->io = IO_NONE; /* the device is already disconnect, free the remaining resources */ @@ -377,16 +416,15 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; + + if (unlikely(res_get(fh) < 0)) + return -EBUSY; + mutex_lock(&dev->lock); if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); - if (dev->reader > 0 && fh->reader == 0) { - mutex_unlock(&dev->lock); - return -EBUSY; - } - if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); em28xx_videodbg("not supported yet! ...\n"); @@ -425,9 +463,6 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, " the device again to choose the read method\n"); mutex_unlock(&dev->lock); return -EINVAL; - } else { - dev->reader = 1; - fh->reader = 1; } if (dev->io == IO_NONE) { @@ -499,6 +534,9 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; + if (unlikely(res_get(fh) < 0)) + return POLLERR; + mutex_lock(&dev->lock); if (dev->state & DEV_DISCONNECTED) { @@ -572,15 +610,10 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) void *pos; u32 i; - mutex_lock(&dev->lock); - - if (dev->reader > 0 && fh->reader == 0) { - mutex_unlock(&dev->lock); + if (unlikely(res_get(fh) < 0)) return -EBUSY; - } else { - dev->reader = 1; - fh->reader = 1; - } + + mutex_lock(&dev->lock); if (dev->state & DEV_DISCONNECTED) { em28xx_videodbg("mmap: device not present\n"); @@ -1219,6 +1252,9 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, if (list_empty(&dev->inqueue)) return -EINVAL; + if (unlikely(res_get(fh) < 0)) + return -EBUSY; + dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ em28xx_videodbg("VIDIOC_STREAMON: starting stream\n"); @@ -1243,7 +1279,6 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, } } - fh->reader = 0; em28xx_empty_framequeues(dev); mutex_unlock(&dev->lock); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index f8ad0f4ae6d2..3efc05d2df67 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -224,6 +224,8 @@ struct em28xx { unsigned int has_msp34xx:1; unsigned int has_tda9887:1; + unsigned int stream_on:1; /* Locks streams */ + u32 i2s_speed; /* I2S speed for audio digital stream */ enum em28xx_decoder decoder; @@ -258,7 +260,6 @@ struct em28xx { int vscale; /* vertical scale factor (see datasheet) */ int interlaced; /* 1=interlace fileds, 0=just top fileds */ int type; - unsigned int reader:1; unsigned long hash; /* eeprom hash - for boards with generic ID */ unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ @@ -297,7 +298,7 @@ struct em28xx { struct em28xx_fh { struct em28xx *dev; - unsigned int reader:1; + unsigned int stream_on:1; /* Locks streams */ }; /* Provided by em28xx-i2c.c */