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 <bphilips@suse.de> Signed-off-by: Kees Cook <kees@outflux.net> Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
bbfc4c234e
commit
539a7555b3
|
@ -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)
|
||||||
|
|
||||||
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 @@ out:
|
||||||
}
|
}
|
||||||
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;
|
||||||
* %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)
|
||||||
}
|
}
|
||||||
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 @@ fail_minor:
|
||||||
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
|
||||||
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;
|
||||||
|
|
||||||
/* 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);
|
||||||
|
|
Loading…
Reference in New Issue