Commit 549ee4df authored by Devin Heitmueller's avatar Devin Heitmueller Committed by Mauro Carvalho Chehab

[media] au0828: fix race condition that causes xc5000 to not bind for digital

In some cases users would see the xc5000_attach() call failing for the
digital side of the tuner on initialization.  This is because of udev
running v4l-id while the digital side of the board is still coming up.

This is the exact same race condition which was present in em28xx (not
surprising since I copied all the locking logic from that driver when I
added analog support).  Reproduce Mauro's fix from the em28xx driver in
au0828.
Reported-by: default avatarRick Harding <rharding@mitechie.com>
Signed-off-by: default avatarDevin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 0a3dabb1
...@@ -205,6 +205,8 @@ static int au0828_usb_probe(struct usb_interface *interface, ...@@ -205,6 +205,8 @@ static int au0828_usb_probe(struct usb_interface *interface,
return -ENOMEM; return -ENOMEM;
} }
mutex_init(&dev->lock);
mutex_lock(&dev->lock);
mutex_init(&dev->mutex); mutex_init(&dev->mutex);
mutex_init(&dev->dvb.lock); mutex_init(&dev->dvb.lock);
dev->usbdev = usbdev; dev->usbdev = usbdev;
...@@ -215,6 +217,7 @@ static int au0828_usb_probe(struct usb_interface *interface, ...@@ -215,6 +217,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
if (retval) { if (retval) {
printk(KERN_ERR "%s() v4l2_device_register failed\n", printk(KERN_ERR "%s() v4l2_device_register failed\n",
__func__); __func__);
mutex_unlock(&dev->lock);
kfree(dev); kfree(dev);
return -EIO; return -EIO;
} }
...@@ -245,6 +248,8 @@ static int au0828_usb_probe(struct usb_interface *interface, ...@@ -245,6 +248,8 @@ static int au0828_usb_probe(struct usb_interface *interface,
printk(KERN_INFO "Registered device AU0828 [%s]\n", printk(KERN_INFO "Registered device AU0828 [%s]\n",
dev->board.name == NULL ? "Unset" : dev->board.name); dev->board.name == NULL ? "Unset" : dev->board.name);
mutex_unlock(&dev->lock);
return 0; return 0;
} }
......
...@@ -864,17 +864,15 @@ static int res_get(struct au0828_fh *fh, unsigned int bit) ...@@ -864,17 +864,15 @@ static int res_get(struct au0828_fh *fh, unsigned int bit)
return 1; return 1;
/* is it free? */ /* is it free? */
mutex_lock(&dev->lock);
if (dev->resources & bit) { if (dev->resources & bit) {
/* no, someone else uses it */ /* no, someone else uses it */
mutex_unlock(&dev->lock);
return 0; return 0;
} }
/* it's free, grab it */ /* it's free, grab it */
fh->resources |= bit; fh->resources |= bit;
dev->resources |= bit; dev->resources |= bit;
dprintk(1, "res: get %d\n", bit); dprintk(1, "res: get %d\n", bit);
mutex_unlock(&dev->lock);
return 1; return 1;
} }
...@@ -894,11 +892,9 @@ static void res_free(struct au0828_fh *fh, unsigned int bits) ...@@ -894,11 +892,9 @@ static void res_free(struct au0828_fh *fh, unsigned int bits)
BUG_ON((fh->resources & bits) != bits); BUG_ON((fh->resources & bits) != bits);
mutex_lock(&dev->lock);
fh->resources &= ~bits; fh->resources &= ~bits;
dev->resources &= ~bits; dev->resources &= ~bits;
dprintk(1, "res: put %d\n", bits); dprintk(1, "res: put %d\n", bits);
mutex_unlock(&dev->lock);
} }
static int get_ressource(struct au0828_fh *fh) static int get_ressource(struct au0828_fh *fh)
...@@ -1023,7 +1019,8 @@ static int au0828_v4l2_open(struct file *filp) ...@@ -1023,7 +1019,8 @@ static int au0828_v4l2_open(struct file *filp)
NULL, &dev->slock, NULL, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED, V4L2_FIELD_INTERLACED,
sizeof(struct au0828_buffer), fh, NULL); sizeof(struct au0828_buffer), fh,
&dev->lock);
/* VBI Setup */ /* VBI Setup */
dev->vbi_width = 720; dev->vbi_width = 720;
...@@ -1032,8 +1029,8 @@ static int au0828_v4l2_open(struct file *filp) ...@@ -1032,8 +1029,8 @@ static int au0828_v4l2_open(struct file *filp)
NULL, &dev->slock, NULL, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB, V4L2_FIELD_SEQ_TB,
sizeof(struct au0828_buffer), fh, NULL); sizeof(struct au0828_buffer), fh,
&dev->lock);
return ret; return ret;
} }
...@@ -1312,8 +1309,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, ...@@ -1312,8 +1309,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
if (rc < 0) if (rc < 0)
return rc; return rc;
mutex_lock(&dev->lock);
if (videobuf_queue_is_busy(&fh->vb_vidq)) { if (videobuf_queue_is_busy(&fh->vb_vidq)) {
printk(KERN_INFO "%s queue busy\n", __func__); printk(KERN_INFO "%s queue busy\n", __func__);
rc = -EBUSY; rc = -EBUSY;
...@@ -1322,7 +1317,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, ...@@ -1322,7 +1317,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
rc = au0828_set_format(dev, VIDIOC_S_FMT, f); rc = au0828_set_format(dev, VIDIOC_S_FMT, f);
out: out:
mutex_unlock(&dev->lock);
return rc; return rc;
} }
...@@ -1832,7 +1826,7 @@ static struct v4l2_file_operations au0828_v4l_fops = { ...@@ -1832,7 +1826,7 @@ static struct v4l2_file_operations au0828_v4l_fops = {
.read = au0828_v4l2_read, .read = au0828_v4l2_read,
.poll = au0828_v4l2_poll, .poll = au0828_v4l2_poll,
.mmap = au0828_v4l2_mmap, .mmap = au0828_v4l2_mmap,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops video_ioctl_ops = { static const struct v4l2_ioctl_ops video_ioctl_ops = {
...@@ -1922,7 +1916,6 @@ int au0828_analog_register(struct au0828_dev *dev, ...@@ -1922,7 +1916,6 @@ int au0828_analog_register(struct au0828_dev *dev,
init_waitqueue_head(&dev->open); init_waitqueue_head(&dev->open);
spin_lock_init(&dev->slock); spin_lock_init(&dev->slock);
mutex_init(&dev->lock);
/* init video dma queues */ /* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vidq.active);
...@@ -1963,11 +1956,13 @@ int au0828_analog_register(struct au0828_dev *dev, ...@@ -1963,11 +1956,13 @@ int au0828_analog_register(struct au0828_dev *dev,
/* Fill the video capture device struct */ /* Fill the video capture device struct */
*dev->vdev = au0828_video_template; *dev->vdev = au0828_video_template;
dev->vdev->parent = &dev->usbdev->dev; dev->vdev->parent = &dev->usbdev->dev;
dev->vdev->lock = &dev->lock;
strcpy(dev->vdev->name, "au0828a video"); strcpy(dev->vdev->name, "au0828a video");
/* Setup the VBI device */ /* Setup the VBI device */
*dev->vbi_dev = au0828_video_template; *dev->vbi_dev = au0828_video_template;
dev->vbi_dev->parent = &dev->usbdev->dev; dev->vbi_dev->parent = &dev->usbdev->dev;
dev->vbi_dev->lock = &dev->lock;
strcpy(dev->vbi_dev->name, "au0828a vbi"); strcpy(dev->vbi_dev->name, "au0828a vbi");
/* Register the v4l2 device */ /* Register the v4l2 device */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment