diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-09-05 10:20:56 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-09-05 10:20:56 -0300 |
commit | 5f2d82cefe0ce930f3146875c88b993695c7e03a (patch) | |
tree | 2d33fe6b5949e509d85f48f5c8331adcb22151d3 /linux/drivers/media/video/v4l2-dev.c | |
parent | ad789ba2904603896206a72f0445e8ba56da7134 (diff) | |
parent | 2257e70baa578d959dc4bdcce498ef07d2af00da (diff) | |
download | mediapointer-dvb-s2-5f2d82cefe0ce930f3146875c88b993695c7e03a.tar.gz mediapointer-dvb-s2-5f2d82cefe0ce930f3146875c88b993695c7e03a.tar.bz2 |
merge: http://linuxtv.org/hg/~awalls/v4l-dvb
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Fixed a trivial conflict between a janitor's patch from Hans Verkuil and
Andy patch series.
Priority: normal
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'linux/drivers/media/video/v4l2-dev.c')
-rw-r--r-- | linux/drivers/media/video/v4l2-dev.c | 235 |
1 files changed, 99 insertions, 136 deletions
diff --git a/linux/drivers/media/video/v4l2-dev.c b/linux/drivers/media/video/v4l2-dev.c index 594f2477f..a2daea31c 100644 --- a/linux/drivers/media/video/v4l2-dev.c +++ b/linux/drivers/media/video/v4l2-dev.c @@ -44,6 +44,7 @@ static ssize_t show_index(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, dev); + return sprintf(buf, "%i\n", vfd->index); } @@ -51,6 +52,7 @@ static ssize_t show_name(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, dev); + return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); } @@ -63,12 +65,14 @@ static struct device_attribute video_device_attrs[] = { static ssize_t show_index(struct class_device *cd, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, dev); + return sprintf(buf, "%i\n", vfd->index); } static ssize_t show_name(struct class_device *cd, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, dev); + return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); } @@ -76,12 +80,15 @@ static CLASS_DEVICE_ATTR(index, S_IRUGO, show_index, NULL); static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL); #endif +/* + * Active devices + */ +static struct video_device *video_device[VIDEO_NUM_DEVICES]; +static DEFINE_MUTEX(videodev_lock); + struct video_device *video_device_alloc(void) { - struct video_device *vfd; - - vfd = kzalloc(sizeof(*vfd), GFP_KERNEL); - return vfd; + return kzalloc(sizeof(struct video_device), GFP_KERNEL); } EXPORT_SYMBOL(video_device_alloc); @@ -91,6 +98,42 @@ void video_device_release(struct video_device *vfd) } EXPORT_SYMBOL(video_device_release); +void video_device_release_empty(struct video_device *vfd) +{ + /* Do nothing */ + /* Only valid when the video_device struct is a static. */ +} +EXPORT_SYMBOL(video_device_release_empty); + +/* Called when the last user of the character device is gone. */ +static void v4l2_chardev_release(struct kobject *kobj) +{ + struct video_device *vfd = container_of(kobj, struct video_device, cdev.kobj); + + mutex_lock(&videodev_lock); + if (video_device[vfd->minor] != vfd) { + mutex_unlock(&videodev_lock); + BUG(); + return; + } + + /* Free up this device for reuse */ + video_device[vfd->minor] = NULL; + mutex_unlock(&videodev_lock); + + /* Release the character device */ + vfd->cdev_release(kobj); + /* Release video_device and perform other + cleanups as needed. */ + if (vfd->release) + vfd->release(vfd); +} + +/* The new kobj_type for the character device */ +static struct kobj_type v4l2_ktype_cdev_default = { + .release = v4l2_chardev_release, +}; + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) static void video_release(struct class_device *cd) #else @@ -99,12 +142,11 @@ static void video_release(struct device *cd) { struct video_device *vfd = container_of(cd, struct video_device, dev); -#if 1 /* keep */ - /* needed until all drivers are fixed */ - if (!vfd->release) - return; -#endif - vfd->release(vfd); + /* It's now safe to delete the char device. + This will either trigger the v4l2_chardev_release immediately (if + the refcount goes to 0) or later when the last user of the + character device closes it. */ + cdev_del(&vfd->cdev); } static struct class video_class = { @@ -117,13 +159,6 @@ static struct class video_class = { #endif }; -/* - * Active devices - */ - -static struct video_device *video_device[VIDEO_NUM_DEVICES]; -static DEFINE_MUTEX(videodev_lock); - struct video_device *video_devdata(struct file *file) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) @@ -134,79 +169,6 @@ struct video_device *video_devdata(struct file *file) } EXPORT_SYMBOL(video_devdata); -/* - * Open a video device - FIXME: Obsoleted - */ -static int video_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - int err = 0; - struct video_device *vfl; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) - const struct file_operations *old_fops; -#else - struct file_operations *old_fops; -#endif - - if (minor >= VIDEO_NUM_DEVICES) - return -ENODEV; - mutex_lock(&videodev_lock); - vfl = video_device[minor]; - if (vfl == NULL) { - mutex_unlock(&videodev_lock); - request_module("char-major-%d-%d", VIDEO_MAJOR, minor); - mutex_lock(&videodev_lock); - vfl = video_device[minor]; - if (vfl == NULL) { - mutex_unlock(&videodev_lock); - return -ENODEV; - } - } - old_fops = file->f_op; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) - file->f_op = fops_get(vfl->fops); -#else - file->f_op = (struct file_operations *)fops_get(vfl->fops); -#endif - if (file->f_op->open) - err = file->f_op->open(inode, file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } - fops_put(old_fops); - mutex_unlock(&videodev_lock); - return err; -} - -/* - * open/release helper functions -- handle exclusive opens - * Should be removed soon - */ -int video_exclusive_open(struct inode *inode, struct file *file) -{ - struct video_device *vfl = video_devdata(file); - int retval = 0; - - mutex_lock(&vfl->lock); - if (vfl->users) - retval = -EBUSY; - else - vfl->users++; - mutex_unlock(&vfl->lock); - return retval; -} -EXPORT_SYMBOL(video_exclusive_open); - -int video_exclusive_release(struct inode *inode, struct file *file) -{ - struct video_device *vfl = video_devdata(file); - - vfl->users--; - return 0; -} -EXPORT_SYMBOL(video_exclusive_release); - /** * get_index - assign stream number based on parent device * @vdev: video_device to assign index number to, vdev->dev should be assigned @@ -291,6 +253,13 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, int end; int ret; char *name_base; + void *priv = video_get_drvdata(vfd); + + /* the release callback MUST be present */ + BUG_ON(!vfd->release); + + if (vfd == NULL) + return -EINVAL; switch (type) { case VFL_TYPE_GRABBER: @@ -319,9 +288,16 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, return -EINVAL; } + /* Initialize the character device */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) + cdev_init(&vfd->cdev, vfd->fops); +#else + cdev_init(&vfd->cdev, (struct file_operations *)vfd->fops); +#endif + vfd->cdev.owner = vfd->fops->owner; /* pick a minor number */ mutex_lock(&videodev_lock); - if (nr >= 0 && nr < end-base) { + if (nr >= 0 && nr < end-base) { /* use the one the driver asked for */ i = base + nr; if (NULL != video_device[i]) { @@ -352,10 +328,16 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, goto fail_minor; } - mutex_init(&vfd->lock); - + ret = cdev_add(&vfd->cdev, MKDEV(VIDEO_MAJOR, vfd->minor), 1); + if (ret < 0) { + printk(KERN_ERR "%s: cdev_add failed\n", __func__); + goto fail_minor; + } /* sysfs class */ - memset(&vfd->dev, 0x00, sizeof(vfd->dev)); + memset(&vfd->dev, 0, sizeof(vfd->dev)); + /* The memset above cleared the device's drvdata, so + put back the copy we made earlier. */ + video_set_drvdata(vfd, priv); vfd->dev.class = &video_class; vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) @@ -371,41 +353,38 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, #endif if (ret < 0) { printk(KERN_ERR "%s: device_register failed\n", __func__); - goto fail_minor; + goto del_cdev; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) - ret = class_device_create_file(&vfd->dev, - &class_device_attr_name); + ret = class_device_create_file(&vfd->dev, &class_device_attr_name); if (ret < 0) { printk(KERN_ERR "%s: class_device_create_file 'name' failed\n", __func__); class_device_unregister(&vfd->dev); - goto fail_minor; + goto del_cdev; } - ret = class_device_create_file(&vfd->dev, - &class_device_attr_index); + ret = class_device_create_file(&vfd->dev, &class_device_attr_index); if (ret < 0) { printk(KERN_ERR "%s: class_device_create_file 'index' failed\n", __func__); class_device_unregister(&vfd->dev); - goto fail_minor; + goto del_cdev; } #endif - -#if 1 /* keep */ - /* needed until all drivers are fixed */ - if (!vfd->release) - printk(KERN_WARNING "videodev: \"%s\" has no release callback. " - "Please fix your driver for proper sysfs support, see " - "http://lwn.net/Articles/36850/\n", vfd->name); -#endif + /* Remember the cdev's release function */ + vfd->cdev_release = vfd->cdev.kobj.ktype->release; + /* Install our own */ + vfd->cdev.kobj.ktype = &v4l2_ktype_cdev_default; return 0; +del_cdev: + cdev_del(&vfd->cdev); + fail_minor: mutex_lock(&videodev_lock); video_device[vfd->minor] = NULL; - vfd->minor = -1; mutex_unlock(&videodev_lock); + vfd->minor = -1; return ret; } EXPORT_SYMBOL(video_register_device_index); @@ -420,51 +399,33 @@ EXPORT_SYMBOL(video_register_device_index); void video_unregister_device(struct video_device *vfd) { - mutex_lock(&videodev_lock); - if (video_device[vfd->minor] != vfd) - panic("videodev: bad unregister"); - - video_device[vfd->minor] = NULL; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) class_device_unregister(&vfd->dev); #else device_unregister(&vfd->dev); #endif - mutex_unlock(&videodev_lock); } EXPORT_SYMBOL(video_unregister_device); /* - * Video fs operations - */ -static const struct file_operations video_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .open = video_open, -}; - -/* * Initialise video for linux */ - static int __init videodev_init(void) { + dev_t dev = MKDEV(VIDEO_MAJOR, 0); int ret; printk(KERN_INFO "Linux video capture interface: v2.00\n"); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) - if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) { -#else - if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, - (struct file_operations *)&video_fops)) { -#endif - printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR); - return -EIO; + ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME); + if (ret < 0) { + printk(KERN_WARNING "videodev: unable to get major %d\n", + VIDEO_MAJOR); + return ret; } ret = class_register(&video_class); if (ret < 0) { - unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); + unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); printk(KERN_WARNING "video_dev: class_register failed\n"); return -EIO; } @@ -474,8 +435,10 @@ static int __init videodev_init(void) static void __exit videodev_exit(void) { + dev_t dev = MKDEV(VIDEO_MAJOR, 0); + class_unregister(&video_class); - unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); + unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); } module_init(videodev_init) |