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