[media] tm6000: fix resource locking
authorMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 11 Oct 2010 13:48:11 +0000 (10:48 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 21 Oct 2010 13:36:26 +0000 (11:36 -0200)
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/staging/tm6000/tm6000-video.c
drivers/staging/tm6000/tm6000.h

index 4a5fe6670fb4153ee83b66a49acb0cd61949ef6d..cb251af895b85828676ec6d191c23220f1503957 100644 (file)
@@ -788,25 +788,49 @@ static struct videobuf_queue_ops tm6000_video_qops = {
        IOCTL handling
    ------------------------------------------------------------------*/
 
-static int res_get(struct tm6000_core *dev, struct tm6000_fh *fh)
+static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh)
 {
-       /* is it free? */
-       if (dev->resources)
-               return 0;
-       /* it's free, grab it */
-       dev->resources =1;
-       dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
-       return 1;
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources == fh && dev->is_res_read)
+               return true;
+
+       return false;
+}
+
+static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources == fh)
+               return true;
+
+       return false;
 }
 
-static int res_locked(struct tm6000_core *dev)
+static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh,
+                  bool is_res_read)
 {
-       return (dev->resources);
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources == fh && dev->is_res_read == is_res_read)
+               return true;
+
+       /* is it free? */
+       if (dev->resources)
+               return false;
+
+       /* grab it */
+       dev->resources = fh;
+       dev->is_res_read = is_res_read;
+       dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
+       return true;
 }
 
 static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
 {
-       dev->resources = 0;
+       /* Is the current fh handling it? if so, that's OK */
+       if (dev->resources != fh)
+               return;
+
+       dev->resources = NULL;
        dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
 }
 
@@ -981,7 +1005,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
        if (i != fh->type)
                return -EINVAL;
 
-       if (!res_get(dev,fh))
+       if (!res_get(dev, fh, false))
                return -EBUSY;
        return (videobuf_streamon(&fh->vb_vidq));
 }
@@ -1310,7 +1334,7 @@ tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
        struct tm6000_fh        *fh = file->private_data;
 
        if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               if (res_locked(fh->dev))
+               if (!res_get(fh->dev, fh, true))
                        return -EBUSY;
 
                return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
@@ -1328,7 +1352,10 @@ tm6000_poll(struct file *file, struct poll_table_struct *wait)
        if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
                return POLLERR;
 
-       if (res_get(fh->dev,fh)) {
+       if (!!is_res_streaming(fh->dev, fh))
+               return POLLERR;
+
+       if (!is_res_read(fh->dev, fh)) {
                /* streaming capture */
                if (list_empty(&fh->vb_vidq.stream))
                        return POLLERR;
@@ -1356,6 +1383,7 @@ static int tm6000_release(struct file *file)
 
        dev->users--;
 
+       res_free(dev, fh);
        if (!dev->users) {
                tm6000_uninit_isoc(dev);
                videobuf_mmap_free(&fh->vb_vidq);
index 5d9dcab5c87d88b70a6b671cfc5714252cfef0e6..a1c6ca2647ef0ea58cf06aa00c1136d6935bab54 100644 (file)
@@ -189,7 +189,9 @@ struct tm6000_core {
        int                             users;
 
        /* various device info */
-       unsigned int                    resources;
+       struct tm6000_fh                *resources;     /* Points to fh that is streaming */
+       bool                            is_res_read;
+
        struct video_device             *vfd;
        struct tm6000_dmaqueue          vidq;
        struct v4l2_device              v4l2_dev;