The patch number 9912 was added via Mauro Carvalho Chehab <mche...@redhat.com>
to http://linuxtv.org/hg/v4l-dvb master development tree.

Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel

If anyone has any objections, please let us know by sending a message to:
        v4l-dvb-maintai...@linuxtv.org

------

From: Mauro Carvalho Chehab  <mche...@redhat.com>
em28xx: fix/improve em28xx locking schema


Changes/fixes on em28xx dev->lock:

- em28xx_init_dev() were unlocking without a previous lock;

- some read ioctls need to lock after the removal of KBL, since a write
  may be happening at the same time an ioctl is reading;

- keep the device locked during all device initialization;

- lock/unlock while reading/writing registers.

Priority: normal

Signed-off-by: Mauro Carvalho Chehab <mche...@redhat.com>


---

 linux/drivers/media/video/em28xx/em28xx-video.c |   55 ++++++++++++----
 1 file changed, 43 insertions(+), 12 deletions(-)

diff -r 3980938ba091 -r 3cc7daa31234 
linux/drivers/media/video/em28xx/em28xx-video.c
--- a/linux/drivers/media/video/em28xx/em28xx-video.c   Tue Dec 16 21:36:13 
2008 -0200
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c   Tue Dec 16 23:04:56 
2008 -0200
@@ -789,9 +789,9 @@ static int vidioc_s_fmt_vid_cap(struct f
        if (rc < 0)
                return rc;
 
+       mutex_lock(&dev->lock);
+
        vidioc_try_fmt_vid_cap(file, priv, f);
-
-       mutex_lock(&dev->lock);
 
        if (videobuf_queue_is_busy(&fh->vb_vidq)) {
                em28xx_errdev("%s queue busy\n", __func__);
@@ -833,14 +833,11 @@ static int vidioc_s_std(struct file *fil
 
        mutex_lock(&dev->lock);
        dev->norm = *norm;
-       mutex_unlock(&dev->lock);
 
        /* Adjusts width/height, if needed */
        f.fmt.pix.width = dev->width;
        f.fmt.pix.height = dev->height;
        vidioc_try_fmt_vid_cap(file, priv, &f);
-
-       mutex_lock(&dev->lock);
 
        /* set new image size */
        dev->width = f.fmt.pix.width;
@@ -976,11 +973,15 @@ static int vidioc_s_audio(struct file *f
        if (a->index != dev->ctl_ainput)
                return -EINVAL;
 #else
+       mutex_lock(&dev->lock);
+
        dev->ctl_ainput = INPUT(a->index)->amux;
        dev->ctl_aoutput = INPUT(a->index)->aout;
 
        if (!dev->ctl_aoutput)
                dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+
+       mutex_unlock(&dev->lock);
 #endif
        return 0;
 }
@@ -1030,6 +1031,7 @@ static int vidioc_g_ctrl(struct file *fi
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
+
        mutex_lock(&dev->lock);
 
        if (!dev->board.has_msp34xx)
@@ -1140,8 +1142,10 @@ static int vidioc_g_frequency(struct fil
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
 
+       mutex_lock(&dev->lock);
        f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
        f->frequency = dev->ctl_freq;
+       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -1171,6 +1175,7 @@ static int vidioc_s_frequency(struct fil
        em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
 
        mutex_unlock(&dev->lock);
+
        return 0;
 }
 
@@ -1198,15 +1203,20 @@ static int vidioc_g_register(struct file
                return -EINVAL;
 
        if (em28xx_reg_len(reg->reg) == 1) {
+               mutex_lock(&dev->lock);
                ret = em28xx_read_reg(dev, reg->reg);
+               mutex_unlock(&dev->lock);
+
                if (ret < 0)
                        return ret;
 
                reg->val = ret;
        } else {
                __le64 val = 0;
+               mutex_lock(&dev->lock);
                ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
                                                   reg->reg, (char *)&val, 2);
+               mutex_unlock(&dev->lock);
                if (ret < 0)
                        return ret;
 
@@ -1222,11 +1232,16 @@ static int vidioc_s_register(struct file
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
        __le64 buf;
+       int    rc;
 
        buf = cpu_to_le64(reg->val);
 
-       return em28xx_write_regs(dev, reg->reg, (char *)&buf,
-                                em28xx_reg_len(reg->reg));
+       mutex_lock(&dev->lock);
+       rc = em28xx_write_regs(dev, reg->reg, (char *)&buf,
+                              em28xx_reg_len(reg->reg));
+       mutex_unlock(&dev->lock);
+
+       return rc;
 }
 #endif
 
@@ -1265,12 +1280,15 @@ static int vidioc_streamon(struct file *
 
        mutex_lock(&dev->lock);
        rc = res_get(fh);
-       mutex_unlock(&dev->lock);
 
        if (unlikely(rc < 0))
                return rc;
 
-       return (videobuf_streamon(&fh->vb_vidq));
+       rc = videobuf_streamon(&fh->vb_vidq);
+
+       mutex_unlock(&dev->lock);
+
+       return rc;
 }
 
 static int vidioc_streamoff(struct file *file, void *priv,
@@ -1289,9 +1307,11 @@ static int vidioc_streamoff(struct file 
        if (type != fh->type)
                return -EINVAL;
 
+       mutex_lock(&dev->lock);
+
        videobuf_streamoff(&fh->vb_vidq);
-       mutex_lock(&dev->lock);
        res_free(fh);
+
        mutex_unlock(&dev->lock);
 
        return 0;
@@ -1513,7 +1533,10 @@ static int radio_g_tuner(struct file *fi
        strcpy(t->name, "Radio");
        t->type = V4L2_TUNER_RADIO;
 
+       mutex_lock(&dev->lock);
        em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+       mutex_unlock(&dev->lock);
+
        return 0;
 }
 
@@ -1545,7 +1568,9 @@ static int radio_s_tuner(struct file *fi
        if (0 != t->index)
                return -EINVAL;
 
+       mutex_lock(&dev->lock);
        em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
+       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -1609,6 +1634,7 @@ static int em28xx_v4l2_open(struct inode
                }
        }
        mutex_unlock(&em28xx_devlist_mutex);
+
        if (NULL == dev)
                return -ENODEV;
 
@@ -2104,7 +2130,6 @@ static int em28xx_init_dev(struct em28xx
        unsigned int maxh, maxw;
 
        dev->udev = udev;
-       mutex_init(&dev->lock);
        mutex_init(&dev->ctrl_urb_lock);
        spin_lock_init(&dev->slock);
        init_waitqueue_head(&dev->open);
@@ -2222,7 +2247,6 @@ static int em28xx_init_dev(struct em28xx
        return 0;
 
 fail_reg_devices:
-       mutex_unlock(&dev->lock);
        return retval;
 }
 
@@ -2425,6 +2449,8 @@ static int em28xx_usb_probe(struct usb_i
                dev->model = card[nr];
 
        /* allocate device struct */
+       mutex_init(&dev->lock);
+       mutex_lock(&dev->lock);
        retval = em28xx_init_dev(&dev, udev, nr);
        if (retval) {
                em28xx_devused &= ~(1<<dev->devno);
@@ -2437,6 +2463,11 @@ static int em28xx_usb_probe(struct usb_i
        usb_set_intfdata(interface, dev);
 
        request_modules(dev);
+
+       /* Should be the last thing to do, to avoid newer udev's to
+          open the device before fully initializing it
+        */
+       mutex_unlock(&dev->lock);
 
        return 0;
 }


---

Patch is available at: 
http://linuxtv.org/hg/v4l-dvb/rev/3cc7daa31234ca3c9bd0a58eb825f61499a65826

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to