From 539a7555b31e65e66fb84c881d07d2bf18c974d0 Mon Sep 17 00:00:00 2001 From: "brandon@ifup.org" Date: Fri, 20 Jun 2008 22:58:53 -0300 Subject: [PATCH] V4L/DVB (8078): Introduce "index" attribute for persistent video4linux device nodes A number of V4L drivers have a mod param to specify their preferred minors. This is because it is often desirable for applications to have a static /dev name for a particular device. However, using minors has several disadvantages: 1) the requested minor may already be taken 2) using a mod param is driver specific 3) it requires every driver to add a param 4) requires configuration by hand This patch introduces an "index" attribute that when combined with udev rules can create static device paths like this: /dev/v4l/by-path/pci-0000\:00\:1d.2-usb-0\:1\:1.0-video0 /dev/v4l/by-path/pci-0000\:00\:1d.2-usb-0\:1\:1.0-video1 /dev/v4l/by-path/pci-0000\:00\:1d.2-usb-0\:1\:1.0-video2 $ ls -la /dev/v4l/by-path/pci-0000\:00\:1d.2-usb-0\:1\:1.0-video0 lrwxrwxrwx 1 root root 12 2008-04-28 00:02 /dev/v4l/by-path/pci-0000:00:1d.2-usb-0:1:1.0-video0 -> ../../video1 These paths are steady across reboots and should be resistant to rearranging across Kernel versions. video_register_device_index is available to drivers to request a specific index number. Signed-off-by: Brandon Philips Signed-off-by: Kees Cook Signed-off-by: Kay Sievers Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 98 +++++++++++++++++++++++++++++++++- include/media/v4l2-dev.h | 4 ++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 6cf6ad7193d9..9c539eb33811 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -372,6 +372,14 @@ EXPORT_SYMBOL(v4l_printk_ioctl); * sysfs stuff */ +static ssize_t show_index(struct device *cd, + struct device_attribute *attr, char *buf) +{ + struct video_device *vfd = container_of(cd, struct video_device, + class_dev); + return sprintf(buf, "%i\n", vfd->index); +} + static ssize_t show_name(struct device *cd, struct device_attribute *attr, char *buf) { @@ -410,6 +418,7 @@ static void video_release(struct device *cd) static struct device_attribute video_device_attrs[] = { __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR(index, S_IRUGO, show_index, NULL), __ATTR_NULL }; @@ -1900,8 +1909,82 @@ out: } EXPORT_SYMBOL(video_ioctl2); +struct index_info { + struct device *dev; + unsigned int used[VIDEO_NUM_DEVICES]; +}; + +static int __fill_index_info(struct device *cd, void *data) +{ + struct index_info *info = data; + struct video_device *vfd = container_of(cd, struct video_device, + class_dev); + + if (info->dev == vfd->dev) + info->used[vfd->index] = 1; + + return 0; +} + +/** + * assign_index - assign stream number based on parent device + * @vdev: video_device to assign index number to, vdev->dev should be assigned + * @num: -1 if auto assign, requested number otherwise + * + * + * returns -ENFILE if num is already in use, a free index number if + * successful. + */ +static int get_index(struct video_device *vdev, int num) +{ + struct index_info *info; + int i; + int ret = 0; + + if (num >= VIDEO_NUM_DEVICES) + return -EINVAL; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = vdev->dev; + + ret = class_for_each_device(&video_class, info, + __fill_index_info); + + if (ret < 0) + goto out; + + if (num >= 0) { + if (!info->used[num]) + ret = num; + else + ret = -ENFILE; + + goto out; + } + + for (i = 0; i < VIDEO_NUM_DEVICES; i++) { + if (info->used[i]) + continue; + ret = i; + goto out; + } + +out: + kfree(info); + return ret; +} + static const struct file_operations video_fops; +int video_register_device(struct video_device *vfd, int type, int nr) +{ + return video_register_device_index(vfd, type, nr, -1); +} +EXPORT_SYMBOL(video_register_device); + /** * video_register_device - register video4linux devices * @vfd: video device structure we want to register @@ -1927,7 +2010,8 @@ static const struct file_operations video_fops; * %VFL_TYPE_RADIO - A radio card */ -int video_register_device(struct video_device *vfd, int type, int nr) +int video_register_device_index(struct video_device *vfd, int type, int nr, + int index) { int i=0; int base; @@ -1984,6 +2068,16 @@ int video_register_device(struct video_device *vfd, int type, int nr) } video_device[i]=vfd; vfd->minor=i; + + ret = get_index(vfd, index); + if (ret < 0) { + printk(KERN_ERR "%s: get_index failed\n", + __func__); + goto fail_minor; + } + + vfd->index = ret; + mutex_unlock(&videodev_lock); mutex_init(&vfd->lock); @@ -2017,7 +2111,7 @@ fail_minor: mutex_unlock(&videodev_lock); return ret; } -EXPORT_SYMBOL(video_register_device); +EXPORT_SYMBOL(video_register_device_index); /** * video_unregister_device - unregister a video4linux device diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 40b0810a595a..9e6e4f18e948 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -96,6 +96,8 @@ struct video_device int type; /* v4l1 */ int type2; /* v4l2 */ int minor; + /* attribute to diferentiate multiple indexs on one physical device */ + int index; int debug; /* Activates debug level*/ @@ -347,6 +349,8 @@ void *priv; /* Version 2 functions */ extern int video_register_device(struct video_device *vfd, int type, int nr); +int video_register_device_index(struct video_device *vfd, int type, int nr, + int index); void video_unregister_device(struct video_device *); extern int video_ioctl2(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);