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
This commit is contained in:
commit
8efc1a1a22
@ -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(>->vdev, gt);
|
||||
|
||||
if (video_register_device(>->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(>->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 @@ done:
|
||||
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 @@ done:
|
||||
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 @@ done:
|
||||
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 @@ done:
|
||||
* 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 @@ done:
|
||||
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 @@ out:
|
||||
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user