V4L/DVB (6583): Fix em28xx read stream locking
authorMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 11 Nov 2007 04:08:26 +0000 (01:08 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Fri, 25 Jan 2008 21:02:06 +0000 (19:02 -0200)
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>
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h

index 5b17ca9cad1181ef8f465367e232b21bf8300eff..f0191779a8e2c9588c4b120cfed18160721df999 100644 (file)
@@ -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);
 
index f8ad0f4ae6d202c237c311166b23daa99505b494..3efc05d2df678567d7b751842c68dde7d2ea4c51 100644 (file)
@@ -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 */