Commit 8efc1a1a authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'bkl_removal' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6

* 'bkl_removal' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6:
  [media] uvcvideo: Convert to unlocked_ioctl
  [media] uvcvideo: Lock stream mutex when accessing format-related information
  [media] uvcvideo: Move mmap() handler to uvc_queue.c
  [media] uvcvideo: Move mutex lock/unlock inside uvc_free_buffers
  [media] uvcvideo: Lock controls mutex when querying menus
  [media] v4l2-dev: fix race condition
  [media] V4L: improve the BKL replacement heuristic
  [media] v4l2-dev: use mutex_lock_interruptible instead of plain mutex_lock
  [media] cx18: convert to unlocked_ioctl
  [media] radio-timb: convert to unlocked_ioctl
  [media] sh_vou: convert to unlocked_ioctl
  [media] cafe_ccic: replace ioctl by unlocked_ioctl
  [media] et61x251_core: trivial conversion to unlocked_ioctl
  [media] sn9c102: convert to unlocked_ioctl
  [media] BKL: trivial ioctl -> unlocked_ioctl video driver conversions
  [media] typhoon: convert to unlocked_ioctl
  [media] si4713: convert to unlocked_ioctl
  [media] tea5764: convert to unlocked_ioctl
  [media] cadet: use unlocked_ioctl
  [media] BKL: trivial BKL removal from V4L2 radio drivers
parents 74280817 673eb9ff
...@@ -361,7 +361,7 @@ static int vidioc_s_audio(struct file *file, void *priv, ...@@ -361,7 +361,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations rtrack_fops = { static const struct v4l2_file_operations rtrack_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { static const struct v4l2_ioctl_ops rtrack_ioctl_ops = {
...@@ -412,13 +412,6 @@ static int __init rtrack_init(void) ...@@ -412,13 +412,6 @@ static int __init rtrack_init(void)
rt->vdev.release = video_device_release_empty; rt->vdev.release = video_device_release_empty;
video_set_drvdata(&rt->vdev, rt); video_set_drvdata(&rt->vdev, rt);
if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(&rt->v4l2_dev);
release_region(rt->io, 2);
return -EINVAL;
}
v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
/* Set up the I/O locking */ /* Set up the I/O locking */
mutex_init(&rt->lock); mutex_init(&rt->lock);
...@@ -430,6 +423,13 @@ static int __init rtrack_init(void) ...@@ -430,6 +423,13 @@ static int __init rtrack_init(void)
sleep_delay(2000000); /* make sure it's totally down */ sleep_delay(2000000); /* make sure it's totally down */
outb(0xc0, rt->io); /* steady volume, mute card */ outb(0xc0, rt->io); /* steady volume, mute card */
if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(&rt->v4l2_dev);
release_region(rt->io, 2);
return -EINVAL;
}
v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
return 0; return 0;
} }
......
...@@ -324,7 +324,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, ...@@ -324,7 +324,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
static const struct v4l2_file_operations aztech_fops = { static const struct v4l2_file_operations aztech_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops aztech_ioctl_ops = { static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
...@@ -375,6 +375,8 @@ static int __init aztech_init(void) ...@@ -375,6 +375,8 @@ static int __init aztech_init(void)
az->vdev.ioctl_ops = &aztech_ioctl_ops; az->vdev.ioctl_ops = &aztech_ioctl_ops;
az->vdev.release = video_device_release_empty; az->vdev.release = video_device_release_empty;
video_set_drvdata(&az->vdev, az); video_set_drvdata(&az->vdev, az);
/* mute card - prevents noisy bootups */
outb(0, az->io);
if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev); v4l2_device_unregister(v4l2_dev);
...@@ -383,8 +385,6 @@ static int __init aztech_init(void) ...@@ -383,8 +385,6 @@ static int __init aztech_init(void)
} }
v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
/* mute card - prevents noisy bootups */
outb(0, az->io);
return 0; return 0;
} }
......
...@@ -328,11 +328,10 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo ...@@ -328,11 +328,10 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
unsigned char readbuf[RDS_BUFFER]; unsigned char readbuf[RDS_BUFFER];
int i = 0; int i = 0;
if (dev->rdsstat == 0) {
mutex_lock(&dev->lock); mutex_lock(&dev->lock);
if (dev->rdsstat == 0) {
dev->rdsstat = 1; dev->rdsstat = 1;
outb(0x80, dev->io); /* Select RDS fifo */ outb(0x80, dev->io); /* Select RDS fifo */
mutex_unlock(&dev->lock);
init_timer(&dev->readtimer); init_timer(&dev->readtimer);
dev->readtimer.function = cadet_handler; dev->readtimer.function = cadet_handler;
dev->readtimer.data = (unsigned long)dev; dev->readtimer.data = (unsigned long)dev;
...@@ -340,12 +339,15 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo ...@@ -340,12 +339,15 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
add_timer(&dev->readtimer); add_timer(&dev->readtimer);
} }
if (dev->rdsin == dev->rdsout) { if (dev->rdsin == dev->rdsout) {
mutex_unlock(&dev->lock);
if (file->f_flags & O_NONBLOCK) if (file->f_flags & O_NONBLOCK)
return -EWOULDBLOCK; return -EWOULDBLOCK;
interruptible_sleep_on(&dev->read_queue); interruptible_sleep_on(&dev->read_queue);
mutex_lock(&dev->lock);
} }
while (i < count && dev->rdsin != dev->rdsout) while (i < count && dev->rdsin != dev->rdsout)
readbuf[i++] = dev->rdsbuf[dev->rdsout++]; readbuf[i++] = dev->rdsbuf[dev->rdsout++];
mutex_unlock(&dev->lock);
if (copy_to_user(data, readbuf, i)) if (copy_to_user(data, readbuf, i))
return -EFAULT; return -EFAULT;
...@@ -525,9 +527,11 @@ static int cadet_open(struct file *file) ...@@ -525,9 +527,11 @@ static int cadet_open(struct file *file)
{ {
struct cadet *dev = video_drvdata(file); struct cadet *dev = video_drvdata(file);
mutex_lock(&dev->lock);
dev->users++; dev->users++;
if (1 == dev->users) if (1 == dev->users)
init_waitqueue_head(&dev->read_queue); init_waitqueue_head(&dev->read_queue);
mutex_unlock(&dev->lock);
return 0; return 0;
} }
...@@ -535,11 +539,13 @@ static int cadet_release(struct file *file) ...@@ -535,11 +539,13 @@ static int cadet_release(struct file *file)
{ {
struct cadet *dev = video_drvdata(file); struct cadet *dev = video_drvdata(file);
mutex_lock(&dev->lock);
dev->users--; dev->users--;
if (0 == dev->users) { if (0 == dev->users) {
del_timer_sync(&dev->readtimer); del_timer_sync(&dev->readtimer);
dev->rdsstat = 0; dev->rdsstat = 0;
} }
mutex_unlock(&dev->lock);
return 0; return 0;
} }
...@@ -559,7 +565,7 @@ static const struct v4l2_file_operations cadet_fops = { ...@@ -559,7 +565,7 @@ static const struct v4l2_file_operations cadet_fops = {
.open = cadet_open, .open = cadet_open,
.release = cadet_release, .release = cadet_release,
.read = cadet_read, .read = cadet_read,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
.poll = cadet_poll, .poll = cadet_poll,
}; };
......
...@@ -361,7 +361,7 @@ MODULE_DEVICE_TABLE(pci, gemtek_pci_id); ...@@ -361,7 +361,7 @@ MODULE_DEVICE_TABLE(pci, gemtek_pci_id);
static const struct v4l2_file_operations gemtek_pci_fops = { static const struct v4l2_file_operations gemtek_pci_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = { static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = {
...@@ -422,11 +422,11 @@ static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_dev ...@@ -422,11 +422,11 @@ static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_dev
card->vdev.release = video_device_release_empty; card->vdev.release = video_device_release_empty;
video_set_drvdata(&card->vdev, card); video_set_drvdata(&card->vdev, card);
gemtek_pci_mute(card);
if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0) if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0)
goto err_video; goto err_video;
gemtek_pci_mute(card);
v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
pdev->revision, card->iobase, card->iobase + card->length - 1); pdev->revision, card->iobase, card->iobase + card->length - 1);
......
...@@ -378,7 +378,7 @@ static int gemtek_probe(struct gemtek *gt) ...@@ -378,7 +378,7 @@ static int gemtek_probe(struct gemtek *gt)
static const struct v4l2_file_operations gemtek_fops = { static const struct v4l2_file_operations gemtek_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static int vidioc_querycap(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv,
...@@ -577,12 +577,6 @@ static int __init gemtek_init(void) ...@@ -577,12 +577,6 @@ static int __init gemtek_init(void)
gt->vdev.release = video_device_release_empty; gt->vdev.release = video_device_release_empty;
video_set_drvdata(&gt->vdev, gt); video_set_drvdata(&gt->vdev, gt);
if (video_register_device(&gt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(gt->io, 1);
return -EBUSY;
}
/* Set defaults */ /* Set defaults */
gt->lastfreq = GEMTEK_LOWFREQ; gt->lastfreq = GEMTEK_LOWFREQ;
gt->bu2614data = 0; gt->bu2614data = 0;
...@@ -590,6 +584,12 @@ static int __init gemtek_init(void) ...@@ -590,6 +584,12 @@ static int __init gemtek_init(void)
if (initmute) if (initmute)
gemtek_mute(gt); gemtek_mute(gt);
if (video_register_device(&gt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(gt->io, 1);
return -EBUSY;
}
return 0; return 0;
} }
......
...@@ -299,7 +299,7 @@ static int vidioc_s_audio(struct file *file, void *priv, ...@@ -299,7 +299,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations maestro_fops = { static const struct v4l2_file_operations maestro_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops maestro_ioctl_ops = { static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
...@@ -383,22 +383,20 @@ static int __devinit maestro_probe(struct pci_dev *pdev, ...@@ -383,22 +383,20 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
dev->vdev.release = video_device_release_empty; dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev); video_set_drvdata(&dev->vdev, dev);
if (!radio_power_on(dev)) {
retval = -EIO;
goto errfr1;
}
retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr); retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
if (retval) { if (retval) {
v4l2_err(v4l2_dev, "can't register video device!\n"); v4l2_err(v4l2_dev, "can't register video device!\n");
goto errfr1; goto errfr1;
} }
if (!radio_power_on(dev)) {
retval = -EIO;
goto errunr;
}
v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n"); v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
return 0; return 0;
errunr:
video_unregister_device(&dev->vdev);
errfr1: errfr1:
v4l2_device_unregister(v4l2_dev); v4l2_device_unregister(v4l2_dev);
errfr: errfr:
......
...@@ -346,7 +346,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, ...@@ -346,7 +346,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
static const struct v4l2_file_operations maxiradio_fops = { static const struct v4l2_file_operations maxiradio_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
......
...@@ -33,6 +33,7 @@ struct pcm20 { ...@@ -33,6 +33,7 @@ struct pcm20 {
unsigned long freq; unsigned long freq;
int muted; int muted;
struct snd_miro_aci *aci; struct snd_miro_aci *aci;
struct mutex lock;
}; };
static struct pcm20 pcm20_card = { static struct pcm20 pcm20_card = {
...@@ -72,7 +73,7 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq) ...@@ -72,7 +73,7 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
static const struct v4l2_file_operations pcm20_fops = { static const struct v4l2_file_operations pcm20_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static int vidioc_querycap(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv,
...@@ -229,7 +230,7 @@ static int __init pcm20_init(void) ...@@ -229,7 +230,7 @@ static int __init pcm20_init(void)
return -ENODEV; return -ENODEV;
} }
strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name)); strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name));
mutex_init(&dev->lock);
res = v4l2_device_register(NULL, v4l2_dev); res = v4l2_device_register(NULL, v4l2_dev);
if (res < 0) { if (res < 0) {
...@@ -242,6 +243,7 @@ static int __init pcm20_init(void) ...@@ -242,6 +243,7 @@ static int __init pcm20_init(void)
dev->vdev.fops = &pcm20_fops; dev->vdev.fops = &pcm20_fops;
dev->vdev.ioctl_ops = &pcm20_ioctl_ops; dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
dev->vdev.release = video_device_release_empty; dev->vdev.release = video_device_release_empty;
dev->vdev.lock = &dev->lock;
video_set_drvdata(&dev->vdev, dev); video_set_drvdata(&dev->vdev, dev);
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0)
......
...@@ -266,7 +266,7 @@ static int vidioc_s_audio(struct file *file, void *priv, ...@@ -266,7 +266,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations rtrack2_fops = { static const struct v4l2_file_operations rtrack2_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
...@@ -315,6 +315,10 @@ static int __init rtrack2_init(void) ...@@ -315,6 +315,10 @@ static int __init rtrack2_init(void)
dev->vdev.release = video_device_release_empty; dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev); video_set_drvdata(&dev->vdev, dev);
/* mute card - prevents noisy bootups */
outb(1, dev->io);
dev->muted = 1;
mutex_init(&dev->lock); mutex_init(&dev->lock);
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev); v4l2_device_unregister(v4l2_dev);
...@@ -324,10 +328,6 @@ static int __init rtrack2_init(void) ...@@ -324,10 +328,6 @@ static int __init rtrack2_init(void)
v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n"); v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
/* mute card - prevents noisy bootups */
outb(1, dev->io);
dev->muted = 1;
return 0; return 0;
} }
......
...@@ -260,7 +260,7 @@ static int vidioc_s_audio(struct file *file, void *priv, ...@@ -260,7 +260,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations fmi_fops = { static const struct v4l2_file_operations fmi_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops fmi_ioctl_ops = { static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
...@@ -382,6 +382,9 @@ static int __init fmi_init(void) ...@@ -382,6 +382,9 @@ static int __init fmi_init(void)
mutex_init(&fmi->lock); mutex_init(&fmi->lock);
/* mute card - prevents noisy bootups */
fmi_mute(fmi);
if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev); v4l2_device_unregister(v4l2_dev);
release_region(fmi->io, 2); release_region(fmi->io, 2);
...@@ -391,8 +394,6 @@ static int __init fmi_init(void) ...@@ -391,8 +394,6 @@ static int __init fmi_init(void)
} }
v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io); v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io);
/* mute card - prevents noisy bootups */
fmi_mute(fmi);
return 0; return 0;
} }
......
...@@ -376,7 +376,7 @@ static int vidioc_s_audio(struct file *file, void *priv, ...@@ -376,7 +376,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations fmr2_fops = { static const struct v4l2_file_operations fmr2_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops fmr2_ioctl_ops = { static const struct v4l2_ioctl_ops fmr2_ioctl_ops = {
...@@ -424,6 +424,10 @@ static int __init fmr2_init(void) ...@@ -424,6 +424,10 @@ static int __init fmr2_init(void)
fmr2->vdev.release = video_device_release_empty; fmr2->vdev.release = video_device_release_empty;
video_set_drvdata(&fmr2->vdev, fmr2); video_set_drvdata(&fmr2->vdev, fmr2);
/* mute card - prevents noisy bootups */
fmr2_mute(fmr2->io);
fmr2_product_info(fmr2);
if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev); v4l2_device_unregister(v4l2_dev);
release_region(fmr2->io, 2); release_region(fmr2->io, 2);
...@@ -431,11 +435,6 @@ static int __init fmr2_init(void) ...@@ -431,11 +435,6 @@ static int __init fmr2_init(void)
} }
v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io); v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io);
/* mute card - prevents noisy bootups */
mutex_lock(&fmr2->lock);
fmr2_mute(fmr2->io);
fmr2_product_info(fmr2);
mutex_unlock(&fmr2->lock);
debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type)); debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type));
return 0; return 0;
} }
......
...@@ -53,7 +53,8 @@ struct radio_si4713_device { ...@@ -53,7 +53,8 @@ struct radio_si4713_device {
/* radio_si4713_fops - file operations interface */ /* radio_si4713_fops - file operations interface */
static const struct v4l2_file_operations radio_si4713_fops = { static const struct v4l2_file_operations radio_si4713_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, /* Note: locking is done at the subdev level in the i2c driver. */
.unlocked_ioctl = video_ioctl2,
}; };
/* Video4Linux Interface */ /* Video4Linux Interface */
......
...@@ -142,7 +142,6 @@ struct tea5764_device { ...@@ -142,7 +142,6 @@ struct tea5764_device {
struct video_device *videodev; struct video_device *videodev;
struct tea5764_regs regs; struct tea5764_regs regs;
struct mutex mutex; struct mutex mutex;
int users;
}; };
/* I2C code related */ /* I2C code related */
...@@ -458,41 +457,10 @@ static int vidioc_s_audio(struct file *file, void *priv, ...@@ -458,41 +457,10 @@ static int vidioc_s_audio(struct file *file, void *priv,
return 0; return 0;
} }
static int tea5764_open(struct file *file)
{
/* Currently we support only one device */
struct tea5764_device *radio = video_drvdata(file);
mutex_lock(&radio->mutex);
/* Only exclusive access */
if (radio->users) {
mutex_unlock(&radio->mutex);
return -EBUSY;
}
radio->users++;
mutex_unlock(&radio->mutex);
file->private_data = radio;
return 0;
}
static int tea5764_close(struct file *file)
{
struct tea5764_device *radio = video_drvdata(file);
if (!radio)
return -ENODEV;
mutex_lock(&radio->mutex);
radio->users--;
mutex_unlock(&radio->mutex);
return 0;
}
/* File system interface */ /* File system interface */
static const struct v4l2_file_operations tea5764_fops = { static const struct v4l2_file_operations tea5764_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = tea5764_open, .unlocked_ioctl = video_ioctl2,
.release = tea5764_close,
.ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops tea5764_ioctl_ops = { static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
...@@ -527,7 +495,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client, ...@@ -527,7 +495,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
int ret; int ret;
PDEBUG("probe"); PDEBUG("probe");
radio = kmalloc(sizeof(struct tea5764_device), GFP_KERNEL); radio = kzalloc(sizeof(struct tea5764_device), GFP_KERNEL);
if (!radio) if (!radio)
return -ENOMEM; return -ENOMEM;
...@@ -555,12 +523,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client, ...@@ -555,12 +523,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
i2c_set_clientdata(client, radio); i2c_set_clientdata(client, radio);
video_set_drvdata(radio->videodev, radio); video_set_drvdata(radio->videodev, radio);
radio->videodev->lock = &radio->mutex;
ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
if (ret < 0) {
PWARN("Could not register video device!");
goto errrel;
}
/* initialize and power off the chip */ /* initialize and power off the chip */
tea5764_i2c_read(radio); tea5764_i2c_read(radio);
...@@ -568,6 +531,12 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client, ...@@ -568,6 +531,12 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
tea5764_mute(radio, 1); tea5764_mute(radio, 1);
tea5764_power_down(radio); tea5764_power_down(radio);
ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
if (ret < 0) {
PWARN("Could not register video device!");
goto errrel;
}
PINFO("registered."); PINFO("registered.");
return 0; return 0;
errrel: errrel:
......
...@@ -338,7 +338,7 @@ static int vidioc_s_audio(struct file *file, void *priv, ...@@ -338,7 +338,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations terratec_fops = { static const struct v4l2_file_operations terratec_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops terratec_ioctl_ops = { static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
...@@ -389,6 +389,9 @@ static int __init terratec_init(void) ...@@ -389,6 +389,9 @@ static int __init terratec_init(void)
mutex_init(&tt->lock); mutex_init(&tt->lock);
/* mute card - prevents noisy bootups */
tt_write_vol(tt, 0);
if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(&tt->v4l2_dev); v4l2_device_unregister(&tt->v4l2_dev);
release_region(tt->io, 2); release_region(tt->io, 2);
...@@ -396,9 +399,6 @@ static int __init terratec_init(void) ...@@ -396,9 +399,6 @@ static int __init terratec_init(void)
} }
v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n"); v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n");
/* mute card - prevents noisy bootups */
tt_write_vol(tt, 0);
return 0; return 0;
} }
......
...@@ -34,6 +34,7 @@ struct timbradio { ...@@ -34,6 +34,7 @@ struct timbradio {
struct v4l2_subdev *sd_dsp; struct v4l2_subdev *sd_dsp;
struct video_device video_dev; struct video_device video_dev;
struct v4l2_device v4l2_dev; struct v4l2_device v4l2_dev;
struct mutex lock;
}; };
...@@ -142,7 +143,7 @@ static const struct v4l2_ioctl_ops timbradio_ioctl_ops = { ...@@ -142,7 +143,7 @@ static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {
static const struct v4l2_file_operations timbradio_fops = { static const struct v4l2_file_operations timbradio_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static int __devinit timbradio_probe(struct platform_device *pdev) static int __devinit timbradio_probe(struct platform_device *pdev)
...@@ -164,6 +165,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev) ...@@ -164,6 +165,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
} }
tr->pdata = *pdata; tr->pdata = *pdata;
mutex_init(&tr->lock);
strlcpy(tr->video_dev.name, "Timberdale Radio", strlcpy(tr->video_dev.name, "Timberdale Radio",
sizeof(tr->video_dev.name)); sizeof(tr->video_dev.name));
...@@ -171,6 +173,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev) ...@@ -171,6 +173,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
tr->video_dev.ioctl_ops = &timbradio_ioctl_ops; tr->video_dev.ioctl_ops = &timbradio_ioctl_ops;
tr->video_dev.release = video_device_release_empty; tr->video_dev.release = video_device_release_empty;
tr->video_dev.minor = -1; tr->video_dev.minor = -1;
tr->video_dev.lock = &tr->lock;
strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name)); strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
err = v4l2_device_register(NULL, &tr->v4l2_dev); err = v4l2_device_register(NULL, &tr->v4l2_dev);
......
...@@ -344,7 +344,7 @@ static int vidioc_s_audio(struct file *file, void *priv, ...@@ -344,7 +344,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations trust_fops = { static const struct v4l2_file_operations trust_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops trust_ioctl_ops = { static const struct v4l2_ioctl_ops trust_ioctl_ops = {
...@@ -396,14 +396,6 @@ static int __init trust_init(void) ...@@ -396,14 +396,6 @@ static int __init trust_init(void)
tr->vdev.release = video_device_release_empty; tr->vdev.release = video_device_release_empty;
video_set_drvdata(&tr->vdev, tr); video_set_drvdata(&tr->vdev, tr);
if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(tr->io, 2);
return -EINVAL;
}
v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */
...@@ -418,6 +410,14 @@ static int __init trust_init(void) ...@@ -418,6 +410,14 @@ static int __init trust_init(void)
/* mute card - prevents noisy bootups */ /* mute card - prevents noisy bootups */
tr_setmute(tr, 1); tr_setmute(tr, 1);
if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(tr->io, 2);
return -EINVAL;
}
v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
return 0; return 0;
} }
......
...@@ -317,7 +317,7 @@ static int vidioc_log_status(struct file *file, void *priv) ...@@ -317,7 +317,7 @@ static int vidioc_log_status(struct file *file, void *priv)
static const struct v4l2_file_operations typhoon_fops = { static const struct v4l2_file_operations typhoon_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
...@@ -344,18 +344,18 @@ static int __init typhoon_init(void) ...@@ -344,18 +344,18 @@ static int __init typhoon_init(void)
strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name)); strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name));
dev->io = io; dev->io = io;
dev->curfreq = dev->mutefreq = mutefreq;
if (dev->io == -1) { if (dev->io == -1) {
v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n"); v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n");
return -EINVAL; return -EINVAL;
} }
if (dev->mutefreq < 87000 || dev->mutefreq > 108500) { if (mutefreq < 87000 || mutefreq > 108500) {
v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n"); v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n");
v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
return -EINVAL; return -EINVAL;
} }
dev->curfreq = dev->mutefreq = mutefreq << 4;
mutex_init(&dev->lock); mutex_init(&dev->lock);
if (!request_region(dev->io, 8, "typhoon")) { if (!request_region(dev->io, 8, "typhoon")) {
...@@ -378,17 +378,17 @@ static int __init typhoon_init(void) ...@@ -378,17 +378,17 @@ static int __init typhoon_init(void)
dev->vdev.ioctl_ops = &typhoon_ioctl_ops; dev->vdev.ioctl_ops = &typhoon_ioctl_ops;
dev->vdev.release = video_device_release_empty; dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev); video_set_drvdata(&dev->vdev, dev);
/* mute card - prevents noisy bootups */
typhoon_mute(dev);
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(&dev->v4l2_dev); v4l2_device_unregister(&dev->v4l2_dev);
release_region(dev->io, 8); release_region(dev->io, 8);
return -EINVAL; return -EINVAL;
} }
v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io); v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io);
v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", dev->mutefreq); v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq);
dev->mutefreq <<= 4;
/* mute card - prevents noisy bootups */
typhoon_mute(dev);
return 0; return 0;
} }
......
...@@ -377,7 +377,7 @@ static int vidioc_s_audio(struct file *file, void *priv, ...@@ -377,7 +377,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations zoltrix_fops = static const struct v4l2_file_operations zoltrix_fops =
{ {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
...@@ -424,20 +424,6 @@ static int __init zoltrix_init(void) ...@@ -424,20 +424,6 @@ static int __init zoltrix_init(void)
return res; return res;
} }
strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
zol->vdev.v4l2_dev = v4l2_dev;
zol->vdev.fops = &zoltrix_fops;
zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
zol->vdev.release = video_device_release_empty;
video_set_drvdata(&zol->vdev, zol);
if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(zol->io, 2);
return -EINVAL;
}
v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
mutex_init(&zol->lock); mutex_init(&zol->lock);
/* mute card - prevents noisy bootups */ /* mute card - prevents noisy bootups */
...@@ -452,6 +438,20 @@ static int __init zoltrix_init(void) ...@@ -452,6 +438,20 @@ static int __init zoltrix_init(void)
zol->curvol = 0; zol->curvol = 0;
zol->stereo = 1; zol->stereo = 1;
strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
zol->vdev.v4l2_dev = v4l2_dev;
zol->vdev.fops = &zoltrix_fops;
zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
zol->vdev.release = video_device_release_empty;
video_set_drvdata(&zol->vdev, zol);
if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(zol->io, 2);
return -EINVAL;
}
v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
return 0; return 0;
} }
......
...@@ -712,7 +712,7 @@ static int ar_initialize(struct ar *ar) ...@@ -712,7 +712,7 @@ static int ar_initialize(struct ar *ar)
static const struct v4l2_file_operations ar_fops = { static const struct v4l2_file_operations ar_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = ar_read, .read = ar_read,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops ar_ioctl_ops = { static const struct v4l2_ioctl_ops ar_ioctl_ops = {
......
...@@ -860,7 +860,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf, ...@@ -860,7 +860,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
static const struct v4l2_file_operations qcam_fops = { static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
.read = qcam_read, .read = qcam_read,
}; };
......
...@@ -718,7 +718,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf, ...@@ -718,7 +718,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
static const struct v4l2_file_operations qcam_fops = { static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
.read = qcam_read, .read = qcam_read,
}; };
......
...@@ -1775,7 +1775,7 @@ static const struct v4l2_file_operations cafe_v4l_fops = { ...@@ -1775,7 +1775,7 @@ static const struct v4l2_file_operations cafe_v4l_fops = {
.read = cafe_v4l_read, .read = cafe_v4l_read,
.poll = cafe_v4l_poll, .poll = cafe_v4l_poll,
.mmap = cafe_v4l_mmap, .mmap = cafe_v4l_mmap,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
}; };
static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = { static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
......
...@@ -218,7 +218,13 @@ static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream) ...@@ -218,7 +218,13 @@ static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream)
static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream, static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg) unsigned int cmd, void *arg)
{ {
return snd_pcm_lib_ioctl(substream, cmd, arg); struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
int ret;
snd_cx18_lock(cxsc);
ret = snd_pcm_lib_ioctl(substream, cmd, arg);
snd_cx18_unlock(cxsc);
return ret;
} }
......
...@@ -41,7 +41,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = { ...@@ -41,7 +41,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = {
.read = cx18_v4l2_read, .read = cx18_v4l2_read,
.open = cx18_v4l2_open, .open = cx18_v4l2_open,
/* FIXME change to video_ioctl2 if serialization lock can be removed */ /* FIXME change to video_ioctl2 if serialization lock can be removed */
.ioctl = cx18_v4l2_ioctl, .unlocked_ioctl = cx18_v4l2_ioctl,
.release = cx18_v4l2_close, .release = cx18_v4l2_close,
.poll = cx18_v4l2_enc_poll, .poll = cx18_v4l2_enc_poll,
}; };
......
...@@ -2530,7 +2530,7 @@ static const struct v4l2_file_operations et61x251_fops = { ...@@ -2530,7 +2530,7 @@ static const struct v4l2_file_operations et61x251_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = et61x251_open, .open = et61x251_open,
.release = et61x251_release, .release = et61x251_release,
.ioctl = et61x251_ioctl, .unlocked_ioctl = et61x251_ioctl,
.read = et61x251_read, .read = et61x251_read,
.poll = et61x251_poll, .poll = et61x251_poll,
.mmap = et61x251_mmap, .mmap = et61x251_mmap,
......
...@@ -1659,7 +1659,7 @@ static const struct v4l2_file_operations meye_fops = { ...@@ -1659,7 +1659,7 @@ static const struct v4l2_file_operations meye_fops = {
.open = meye_open, .open = meye_open,
.release = meye_release, .release = meye_release,
.mmap = meye_mmap, .mmap = meye_mmap,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
.poll = meye_poll, .poll = meye_poll,
}; };
...@@ -1831,12 +1831,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev, ...@@ -1831,12 +1831,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
msleep(1); msleep(1);
mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);
if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
video_nr) < 0) {
v4l2_err(v4l2_dev, "video_register_device failed\n");
goto outvideoreg;
}
mutex_init(&meye.lock); mutex_init(&meye.lock);
init_waitqueue_head(&meye.proc_list); init_waitqueue_head(&meye.proc_list);
meye.brightness = 32 << 10; meye.brightness = 32 << 10;
...@@ -1858,6 +1852,12 @@ static int __devinit meye_probe(struct pci_dev *pcidev, ...@@ -1858,6 +1852,12 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);
sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);
if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
video_nr) < 0) {
v4l2_err(v4l2_dev, "video_register_device failed\n");
goto outvideoreg;
}
v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n", v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n",
MEYE_DRIVER_VERSION); MEYE_DRIVER_VERSION);
v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n", v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n",
......
...@@ -932,7 +932,7 @@ static ssize_t pms_read(struct file *file, char __user *buf, ...@@ -932,7 +932,7 @@ static ssize_t pms_read(struct file *file, char __user *buf,
static const struct v4l2_file_operations pms_fops = { static const struct v4l2_file_operations pms_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
.read = pms_read, .read = pms_read,
}; };
......
...@@ -75,6 +75,7 @@ struct sh_vou_device { ...@@ -75,6 +75,7 @@ struct sh_vou_device {
int pix_idx; int pix_idx;
struct videobuf_buffer *active; struct videobuf_buffer *active;
enum sh_vou_status status; enum sh_vou_status status;
struct mutex fop_lock;
}; };
struct sh_vou_file { struct sh_vou_file {
...@@ -235,7 +236,7 @@ static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb) ...@@ -235,7 +236,7 @@ static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb)
vb->state = VIDEOBUF_NEEDS_INIT; vb->state = VIDEOBUF_NEEDS_INIT;
} }
/* Locking: caller holds vq->vb_lock mutex */ /* Locking: caller holds fop_lock mutex */
static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count, static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size) unsigned int *size)
{ {
...@@ -257,7 +258,7 @@ static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count, ...@@ -257,7 +258,7 @@ static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
return 0; return 0;
} }
/* Locking: caller holds vq->vb_lock mutex */ /* Locking: caller holds fop_lock mutex */
static int sh_vou_buf_prepare(struct videobuf_queue *vq, static int sh_vou_buf_prepare(struct videobuf_queue *vq,
struct videobuf_buffer *vb, struct videobuf_buffer *vb,
enum v4l2_field field) enum v4l2_field field)
...@@ -306,7 +307,7 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq, ...@@ -306,7 +307,7 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq,
return 0; return 0;
} }
/* Locking: caller holds vq->vb_lock mutex and vq->irqlock spinlock */ /* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */
static void sh_vou_buf_queue(struct videobuf_queue *vq, static void sh_vou_buf_queue(struct videobuf_queue *vq,
struct videobuf_buffer *vb) struct videobuf_buffer *vb)
{ {
...@@ -1190,7 +1191,7 @@ static int sh_vou_open(struct file *file) ...@@ -1190,7 +1191,7 @@ static int sh_vou_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_BUF_TYPE_VIDEO_OUTPUT,
V4L2_FIELD_NONE, V4L2_FIELD_NONE,
sizeof(struct videobuf_buffer), vdev, sizeof(struct videobuf_buffer), vdev,
NULL); &vou_dev->fop_lock);
return 0; return 0;
} }
...@@ -1292,7 +1293,7 @@ static const struct v4l2_file_operations sh_vou_fops = { ...@@ -1292,7 +1293,7 @@ static const struct v4l2_file_operations sh_vou_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = sh_vou_open, .open = sh_vou_open,
.release = sh_vou_release, .release = sh_vou_release,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
.mmap = sh_vou_mmap, .mmap = sh_vou_mmap,
.poll = sh_vou_poll, .poll = sh_vou_poll,
}; };
...@@ -1331,6 +1332,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev) ...@@ -1331,6 +1332,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&vou_dev->queue); INIT_LIST_HEAD(&vou_dev->queue);
spin_lock_init(&vou_dev->lock); spin_lock_init(&vou_dev->lock);
mutex_init(&vou_dev->fop_lock);
atomic_set(&vou_dev->use_count, 0); atomic_set(&vou_dev->use_count, 0);
vou_dev->pdata = vou_pdata; vou_dev->pdata = vou_pdata;
vou_dev->status = SH_VOU_IDLE; vou_dev->status = SH_VOU_IDLE;
...@@ -1388,6 +1390,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev) ...@@ -1388,6 +1390,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
vdev->tvnorms |= V4L2_STD_PAL; vdev->tvnorms |= V4L2_STD_PAL;
vdev->v4l2_dev = &vou_dev->v4l2_dev; vdev->v4l2_dev = &vou_dev->v4l2_dev;
vdev->release = video_device_release; vdev->release = video_device_release;
vdev->lock = &vou_dev->fop_lock;
vou_dev->vdev = vdev; vou_dev->vdev = vdev;
video_set_drvdata(vdev, vou_dev); video_set_drvdata(vdev, vou_dev);
......
...@@ -3238,7 +3238,7 @@ static const struct v4l2_file_operations sn9c102_fops = { ...@@ -3238,7 +3238,7 @@ static const struct v4l2_file_operations sn9c102_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = sn9c102_open, .open = sn9c102_open,
.release = sn9c102_release, .release = sn9c102_release,
.ioctl = sn9c102_ioctl, .unlocked_ioctl = sn9c102_ioctl,
.read = sn9c102_read, .read = sn9c102_read,
.poll = sn9c102_poll, .poll = sn9c102_poll,
.mmap = sn9c102_mmap, .mmap = sn9c102_mmap,
......
...@@ -785,7 +785,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, ...@@ -785,7 +785,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
} }
} }
struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
__u32 v4l2_id, struct uvc_control_mapping **mapping) __u32 v4l2_id, struct uvc_control_mapping **mapping)
{ {
struct uvc_control *ctrl = NULL; struct uvc_control *ctrl = NULL;
...@@ -944,6 +944,52 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, ...@@ -944,6 +944,52 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
return ret; return ret;
} }
/*
* Mapping V4L2 controls to UVC controls can be straighforward if done well.
* Most of the UVC controls exist in V4L2, and can be mapped directly. Some
* must be grouped (for instance the Red Balance, Blue Balance and Do White
* Balance V4L2 controls use the White Balance Component UVC control) or
* otherwise translated. The approach we take here is to use a translation
* table for the controls that can be mapped directly, and handle the others
* manually.
*/
int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
struct v4l2_querymenu *query_menu)
{
struct uvc_menu_info *menu_info;
struct uvc_control_mapping *mapping;
struct uvc_control *ctrl;
u32 index = query_menu->index;
u32 id = query_menu->id;
int ret;
memset(query_menu, 0, sizeof(*query_menu));
query_menu->id = id;
query_menu->index = index;
ret = mutex_lock_interruptible(&chain->ctrl_mutex);
if (ret < 0)
return -ERESTARTSYS;
ctrl = uvc_find_control(chain, query_menu->id, &mapping);
if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
ret = -EINVAL;
goto done;
}
if (query_menu->index >= mapping->menu_count) {
ret = -EINVAL;
goto done;
}
menu_info = &mapping->menu_info[query_menu->index];
strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
done:
mutex_unlock(&chain->ctrl_mutex);
return ret;
}
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
* Control transactions * Control transactions
......
...@@ -89,6 +89,39 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, ...@@ -89,6 +89,39 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
queue->type = type; queue->type = type;
} }
/*
* Free the video buffers.
*
* This function must be called with the queue lock held.
*/
static int __uvc_free_buffers(struct uvc_video_queue *queue)
{
unsigned int i;
for (i = 0; i < queue->count; ++i) {
if (queue->buffer[i].vma_use_count != 0)
return -EBUSY;
}
if (queue->count) {
vfree(queue->mem);
queue->count = 0;
}
return 0;
}
int uvc_free_buffers(struct uvc_video_queue *queue)
{
int ret;
mutex_lock(&queue->mutex);
ret = __uvc_free_buffers(queue);
mutex_unlock(&queue->mutex);
return ret;
}
/* /*
* Allocate the video buffers. * Allocate the video buffers.
* *
...@@ -110,7 +143,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, ...@@ -110,7 +143,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
mutex_lock(&queue->mutex); mutex_lock(&queue->mutex);
if ((ret = uvc_free_buffers(queue)) < 0) if ((ret = __uvc_free_buffers(queue)) < 0)
goto done; goto done;
/* Bail out if no buffers should be allocated. */ /* Bail out if no buffers should be allocated. */
...@@ -151,28 +184,6 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, ...@@ -151,28 +184,6 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
return ret; return ret;
} }
/*
* Free the video buffers.
*
* This function must be called with the queue lock held.
*/
int uvc_free_buffers(struct uvc_video_queue *queue)
{
unsigned int i;
for (i = 0; i < queue->count; ++i) {
if (queue->buffer[i].vma_use_count != 0)
return -EBUSY;
}
if (queue->count) {
vfree(queue->mem);
queue->count = 0;
}
return 0;
}
/* /*
* Check if buffers have been allocated. * Check if buffers have been allocated.
*/ */
...@@ -368,6 +379,82 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue, ...@@ -368,6 +379,82 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue,
return ret; return ret;
} }
/*
* VMA operations.
*/
static void uvc_vm_open(struct vm_area_struct *vma)
{
struct uvc_buffer *buffer = vma->vm_private_data;
buffer->vma_use_count++;
}
static void uvc_vm_close(struct vm_area_struct *vma)
{
struct uvc_buffer *buffer = vma->vm_private_data;
buffer->vma_use_count--;
}
static const struct vm_operations_struct uvc_vm_ops = {
.open = uvc_vm_open,
.close = uvc_vm_close,
};
/*
* Memory-map a video buffer.
*
* This function implements video buffers memory mapping and is intended to be
* used by the device mmap handler.
*/
int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
{
struct uvc_buffer *uninitialized_var(buffer);
struct page *page;
unsigned long addr, start, size;
unsigned int i;
int ret = 0;
start = vma->vm_start;
size = vma->vm_end - vma->vm_start;
mutex_lock(&queue->mutex);
for (i = 0; i < queue->count; ++i) {
buffer = &queue->buffer[i];
if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
break;
}
if (i == queue->count || size != queue->buf_size) {
ret = -EINVAL;
goto done;
}
/*
* VM_IO marks the area as being an mmaped region for I/O to a
* device. It also prevents the region from being core dumped.
*/
vma->vm_flags |= VM_IO;
addr = (unsigned long)queue->mem + buffer->buf.m.offset;
while (size > 0) {
page = vmalloc_to_page((void *)addr);
if ((ret = vm_insert_page(vma, start, page)) < 0)
goto done;
start += PAGE_SIZE;
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
vma->vm_ops = &uvc_vm_ops;
vma->vm_private_data = buffer;
uvc_vm_open(vma);
done:
mutex_unlock(&queue->mutex);
return ret;
}
/* /*
* Poll the video queue. * Poll the video queue.
* *
......
...@@ -100,40 +100,6 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, ...@@ -100,40 +100,6 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
* V4L2 interface * V4L2 interface
*/ */
/*
* Mapping V4L2 controls to UVC controls can be straighforward if done well.
* Most of the UVC controls exist in V4L2, and can be mapped directly. Some
* must be grouped (for instance the Red Balance, Blue Balance and Do White
* Balance V4L2 controls use the White Balance Component UVC control) or
* otherwise translated. The approach we take here is to use a translation
* table for the controls that can be mapped directly, and handle the others
* manually.
*/
static int uvc_v4l2_query_menu(struct uvc_video_chain *chain,
struct v4l2_querymenu *query_menu)
{
struct uvc_menu_info *menu_info;
struct uvc_control_mapping *mapping;
struct uvc_control *ctrl;
u32 index = query_menu->index;
u32 id = query_menu->id;
ctrl = uvc_find_control(chain, query_menu->id, &mapping);
if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
return -EINVAL;
if (query_menu->index >= mapping->menu_count)
return -EINVAL;
memset(query_menu, 0, sizeof(*query_menu));
query_menu->id = id;
query_menu->index = index;
menu_info = &mapping->menu_info[query_menu->index];
strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
return 0;
}
/* /*
* Find the frame interval closest to the requested frame interval for the * Find the frame interval closest to the requested frame interval for the
* given frame format and size. This should be done by the device as part of * given frame format and size. This should be done by the device as part of
...@@ -260,12 +226,14 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, ...@@ -260,12 +226,14 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
* developers test their webcams with the Linux driver as well as with * developers test their webcams with the Linux driver as well as with
* the Windows driver). * the Windows driver).
*/ */
mutex_lock(&stream->mutex);
if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
probe->dwMaxVideoFrameSize = probe->dwMaxVideoFrameSize =
stream->ctrl.dwMaxVideoFrameSize; stream->ctrl.dwMaxVideoFrameSize;
/* Probe the device. */ /* Probe the device. */
ret = uvc_probe_video(stream, probe); ret = uvc_probe_video(stream, probe);
mutex_unlock(&stream->mutex);
if (ret < 0) if (ret < 0)
goto done; goto done;
...@@ -289,14 +257,21 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, ...@@ -289,14 +257,21 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
static int uvc_v4l2_get_format(struct uvc_streaming *stream, static int uvc_v4l2_get_format(struct uvc_streaming *stream,
struct v4l2_format *fmt) struct v4l2_format *fmt)
{ {
struct uvc_format *format = stream->cur_format; struct uvc_format *format;
struct uvc_frame *frame = stream->cur_frame; struct uvc_frame *frame;
int ret = 0;
if (fmt->type != stream->type) if (fmt->type != stream->type)
return -EINVAL; return -EINVAL;
if (format == NULL || frame == NULL) mutex_lock(&stream->mutex);
return -EINVAL; format = stream->cur_format;
frame = stream->cur_frame;
if (format == NULL || frame == NULL) {
ret = -EINVAL;
goto done;
}
fmt->fmt.pix.pixelformat = format->fcc; fmt->fmt.pix.pixelformat = format->fcc;
fmt->fmt.pix.width = frame->wWidth; fmt->fmt.pix.width = frame->wWidth;
...@@ -307,7 +282,9 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream, ...@@ -307,7 +282,9 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream,
fmt->fmt.pix.colorspace = format->colorspace; fmt->fmt.pix.colorspace = format->colorspace;
fmt->fmt.pix.priv = 0; fmt->fmt.pix.priv = 0;
return 0; done:
mutex_unlock(&stream->mutex);
return ret;
} }
static int uvc_v4l2_set_format(struct uvc_streaming *stream, static int uvc_v4l2_set_format(struct uvc_streaming *stream,
...@@ -321,18 +298,24 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream, ...@@ -321,18 +298,24 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream,
if (fmt->type != stream->type) if (fmt->type != stream->type)
return -EINVAL; return -EINVAL;
if (uvc_queue_allocated(&stream->queue))
return -EBUSY;
ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame); ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame);
if (ret < 0) if (ret < 0)
return ret; return ret;
mutex_lock(&stream->mutex);
if (uvc_queue_allocated(&stream->queue)) {
ret = -EBUSY;
goto done;
}
memcpy(&stream->ctrl, &probe, sizeof probe); memcpy(&stream->ctrl, &probe, sizeof probe);
stream->cur_format = format; stream->cur_format = format;
stream->cur_frame = frame; stream->cur_frame = frame;
return 0; done:
mutex_unlock(&stream->mutex);
return ret;
} }
static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
...@@ -343,7 +326,10 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, ...@@ -343,7 +326,10 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
if (parm->type != stream->type) if (parm->type != stream->type)
return -EINVAL; return -EINVAL;
mutex_lock(&stream->mutex);
numerator = stream->ctrl.dwFrameInterval; numerator = stream->ctrl.dwFrameInterval;
mutex_unlock(&stream->mutex);
denominator = 10000000; denominator = 10000000;
uvc_simplify_fraction(&numerator, &denominator, 8, 333); uvc_simplify_fraction(&numerator, &denominator, 8, 333);
...@@ -370,7 +356,6 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, ...@@ -370,7 +356,6 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
struct v4l2_streamparm *parm) struct v4l2_streamparm *parm)
{ {
struct uvc_frame *frame = stream->cur_frame;
struct uvc_streaming_control probe; struct uvc_streaming_control probe;
struct v4l2_fract timeperframe; struct v4l2_fract timeperframe;
uint32_t interval; uint32_t interval;
...@@ -379,28 +364,36 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, ...@@ -379,28 +364,36 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
if (parm->type != stream->type) if (parm->type != stream->type)
return -EINVAL; return -EINVAL;
if (uvc_queue_streaming(&stream->queue))
return -EBUSY;
if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
timeperframe = parm->parm.capture.timeperframe; timeperframe = parm->parm.capture.timeperframe;
else else
timeperframe = parm->parm.output.timeperframe; timeperframe = parm->parm.output.timeperframe;
memcpy(&probe, &stream->ctrl, sizeof probe);
interval = uvc_fraction_to_interval(timeperframe.numerator, interval = uvc_fraction_to_interval(timeperframe.numerator,
timeperframe.denominator); timeperframe.denominator);
uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n", uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
timeperframe.numerator, timeperframe.denominator, interval); timeperframe.numerator, timeperframe.denominator, interval);
probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
mutex_lock(&stream->mutex);
if (uvc_queue_streaming(&stream->queue)) {
mutex_unlock(&stream->mutex);
return -EBUSY;
}
memcpy(&probe, &stream->ctrl, sizeof probe);
probe.dwFrameInterval =
uvc_try_frame_interval(stream->cur_frame, interval);
/* Probe the device with the new settings. */ /* Probe the device with the new settings. */
ret = uvc_probe_video(stream, &probe); ret = uvc_probe_video(stream, &probe);
if (ret < 0) if (ret < 0) {
mutex_unlock(&stream->mutex);
return ret; return ret;
}
memcpy(&stream->ctrl, &probe, sizeof probe); memcpy(&stream->ctrl, &probe, sizeof probe);
mutex_unlock(&stream->mutex);
/* Return the actual frame period. */ /* Return the actual frame period. */
timeperframe.numerator = probe.dwFrameInterval; timeperframe.numerator = probe.dwFrameInterval;
...@@ -528,11 +521,9 @@ static int uvc_v4l2_release(struct file *file) ...@@ -528,11 +521,9 @@ static int uvc_v4l2_release(struct file *file)
if (uvc_has_privileges(handle)) { if (uvc_has_privileges(handle)) {
uvc_video_enable(stream, 0); uvc_video_enable(stream, 0);
mutex_lock(&stream->queue.mutex);
if (uvc_free_buffers(&stream->queue) < 0) if (uvc_free_buffers(&stream->queue) < 0)
uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to " uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
"free buffers.\n"); "free buffers.\n");
mutex_unlock(&stream->queue.mutex);
} }
/* Release the file handle. */ /* Release the file handle. */
...@@ -624,7 +615,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -624,7 +615,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
} }
case VIDIOC_QUERYMENU: case VIDIOC_QUERYMENU:
return uvc_v4l2_query_menu(chain, arg); return uvc_query_v4l2_menu(chain, arg);
case VIDIOC_G_EXT_CTRLS: case VIDIOC_G_EXT_CTRLS:
{ {
...@@ -905,15 +896,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -905,15 +896,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_CROPCAP: case VIDIOC_CROPCAP:
{ {
struct v4l2_cropcap *ccap = arg; struct v4l2_cropcap *ccap = arg;
struct uvc_frame *frame = stream->cur_frame;
if (ccap->type != stream->type) if (ccap->type != stream->type)
return -EINVAL; return -EINVAL;
ccap->bounds.left = 0; ccap->bounds.left = 0;
ccap->bounds.top = 0; ccap->bounds.top = 0;
ccap->bounds.width = frame->wWidth;
ccap->bounds.height = frame->wHeight; mutex_lock(&stream->mutex);
ccap->bounds.width = stream->cur_frame->wWidth;
ccap->bounds.height = stream->cur_frame->wHeight;
mutex_unlock(&stream->mutex);
ccap->defrect = ccap->bounds; ccap->defrect = ccap->bounds;
...@@ -930,8 +923,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -930,8 +923,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_REQBUFS: case VIDIOC_REQBUFS:
{ {
struct v4l2_requestbuffers *rb = arg; struct v4l2_requestbuffers *rb = arg;
unsigned int bufsize =
stream->ctrl.dwMaxVideoFrameSize;
if (rb->type != stream->type || if (rb->type != stream->type ||
rb->memory != V4L2_MEMORY_MMAP) rb->memory != V4L2_MEMORY_MMAP)
...@@ -940,7 +931,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -940,7 +931,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if ((ret = uvc_acquire_privileges(handle)) < 0) if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret; return ret;
ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize); mutex_lock(&stream->mutex);
ret = uvc_alloc_buffers(&stream->queue, rb->count,
stream->ctrl.dwMaxVideoFrameSize);
mutex_unlock(&stream->mutex);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -988,7 +982,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -988,7 +982,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (!uvc_has_privileges(handle)) if (!uvc_has_privileges(handle))
return -EBUSY; return -EBUSY;
mutex_lock(&stream->mutex);
ret = uvc_video_enable(stream, 1); ret = uvc_video_enable(stream, 1);
mutex_unlock(&stream->mutex);
if (ret < 0) if (ret < 0)
return ret; return ret;
break; break;
...@@ -1068,79 +1064,14 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data, ...@@ -1068,79 +1064,14 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
return -EINVAL; return -EINVAL;
} }
/*
* VMA operations.
*/
static void uvc_vm_open(struct vm_area_struct *vma)
{
struct uvc_buffer *buffer = vma->vm_private_data;
buffer->vma_use_count++;
}
static void uvc_vm_close(struct vm_area_struct *vma)
{
struct uvc_buffer *buffer = vma->vm_private_data;
buffer->vma_use_count--;
}
static const struct vm_operations_struct uvc_vm_ops = {
.open = uvc_vm_open,
.close = uvc_vm_close,
};
static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
{ {
struct uvc_fh *handle = file->private_data; struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream; struct uvc_streaming *stream = handle->stream;
struct uvc_video_queue *queue = &stream->queue;
struct uvc_buffer *uninitialized_var(buffer);
struct page *page;
unsigned long addr, start, size;
unsigned int i;
int ret = 0;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n"); uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n");
start = vma->vm_start; return uvc_queue_mmap(&stream->queue, vma);
size = vma->vm_end - vma->vm_start;
mutex_lock(&queue->mutex);
for (i = 0; i < queue->count; ++i) {
buffer = &queue->buffer[i];
if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
break;
}
if (i == queue->count || size != queue->buf_size) {
ret = -EINVAL;
goto done;
}
/*
* VM_IO marks the area as being an mmaped region for I/O to a
* device. It also prevents the region from being core dumped.
*/
vma->vm_flags |= VM_IO;
addr = (unsigned long)queue->mem + buffer->buf.m.offset;
while (size > 0) {
page = vmalloc_to_page((void *)addr);
if ((ret = vm_insert_page(vma, start, page)) < 0)
goto done;
start += PAGE_SIZE;
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
vma->vm_ops = &uvc_vm_ops;
vma->vm_private_data = buffer;
uvc_vm_open(vma);
done:
mutex_unlock(&queue->mutex);
return ret;
} }
static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
...@@ -1157,7 +1088,7 @@ const struct v4l2_file_operations uvc_fops = { ...@@ -1157,7 +1088,7 @@ const struct v4l2_file_operations uvc_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = uvc_v4l2_open, .open = uvc_v4l2_open,
.release = uvc_v4l2_release, .release = uvc_v4l2_release,
.ioctl = uvc_v4l2_ioctl, .unlocked_ioctl = uvc_v4l2_ioctl,
.read = uvc_v4l2_read, .read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap, .mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll, .poll = uvc_v4l2_poll,
......
...@@ -293,8 +293,6 @@ int uvc_probe_video(struct uvc_streaming *stream, ...@@ -293,8 +293,6 @@ int uvc_probe_video(struct uvc_streaming *stream,
unsigned int i; unsigned int i;
int ret; int ret;
mutex_lock(&stream->mutex);
/* Perform probing. The device should adjust the requested values /* Perform probing. The device should adjust the requested values
* according to its capabilities. However, some devices, namely the * according to its capabilities. However, some devices, namely the
* first generation UVC Logitech webcams, don't implement the Video * first generation UVC Logitech webcams, don't implement the Video
...@@ -346,7 +344,6 @@ int uvc_probe_video(struct uvc_streaming *stream, ...@@ -346,7 +344,6 @@ int uvc_probe_video(struct uvc_streaming *stream,
} }
done: done:
mutex_unlock(&stream->mutex);
return ret; return ret;
} }
......
...@@ -436,7 +436,9 @@ struct uvc_streaming { ...@@ -436,7 +436,9 @@ struct uvc_streaming {
struct uvc_streaming_control ctrl; struct uvc_streaming_control ctrl;
struct uvc_format *cur_format; struct uvc_format *cur_format;
struct uvc_frame *cur_frame; struct uvc_frame *cur_frame;
/* Protect access to ctrl, cur_format, cur_frame and hardware video
* probe control.
*/
struct mutex mutex; struct mutex mutex;
unsigned int frozen : 1; unsigned int frozen : 1;
...@@ -574,6 +576,8 @@ extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable); ...@@ -574,6 +576,8 @@ extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
struct uvc_buffer *buf); struct uvc_buffer *buf);
extern int uvc_queue_mmap(struct uvc_video_queue *queue,
struct vm_area_struct *vma);
extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue, extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
struct file *file, poll_table *wait); struct file *file, poll_table *wait);
extern int uvc_queue_allocated(struct uvc_video_queue *queue); extern int uvc_queue_allocated(struct uvc_video_queue *queue);
...@@ -606,10 +610,10 @@ extern int uvc_status_suspend(struct uvc_device *dev); ...@@ -606,10 +610,10 @@ extern int uvc_status_suspend(struct uvc_device *dev);
extern int uvc_status_resume(struct uvc_device *dev); extern int uvc_status_resume(struct uvc_device *dev);
/* Controls */ /* Controls */
extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
__u32 v4l2_id, struct uvc_control_mapping **mapping);
extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl); struct v4l2_queryctrl *v4l2_ctrl);
extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
struct v4l2_querymenu *query_menu);
extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
const struct uvc_control_mapping *mapping); const struct uvc_control_mapping *mapping);
......
...@@ -186,12 +186,12 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf, ...@@ -186,12 +186,12 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf,
size_t sz, loff_t *off) size_t sz, loff_t *off)
{ {
struct video_device *vdev = video_devdata(filp); struct video_device *vdev = video_devdata(filp);
int ret = -EIO; int ret = -ENODEV;
if (!vdev->fops->read) if (!vdev->fops->read)
return -EINVAL; return -EINVAL;
if (vdev->lock) if (vdev->lock && mutex_lock_interruptible(vdev->lock))
mutex_lock(vdev->lock); return -ERESTARTSYS;
if (video_is_registered(vdev)) if (video_is_registered(vdev))
ret = vdev->fops->read(filp, buf, sz, off); ret = vdev->fops->read(filp, buf, sz, off);
if (vdev->lock) if (vdev->lock)
...@@ -203,12 +203,12 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, ...@@ -203,12 +203,12 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
size_t sz, loff_t *off) size_t sz, loff_t *off)
{ {
struct video_device *vdev = video_devdata(filp); struct video_device *vdev = video_devdata(filp);
int ret = -EIO; int ret = -ENODEV;
if (!vdev->fops->write) if (!vdev->fops->write)
return -EINVAL; return -EINVAL;
if (vdev->lock) if (vdev->lock && mutex_lock_interruptible(vdev->lock))
mutex_lock(vdev->lock); return -ERESTARTSYS;
if (video_is_registered(vdev)) if (video_is_registered(vdev))
ret = vdev->fops->write(filp, buf, sz, off); ret = vdev->fops->write(filp, buf, sz, off);
if (vdev->lock) if (vdev->lock)
...@@ -219,10 +219,10 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, ...@@ -219,10 +219,10 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll) static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
{ {
struct video_device *vdev = video_devdata(filp); struct video_device *vdev = video_devdata(filp);
int ret = DEFAULT_POLLMASK; int ret = POLLERR | POLLHUP;
if (!vdev->fops->poll) if (!vdev->fops->poll)
return ret; return DEFAULT_POLLMASK;
if (vdev->lock) if (vdev->lock)
mutex_lock(vdev->lock); mutex_lock(vdev->lock);
if (video_is_registered(vdev)) if (video_is_registered(vdev))
...@@ -238,20 +238,45 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -238,20 +238,45 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
int ret = -ENODEV; int ret = -ENODEV;
if (vdev->fops->unlocked_ioctl) { if (vdev->fops->unlocked_ioctl) {
if (vdev->lock) if (vdev->lock && mutex_lock_interruptible(vdev->lock))
mutex_lock(vdev->lock); return -ERESTARTSYS;
if (video_is_registered(vdev)) if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
if (vdev->lock) if (vdev->lock)
mutex_unlock(vdev->lock); mutex_unlock(vdev->lock);
} else if (vdev->fops->ioctl) { } else if (vdev->fops->ioctl) {
/* TODO: convert all drivers to unlocked_ioctl */ /* This code path is a replacement for the BKL. It is a major
* hack but it will have to do for those drivers that are not
* yet converted to use unlocked_ioctl.
*
* There are two options: if the driver implements struct
* v4l2_device, then the lock defined there is used to
* serialize the ioctls. Otherwise the v4l2 core lock defined
* below is used. This lock is really bad since it serializes
* completely independent devices.
*
* Both variants suffer from the same problem: if the driver
* sleeps, then it blocks all ioctls since the lock is still
* held. This is very common for VIDIOC_DQBUF since that
* normally waits for a frame to arrive. As a result any other
* ioctl calls will proceed very, very slowly since each call
* will have to wait for the VIDIOC_QBUF to finish. Things that
* should take 0.01s may now take 10-20 seconds.
*
* The workaround is to *not* take the lock for VIDIOC_DQBUF.
* This actually works OK for videobuf-based drivers, since
* videobuf will take its own internal lock.
*/
static DEFINE_MUTEX(v4l2_ioctl_mutex); static DEFINE_MUTEX(v4l2_ioctl_mutex);
struct mutex *m = vdev->v4l2_dev ?
&vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex;
mutex_lock(&v4l2_ioctl_mutex); if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m))
return -ERESTARTSYS;
if (video_is_registered(vdev)) if (video_is_registered(vdev))
ret = vdev->fops->ioctl(filp, cmd, arg); ret = vdev->fops->ioctl(filp, cmd, arg);
mutex_unlock(&v4l2_ioctl_mutex); if (cmd != VIDIOC_DQBUF)
mutex_unlock(m);
} else } else
ret = -ENOTTY; ret = -ENOTTY;
...@@ -265,8 +290,8 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) ...@@ -265,8 +290,8 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
if (!vdev->fops->mmap) if (!vdev->fops->mmap)
return ret; return ret;
if (vdev->lock) if (vdev->lock && mutex_lock_interruptible(vdev->lock))
mutex_lock(vdev->lock); return -ERESTARTSYS;
if (video_is_registered(vdev)) if (video_is_registered(vdev))
ret = vdev->fops->mmap(filp, vm); ret = vdev->fops->mmap(filp, vm);
if (vdev->lock) if (vdev->lock)
...@@ -284,7 +309,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) ...@@ -284,7 +309,7 @@ static int v4l2_open(struct inode *inode, struct file *filp)
mutex_lock(&videodev_lock); mutex_lock(&videodev_lock);
vdev = video_devdata(filp); vdev = video_devdata(filp);
/* return ENODEV if the video device has already been removed. */ /* return ENODEV if the video device has already been removed. */
if (vdev == NULL) { if (vdev == NULL || !video_is_registered(vdev)) {
mutex_unlock(&videodev_lock); mutex_unlock(&videodev_lock);
return -ENODEV; return -ENODEV;
} }
...@@ -292,8 +317,10 @@ static int v4l2_open(struct inode *inode, struct file *filp) ...@@ -292,8 +317,10 @@ static int v4l2_open(struct inode *inode, struct file *filp)
video_get(vdev); video_get(vdev);
mutex_unlock(&videodev_lock); mutex_unlock(&videodev_lock);
if (vdev->fops->open) { if (vdev->fops->open) {
if (vdev->lock) if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
mutex_lock(vdev->lock); ret = -ERESTARTSYS;
goto err;
}
if (video_is_registered(vdev)) if (video_is_registered(vdev))
ret = vdev->fops->open(filp); ret = vdev->fops->open(filp);
else else
...@@ -302,6 +329,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) ...@@ -302,6 +329,7 @@ static int v4l2_open(struct inode *inode, struct file *filp)
mutex_unlock(vdev->lock); mutex_unlock(vdev->lock);
} }
err:
/* decrease the refcount in case of an error */ /* decrease the refcount in case of an error */
if (ret) if (ret)
video_put(vdev); video_put(vdev);
...@@ -596,7 +624,12 @@ void video_unregister_device(struct video_device *vdev) ...@@ -596,7 +624,12 @@ void video_unregister_device(struct video_device *vdev)
if (!vdev || !video_is_registered(vdev)) if (!vdev || !video_is_registered(vdev))
return; return;
mutex_lock(&videodev_lock);
/* This must be in a critical section to prevent a race with v4l2_open.
* Once this bit has been cleared video_get may never be called again.
*/
clear_bit(V4L2_FL_REGISTERED, &vdev->flags); clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
mutex_unlock(&videodev_lock);
device_unregister(&vdev->dev); device_unregister(&vdev->dev);
} }
EXPORT_SYMBOL(video_unregister_device); EXPORT_SYMBOL(video_unregister_device);
......
...@@ -35,6 +35,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) ...@@ -35,6 +35,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
INIT_LIST_HEAD(&v4l2_dev->subdevs); INIT_LIST_HEAD(&v4l2_dev->subdevs);
spin_lock_init(&v4l2_dev->lock); spin_lock_init(&v4l2_dev->lock);
mutex_init(&v4l2_dev->ioctl_lock);
v4l2_dev->dev = dev; v4l2_dev->dev = dev;
if (dev == NULL) { if (dev == NULL) {
/* If dev == NULL, then name must be filled in by the caller */ /* If dev == NULL, then name must be filled in by the caller */
......
...@@ -815,7 +815,7 @@ static ssize_t w9966_v4l_read(struct file *file, char __user *buf, ...@@ -815,7 +815,7 @@ static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
static const struct v4l2_file_operations w9966_fops = { static const struct v4l2_file_operations w9966_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
.read = w9966_v4l_read, .read = w9966_v4l_read,
}; };
......
...@@ -51,6 +51,8 @@ struct v4l2_device { ...@@ -51,6 +51,8 @@ struct v4l2_device {
unsigned int notification, void *arg); unsigned int notification, void *arg);
/* The control handler. May be NULL. */ /* The control handler. May be NULL. */
struct v4l2_ctrl_handler *ctrl_handler; struct v4l2_ctrl_handler *ctrl_handler;
/* BKL replacement mutex. Temporary solution only. */
struct mutex ioctl_lock;
}; };
/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev. /* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev.
......
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