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,
static const struct v4l2_file_operations rtrack_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops rtrack_ioctl_ops = {
......@@ -412,13 +412,6 @@ static int __init rtrack_init(void)
rt->vdev.release = video_device_release_empty;
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 */
mutex_init(&rt->lock);
......@@ -430,6 +423,13 @@ static int __init rtrack_init(void)
sleep_delay(2000000); /* make sure it's totally down */
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;
}
......
......@@ -324,7 +324,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
static const struct v4l2_file_operations aztech_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
......@@ -375,6 +375,8 @@ static int __init aztech_init(void)
az->vdev.ioctl_ops = &aztech_ioctl_ops;
az->vdev.release = video_device_release_empty;
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) {
v4l2_device_unregister(v4l2_dev);
......@@ -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");
/* mute card - prevents noisy bootups */
outb(0, az->io);
return 0;
}
......
......@@ -328,11 +328,10 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
unsigned char readbuf[RDS_BUFFER];
int i = 0;
mutex_lock(&dev->lock);
if (dev->rdsstat == 0) {
mutex_lock(&dev->lock);
dev->rdsstat = 1;
outb(0x80, dev->io); /* Select RDS fifo */
mutex_unlock(&dev->lock);
init_timer(&dev->readtimer);
dev->readtimer.function = cadet_handler;
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
add_timer(&dev->readtimer);
}
if (dev->rdsin == dev->rdsout) {
mutex_unlock(&dev->lock);
if (file->f_flags & O_NONBLOCK)
return -EWOULDBLOCK;
interruptible_sleep_on(&dev->read_queue);
mutex_lock(&dev->lock);
}
while (i < count && dev->rdsin != dev->rdsout)
readbuf[i++] = dev->rdsbuf[dev->rdsout++];
mutex_unlock(&dev->lock);
if (copy_to_user(data, readbuf, i))
return -EFAULT;
......@@ -525,9 +527,11 @@ static int cadet_open(struct file *file)
{
struct cadet *dev = video_drvdata(file);
mutex_lock(&dev->lock);
dev->users++;
if (1 == dev->users)
init_waitqueue_head(&dev->read_queue);
mutex_unlock(&dev->lock);
return 0;
}
......@@ -535,11 +539,13 @@ static int cadet_release(struct file *file)
{
struct cadet *dev = video_drvdata(file);
mutex_lock(&dev->lock);
dev->users--;
if (0 == dev->users) {
del_timer_sync(&dev->readtimer);
dev->rdsstat = 0;
}
mutex_unlock(&dev->lock);
return 0;
}
......@@ -559,7 +565,7 @@ static const struct v4l2_file_operations cadet_fops = {
.open = cadet_open,
.release = cadet_release,
.read = cadet_read,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
.poll = cadet_poll,
};
......
......@@ -361,7 +361,7 @@ MODULE_DEVICE_TABLE(pci, gemtek_pci_id);
static const struct v4l2_file_operations gemtek_pci_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
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
card->vdev.release = video_device_release_empty;
video_set_drvdata(&card->vdev, card);
gemtek_pci_mute(card);
if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0)
goto err_video;
gemtek_pci_mute(card);
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);
......
......@@ -378,7 +378,7 @@ static int gemtek_probe(struct gemtek *gt)
static const struct v4l2_file_operations gemtek_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static int vidioc_querycap(struct file *file, void *priv,
......@@ -577,12 +577,6 @@ static int __init gemtek_init(void)
gt->vdev.release = video_device_release_empty;
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 */
gt->lastfreq = GEMTEK_LOWFREQ;
gt->bu2614data = 0;
......@@ -590,6 +584,12 @@ static int __init gemtek_init(void)
if (initmute)
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;
}
......
......@@ -299,7 +299,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations maestro_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
......@@ -383,22 +383,20 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
dev->vdev.release = video_device_release_empty;
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);
if (retval) {
v4l2_err(v4l2_dev, "can't register video device!\n");
goto errfr1;
}
if (!radio_power_on(dev)) {
retval = -EIO;
goto errunr;
}
v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
return 0;
errunr:
video_unregister_device(&dev->vdev);
errfr1:
v4l2_device_unregister(v4l2_dev);
errfr:
......
......@@ -346,7 +346,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
static const struct v4l2_file_operations maxiradio_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
......
......@@ -33,6 +33,7 @@ struct pcm20 {
unsigned long freq;
int muted;
struct snd_miro_aci *aci;
struct mutex lock;
};
static struct pcm20 pcm20_card = {
......@@ -72,7 +73,7 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
static const struct v4l2_file_operations pcm20_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static int vidioc_querycap(struct file *file, void *priv,
......@@ -229,7 +230,7 @@ static int __init pcm20_init(void)
return -ENODEV;
}
strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name));
mutex_init(&dev->lock);
res = v4l2_device_register(NULL, v4l2_dev);
if (res < 0) {
......@@ -242,6 +243,7 @@ static int __init pcm20_init(void)
dev->vdev.fops = &pcm20_fops;
dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
dev->vdev.release = video_device_release_empty;
dev->vdev.lock = &dev->lock;
video_set_drvdata(&dev->vdev, dev);
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,
static const struct v4l2_file_operations rtrack2_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
......@@ -315,6 +315,10 @@ static int __init rtrack2_init(void)
dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev);
/* mute card - prevents noisy bootups */
outb(1, dev->io);
dev->muted = 1;
mutex_init(&dev->lock);
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
......@@ -324,10 +328,6 @@ static int __init rtrack2_init(void)
v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
/* mute card - prevents noisy bootups */
outb(1, dev->io);
dev->muted = 1;
return 0;
}
......
......@@ -260,7 +260,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations fmi_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
......@@ -382,6 +382,9 @@ static int __init fmi_init(void)
mutex_init(&fmi->lock);
/* mute card - prevents noisy bootups */
fmi_mute(fmi);
if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(fmi->io, 2);
......@@ -391,8 +394,6 @@ static int __init fmi_init(void)
}
v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io);
/* mute card - prevents noisy bootups */
fmi_mute(fmi);
return 0;
}
......
......@@ -376,7 +376,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations fmr2_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops fmr2_ioctl_ops = {
......@@ -424,6 +424,10 @@ static int __init fmr2_init(void)
fmr2->vdev.release = video_device_release_empty;
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) {
v4l2_device_unregister(v4l2_dev);
release_region(fmr2->io, 2);
......@@ -431,11 +435,6 @@ static int __init fmr2_init(void)
}
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));
return 0;
}
......
......@@ -53,7 +53,8 @@ struct radio_si4713_device {
/* radio_si4713_fops - file operations interface */
static const struct v4l2_file_operations radio_si4713_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
/* Note: locking is done at the subdev level in the i2c driver. */
.unlocked_ioctl = video_ioctl2,
};
/* Video4Linux Interface */
......
......@@ -142,7 +142,6 @@ struct tea5764_device {
struct video_device *videodev;
struct tea5764_regs regs;
struct mutex mutex;
int users;
};
/* I2C code related */
......@@ -458,41 +457,10 @@ static int vidioc_s_audio(struct file *file, void *priv,
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 */
static const struct v4l2_file_operations tea5764_fops = {
.owner = THIS_MODULE,
.open = tea5764_open,
.release = tea5764_close,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
......@@ -527,7 +495,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
int ret;
PDEBUG("probe");
radio = kmalloc(sizeof(struct tea5764_device), GFP_KERNEL);
radio = kzalloc(sizeof(struct tea5764_device), GFP_KERNEL);
if (!radio)
return -ENOMEM;
......@@ -555,12 +523,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
i2c_set_clientdata(client, radio);
video_set_drvdata(radio->videodev, radio);
ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
if (ret < 0) {
PWARN("Could not register video device!");
goto errrel;
}
radio->videodev->lock = &radio->mutex;
/* initialize and power off the chip */
tea5764_i2c_read(radio);
......@@ -568,6 +531,12 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
tea5764_mute(radio, 1);
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.");
return 0;
errrel:
......
......@@ -338,7 +338,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations terratec_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
......@@ -389,6 +389,9 @@ static int __init terratec_init(void)
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) {
v4l2_device_unregister(&tt->v4l2_dev);
release_region(tt->io, 2);
......@@ -396,9 +399,6 @@ static int __init terratec_init(void)
}
v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n");
/* mute card - prevents noisy bootups */
tt_write_vol(tt, 0);
return 0;
}
......
......@@ -34,6 +34,7 @@ struct timbradio {
struct v4l2_subdev *sd_dsp;
struct video_device video_dev;
struct v4l2_device v4l2_dev;
struct mutex lock;
};
......@@ -142,7 +143,7 @@ static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {
static const struct v4l2_file_operations timbradio_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
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;
mutex_init(&tr->lock);
strlcpy(tr->video_dev.name, "Timberdale Radio",
sizeof(tr->video_dev.name));
......@@ -171,6 +173,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
tr->video_dev.ioctl_ops = &timbradio_ioctl_ops;
tr->video_dev.release = video_device_release_empty;
tr->video_dev.minor = -1;
tr->video_dev.lock = &tr->lock;
strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
err = v4l2_device_register(NULL, &tr->v4l2_dev);
......
......@@ -344,7 +344,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations trust_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops trust_ioctl_ops = {
......@@ -396,14 +396,6 @@ static int __init trust_init(void)
tr->vdev.release = video_device_release_empty;
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, 0xa0); /* speaker att. RF = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */
......@@ -418,6 +410,14 @@ static int __init trust_init(void)
/* mute card - prevents noisy bootups */
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;
}
......
......@@ -317,7 +317,7 @@ static int vidioc_log_status(struct file *file, void *priv)
static const struct v4l2_file_operations typhoon_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
......@@ -344,18 +344,18 @@ static int __init typhoon_init(void)
strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name));
dev->io = io;
dev->curfreq = dev->mutefreq = mutefreq;
if (dev->io == -1) {
v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n");
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, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
return -EINVAL;
}
dev->curfreq = dev->mutefreq = mutefreq << 4;
mutex_init(&dev->lock);
if (!request_region(dev->io, 8, "typhoon")) {
......@@ -378,17 +378,17 @@ static int __init typhoon_init(void)
dev->vdev.ioctl_ops = &typhoon_ioctl_ops;
dev->vdev.release = video_device_release_empty;
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) {
v4l2_device_unregister(&dev->v4l2_dev);
release_region(dev->io, 8);
return -EINVAL;
}
v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io);
v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", dev->mutefreq);
dev->mutefreq <<= 4;
/* mute card - prevents noisy bootups */
typhoon_mute(dev);
v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq);
return 0;
}
......
......@@ -377,7 +377,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations zoltrix_fops =
{
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
......@@ -424,20 +424,6 @@ static int __init zoltrix_init(void)
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);
/* mute card - prevents noisy bootups */
......@@ -452,6 +438,20 @@ static int __init zoltrix_init(void)
zol->curvol = 0;
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;
}
......
......@@ -712,7 +712,7 @@ static int ar_initialize(struct ar *ar)
static const struct v4l2_file_operations ar_fops = {
.owner = THIS_MODULE,
.read = ar_read,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops ar_ioctl_ops = {
......
......@@ -860,7 +860,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
.read = qcam_read,
};
......
......@@ -718,7 +718,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
.read = qcam_read,
};
......
......@@ -1775,7 +1775,7 @@ static const struct v4l2_file_operations cafe_v4l_fops = {
.read = cafe_v4l_read,
.poll = cafe_v4l_poll,
.mmap = cafe_v4l_mmap,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
};
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)
static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream,
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 = {
.read = cx18_v4l2_read,
.open = cx18_v4l2_open,
/* FIXME change to video_ioctl2 if serialization lock can be removed */
.ioctl = cx18_v4l2_ioctl,
.unlocked_ioctl = cx18_v4l2_ioctl,
.release = cx18_v4l2_close,
.poll = cx18_v4l2_enc_poll,
};
......
......@@ -2530,7 +2530,7 @@ static const struct v4l2_file_operations et61x251_fops = {
.owner = THIS_MODULE,
.open = et61x251_open,
.release = et61x251_release,
.ioctl = et61x251_ioctl,
.unlocked_ioctl = et61x251_ioctl,
.read = et61x251_read,
.poll = et61x251_poll,
.mmap = et61x251_mmap,
......
......@@ -1659,7 +1659,7 @@ static const struct v4l2_file_operations meye_fops = {
.open = meye_open,
.release = meye_release,
.mmap = meye_mmap,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
.poll = meye_poll,
};
......@@ -1831,12 +1831,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
msleep(1);
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);
init_waitqueue_head(&meye.proc_list);
meye.brightness = 32 << 10;
......@@ -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_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",
MEYE_DRIVER_VERSION);
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,
static const struct v4l2_file_operations pms_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
.read = pms_read,
};
......
......@@ -75,6 +75,7 @@ struct sh_vou_device {
int pix_idx;
struct videobuf_buffer *active;
enum sh_vou_status status;
struct mutex fop_lock;
};
struct sh_vou_file {
......@@ -235,7 +236,7 @@ static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb)
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,
unsigned int *size)
{
......@@ -257,7 +258,7 @@ static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
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,
struct videobuf_buffer *vb,
enum v4l2_field field)
......@@ -306,7 +307,7 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq,
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,
struct videobuf_buffer *vb)
{
......@@ -1190,7 +1191,7 @@ static int sh_vou_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_OUTPUT,
V4L2_FIELD_NONE,
sizeof(struct videobuf_buffer), vdev,
NULL);
&vou_dev->fop_lock);
return 0;
}
......@@ -1292,7 +1293,7 @@ static const struct v4l2_file_operations sh_vou_fops = {
.owner = THIS_MODULE,
.open = sh_vou_open,
.release = sh_vou_release,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
.mmap = sh_vou_mmap,
.poll = sh_vou_poll,
};
......@@ -1331,6 +1332,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&vou_dev->queue);
spin_lock_init(&vou_dev->lock);
mutex_init(&vou_dev->fop_lock);
atomic_set(&vou_dev->use_count, 0);
vou_dev->pdata = vou_pdata;
vou_dev->status = SH_VOU_IDLE;
......@@ -1388,6 +1390,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
vdev->tvnorms |= V4L2_STD_PAL;
vdev->v4l2_dev = &vou_dev->v4l2_dev;
vdev->release = video_device_release;
vdev->lock = &vou_dev->fop_lock;
vou_dev->vdev = vdev;
video_set_drvdata(vdev, vou_dev);
......
......@@ -3238,7 +3238,7 @@ static const struct v4l2_file_operations sn9c102_fops = {
.owner = THIS_MODULE,
.open = sn9c102_open,
.release = sn9c102_release,
.ioctl = sn9c102_ioctl,
.unlocked_ioctl = sn9c102_ioctl,
.read = sn9c102_read,
.poll = sn9c102_poll,
.mmap = sn9c102_mmap,
......
......@@ -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)
{
struct uvc_control *ctrl = NULL;
......@@ -944,6 +944,52 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
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
......
......@@ -89,6 +89,39 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_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.
*
......@@ -110,7 +143,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
mutex_lock(&queue->mutex);
if ((ret = uvc_free_buffers(queue)) < 0)
if ((ret = __uvc_free_buffers(queue)) < 0)
goto done;
/* Bail out if no buffers should be allocated. */
......@@ -151,28 +184,6 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
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.
*/
......@@ -368,6 +379,82 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue,
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.
*
......
......@@ -100,40 +100,6 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
* 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
* 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,
* developers test their webcams with the Linux driver as well as with
* the Windows driver).
*/
mutex_lock(&stream->mutex);
if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
probe->dwMaxVideoFrameSize =
stream->ctrl.dwMaxVideoFrameSize;
/* Probe the device. */
ret = uvc_probe_video(stream, probe);
mutex_unlock(&stream->mutex);
if (ret < 0)
goto done;
......@@ -289,14 +257,21 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
static int uvc_v4l2_get_format(struct uvc_streaming *stream,
struct v4l2_format *fmt)
{
struct uvc_format *format = stream->cur_format;
struct uvc_frame *frame = stream->cur_frame;
struct uvc_format *format;
struct uvc_frame *frame;
int ret = 0;
if (fmt->type != stream->type)
return -EINVAL;
if (format == NULL || frame == NULL)
return -EINVAL;
mutex_lock(&stream->mutex);
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.width = frame->wWidth;
......@@ -307,7 +282,9 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream,
fmt->fmt.pix.colorspace = format->colorspace;
fmt->fmt.pix.priv = 0;
return 0;
done:
mutex_unlock(&stream->mutex);
return ret;
}
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)
return -EINVAL;
if (uvc_queue_allocated(&stream->queue))
return -EBUSY;
ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame);
if (ret < 0)
return ret;
mutex_lock(&stream->mutex);
if (uvc_queue_allocated(&stream->queue)) {
ret = -EBUSY;
goto done;
}
memcpy(&stream->ctrl, &probe, sizeof probe);
stream->cur_format = format;
stream->cur_frame = frame;
return 0;
done:
mutex_unlock(&stream->mutex);
return ret;
}
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)
return -EINVAL;
mutex_lock(&stream->mutex);
numerator = stream->ctrl.dwFrameInterval;
mutex_unlock(&stream->mutex);
denominator = 10000000;
uvc_simplify_fraction(&numerator, &denominator, 8, 333);
......@@ -370,7 +356,6 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
struct v4l2_streamparm *parm)
{
struct uvc_frame *frame = stream->cur_frame;
struct uvc_streaming_control probe;
struct v4l2_fract timeperframe;
uint32_t interval;
......@@ -379,28 +364,36 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
if (parm->type != stream->type)
return -EINVAL;
if (uvc_queue_streaming(&stream->queue))
return -EBUSY;
if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
timeperframe = parm->parm.capture.timeperframe;
else
timeperframe = parm->parm.output.timeperframe;
memcpy(&probe, &stream->ctrl, sizeof probe);
interval = uvc_fraction_to_interval(timeperframe.numerator,
timeperframe.denominator);
uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
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. */
ret = uvc_probe_video(stream, &probe);
if (ret < 0)
if (ret < 0) {
mutex_unlock(&stream->mutex);
return ret;
}
memcpy(&stream->ctrl, &probe, sizeof probe);
mutex_unlock(&stream->mutex);
/* Return the actual frame period. */
timeperframe.numerator = probe.dwFrameInterval;
......@@ -528,11 +521,9 @@ static int uvc_v4l2_release(struct file *file)
if (uvc_has_privileges(handle)) {
uvc_video_enable(stream, 0);
mutex_lock(&stream->queue.mutex);
if (uvc_free_buffers(&stream->queue) < 0)
uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
"free buffers.\n");
mutex_unlock(&stream->queue.mutex);
}
/* Release the file handle. */
......@@ -624,7 +615,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
}
case VIDIOC_QUERYMENU:
return uvc_v4l2_query_menu(chain, arg);
return uvc_query_v4l2_menu(chain, arg);
case VIDIOC_G_EXT_CTRLS:
{
......@@ -905,15 +896,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_CROPCAP:
{
struct v4l2_cropcap *ccap = arg;
struct uvc_frame *frame = stream->cur_frame;
if (ccap->type != stream->type)
return -EINVAL;
ccap->bounds.left = 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;
......@@ -930,8 +923,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_REQBUFS:
{
struct v4l2_requestbuffers *rb = arg;
unsigned int bufsize =
stream->ctrl.dwMaxVideoFrameSize;
if (rb->type != stream->type ||
rb->memory != V4L2_MEMORY_MMAP)
......@@ -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)
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)
return ret;
......@@ -988,7 +982,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (!uvc_has_privileges(handle))
return -EBUSY;
mutex_lock(&stream->mutex);
ret = uvc_video_enable(stream, 1);
mutex_unlock(&stream->mutex);
if (ret < 0)
return ret;
break;
......@@ -1068,79 +1064,14 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
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)
{
struct uvc_fh *handle = file->private_data;
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");
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;
return uvc_queue_mmap(&stream->queue, vma);
}
static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
......@@ -1157,7 +1088,7 @@ const struct v4l2_file_operations uvc_fops = {
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
.ioctl = uvc_v4l2_ioctl,
.unlocked_ioctl = uvc_v4l2_ioctl,
.read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
......
......@@ -293,8 +293,6 @@ int uvc_probe_video(struct uvc_streaming *stream,
unsigned int i;
int ret;
mutex_lock(&stream->mutex);
/* Perform probing. The device should adjust the requested values
* according to its capabilities. However, some devices, namely the
* first generation UVC Logitech webcams, don't implement the Video
......@@ -346,7 +344,6 @@ int uvc_probe_video(struct uvc_streaming *stream,
}
done:
mutex_unlock(&stream->mutex);
return ret;
}
......
......@@ -436,7 +436,9 @@ struct uvc_streaming {
struct uvc_streaming_control ctrl;
struct uvc_format *cur_format;
struct uvc_frame *cur_frame;
/* Protect access to ctrl, cur_format, cur_frame and hardware video
* probe control.
*/
struct mutex mutex;
unsigned int frozen : 1;
......@@ -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 struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
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,
struct file *file, poll_table *wait);
extern int uvc_queue_allocated(struct uvc_video_queue *queue);
......@@ -606,10 +610,10 @@ extern int uvc_status_suspend(struct uvc_device *dev);
extern int uvc_status_resume(struct uvc_device *dev);
/* 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,
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,
const struct uvc_control_mapping *mapping);
......
......@@ -186,12 +186,12 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf,
size_t sz, loff_t *off)
{
struct video_device *vdev = video_devdata(filp);
int ret = -EIO;
int ret = -ENODEV;
if (!vdev->fops->read)
return -EINVAL;
if (vdev->lock)
mutex_lock(vdev->lock);
if (vdev->lock && mutex_lock_interruptible(vdev->lock))
return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->read(filp, buf, sz, off);
if (vdev->lock)
......@@ -203,12 +203,12 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
size_t sz, loff_t *off)
{
struct video_device *vdev = video_devdata(filp);
int ret = -EIO;
int ret = -ENODEV;
if (!vdev->fops->write)
return -EINVAL;
if (vdev->lock)
mutex_lock(vdev->lock);
if (vdev->lock && mutex_lock_interruptible(vdev->lock))
return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->write(filp, buf, sz, off);
if (vdev->lock)
......@@ -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)
{
struct video_device *vdev = video_devdata(filp);
int ret = DEFAULT_POLLMASK;
int ret = POLLERR | POLLHUP;
if (!vdev->fops->poll)
return ret;
return DEFAULT_POLLMASK;
if (vdev->lock)
mutex_lock(vdev->lock);
if (video_is_registered(vdev))
......@@ -238,20 +238,45 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
int ret = -ENODEV;
if (vdev->fops->unlocked_ioctl) {
if (vdev->lock)
mutex_lock(vdev->lock);
if (vdev->lock && mutex_lock_interruptible(vdev->lock))
return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
if (vdev->lock)
mutex_unlock(vdev->lock);
} 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);
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))
ret = vdev->fops->ioctl(filp, cmd, arg);
mutex_unlock(&v4l2_ioctl_mutex);
if (cmd != VIDIOC_DQBUF)
mutex_unlock(m);
} else
ret = -ENOTTY;
......@@ -265,8 +290,8 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
if (!vdev->fops->mmap)
return ret;
if (vdev->lock)
mutex_lock(vdev->lock);
if (vdev->lock && mutex_lock_interruptible(vdev->lock))
return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->mmap(filp, vm);
if (vdev->lock)
......@@ -284,7 +309,7 @@ static int v4l2_open(struct inode *inode, struct file *filp)
mutex_lock(&videodev_lock);
vdev = video_devdata(filp);
/* return ENODEV if the video device has already been removed. */
if (vdev == NULL) {
if (vdev == NULL || !video_is_registered(vdev)) {
mutex_unlock(&videodev_lock);
return -ENODEV;
}
......@@ -292,8 +317,10 @@ static int v4l2_open(struct inode *inode, struct file *filp)
video_get(vdev);
mutex_unlock(&videodev_lock);
if (vdev->fops->open) {
if (vdev->lock)
mutex_lock(vdev->lock);
if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
ret = -ERESTARTSYS;
goto err;
}
if (video_is_registered(vdev))
ret = vdev->fops->open(filp);
else
......@@ -302,6 +329,7 @@ static int v4l2_open(struct inode *inode, struct file *filp)
mutex_unlock(vdev->lock);
}
err:
/* decrease the refcount in case of an error */
if (ret)
video_put(vdev);
......@@ -596,7 +624,12 @@ void video_unregister_device(struct video_device *vdev)
if (!vdev || !video_is_registered(vdev))
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);
mutex_unlock(&videodev_lock);
device_unregister(&vdev->dev);
}
EXPORT_SYMBOL(video_unregister_device);
......
......@@ -35,6 +35,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
INIT_LIST_HEAD(&v4l2_dev->subdevs);
spin_lock_init(&v4l2_dev->lock);
mutex_init(&v4l2_dev->ioctl_lock);
v4l2_dev->dev = dev;
if (dev == NULL) {
/* 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,
static const struct v4l2_file_operations w9966_fops = {
.owner = THIS_MODULE,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
.read = w9966_v4l_read,
};
......
......@@ -51,6 +51,8 @@ struct v4l2_device {
unsigned int notification, void *arg);
/* The control handler. May be NULL. */
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.
......
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