Browse Source

V4L/DVB (6583): Fix em28xx read stream locking

On some situations, closing an streaming application and re-opening were
returning -EBUSY.

Uses the same locking schema also present on cx88.

Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Mauro Carvalho Chehab 17 years ago
parent
commit
a225452ef8
2 changed files with 59 additions and 23 deletions
  1. 56 21
      drivers/media/video/em28xx/em28xx-video.c
  2. 3 2
      drivers/media/video/em28xx/em28xx.h

+ 56 - 21
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);
 

+ 3 - 2
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 */