Commit 539a7555 authored by brandon@ifup.org's avatar brandon@ifup.org Committed by Mauro Carvalho Chehab

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: default avatarBrandon Philips <bphilips@suse.de>
Signed-off-by: default avatarKees Cook <kees@outflux.net>
Signed-off-by: default avatarKay Sievers <kay.sievers@vrfy.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent bbfc4c23
...@@ -372,6 +372,14 @@ EXPORT_SYMBOL(v4l_printk_ioctl); ...@@ -372,6 +372,14 @@ EXPORT_SYMBOL(v4l_printk_ioctl);
* sysfs stuff * 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, static ssize_t show_name(struct device *cd,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
...@@ -410,6 +418,7 @@ static void video_release(struct device *cd) ...@@ -410,6 +418,7 @@ static void video_release(struct device *cd)
static struct device_attribute video_device_attrs[] = { static struct device_attribute video_device_attrs[] = {
__ATTR(name, S_IRUGO, show_name, NULL), __ATTR(name, S_IRUGO, show_name, NULL),
__ATTR(index, S_IRUGO, show_index, NULL),
__ATTR_NULL __ATTR_NULL
}; };
...@@ -1900,8 +1909,82 @@ int video_ioctl2 (struct inode *inode, struct file *file, ...@@ -1900,8 +1909,82 @@ int video_ioctl2 (struct inode *inode, struct file *file,
} }
EXPORT_SYMBOL(video_ioctl2); 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; 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 * video_register_device - register video4linux devices
* @vfd: video device structure we want to register * @vfd: video device structure we want to register
...@@ -1927,7 +2010,8 @@ static const struct file_operations video_fops; ...@@ -1927,7 +2010,8 @@ static const struct file_operations video_fops;
* %VFL_TYPE_RADIO - A radio card * %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 i=0;
int base; int base;
...@@ -1984,6 +2068,16 @@ int video_register_device(struct video_device *vfd, int type, int nr) ...@@ -1984,6 +2068,16 @@ int video_register_device(struct video_device *vfd, int type, int nr)
} }
video_device[i]=vfd; video_device[i]=vfd;
vfd->minor=i; 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_unlock(&videodev_lock);
mutex_init(&vfd->lock); mutex_init(&vfd->lock);
...@@ -2017,7 +2111,7 @@ int video_register_device(struct video_device *vfd, int type, int nr) ...@@ -2017,7 +2111,7 @@ int video_register_device(struct video_device *vfd, int type, int nr)
mutex_unlock(&videodev_lock); mutex_unlock(&videodev_lock);
return ret; return ret;
} }
EXPORT_SYMBOL(video_register_device); EXPORT_SYMBOL(video_register_device_index);
/** /**
* video_unregister_device - unregister a video4linux device * video_unregister_device - unregister a video4linux device
......
...@@ -96,6 +96,8 @@ struct video_device ...@@ -96,6 +96,8 @@ struct video_device
int type; /* v4l1 */ int type; /* v4l1 */
int type2; /* v4l2 */ int type2; /* v4l2 */
int minor; int minor;
/* attribute to diferentiate multiple indexs on one physical device */
int index;
int debug; /* Activates debug level*/ int debug; /* Activates debug level*/
...@@ -347,6 +349,8 @@ void *priv; ...@@ -347,6 +349,8 @@ void *priv;
/* Version 2 functions */ /* Version 2 functions */
extern int video_register_device(struct video_device *vfd, int type, int nr); 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 *); void video_unregister_device(struct video_device *);
extern int video_ioctl2(struct inode *inode, struct file *file, extern int video_ioctl2(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg); unsigned int cmd, unsigned long arg);
......
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