diff options
author | brandon@ifup.org <brandon@ifup.org> | 2008-06-20 21:58:53 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-20 06:10:27 -0400 |
commit | 539a7555b31e65e66fb84c881d07d2bf18c974d0 (patch) | |
tree | 6986fc5c76388c2b07b15911eca0b52100d68f15 | |
parent | bbfc4c234e240b67ccd9cdca72d76267bad0dc96 (diff) |
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>
-rw-r--r-- | drivers/media/video/videodev.c | 98 | ||||
-rw-r--r-- | 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); | |||
372 | * sysfs stuff | 372 | * sysfs stuff |
373 | */ | 373 | */ |
374 | 374 | ||
375 | static ssize_t show_index(struct device *cd, | ||
376 | struct device_attribute *attr, char *buf) | ||
377 | { | ||
378 | struct video_device *vfd = container_of(cd, struct video_device, | ||
379 | class_dev); | ||
380 | return sprintf(buf, "%i\n", vfd->index); | ||
381 | } | ||
382 | |||
375 | static ssize_t show_name(struct device *cd, | 383 | static ssize_t show_name(struct device *cd, |
376 | struct device_attribute *attr, char *buf) | 384 | struct device_attribute *attr, char *buf) |
377 | { | 385 | { |
@@ -410,6 +418,7 @@ static void video_release(struct device *cd) | |||
410 | 418 | ||
411 | static struct device_attribute video_device_attrs[] = { | 419 | static struct device_attribute video_device_attrs[] = { |
412 | __ATTR(name, S_IRUGO, show_name, NULL), | 420 | __ATTR(name, S_IRUGO, show_name, NULL), |
421 | __ATTR(index, S_IRUGO, show_index, NULL), | ||
413 | __ATTR_NULL | 422 | __ATTR_NULL |
414 | }; | 423 | }; |
415 | 424 | ||
@@ -1900,8 +1909,82 @@ out: | |||
1900 | } | 1909 | } |
1901 | EXPORT_SYMBOL(video_ioctl2); | 1910 | EXPORT_SYMBOL(video_ioctl2); |
1902 | 1911 | ||
1912 | struct index_info { | ||
1913 | struct device *dev; | ||
1914 | unsigned int used[VIDEO_NUM_DEVICES]; | ||
1915 | }; | ||
1916 | |||
1917 | static int __fill_index_info(struct device *cd, void *data) | ||
1918 | { | ||
1919 | struct index_info *info = data; | ||
1920 | struct video_device *vfd = container_of(cd, struct video_device, | ||
1921 | class_dev); | ||
1922 | |||
1923 | if (info->dev == vfd->dev) | ||
1924 | info->used[vfd->index] = 1; | ||
1925 | |||
1926 | return 0; | ||
1927 | } | ||
1928 | |||
1929 | /** | ||
1930 | * assign_index - assign stream number based on parent device | ||
1931 | * @vdev: video_device to assign index number to, vdev->dev should be assigned | ||
1932 | * @num: -1 if auto assign, requested number otherwise | ||
1933 | * | ||
1934 | * | ||
1935 | * returns -ENFILE if num is already in use, a free index number if | ||
1936 | * successful. | ||
1937 | */ | ||
1938 | static int get_index(struct video_device *vdev, int num) | ||
1939 | { | ||
1940 | struct index_info *info; | ||
1941 | int i; | ||
1942 | int ret = 0; | ||
1943 | |||
1944 | if (num >= VIDEO_NUM_DEVICES) | ||
1945 | return -EINVAL; | ||
1946 | |||
1947 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
1948 | if (!info) | ||
1949 | return -ENOMEM; | ||
1950 | |||
1951 | info->dev = vdev->dev; | ||
1952 | |||
1953 | ret = class_for_each_device(&video_class, info, | ||
1954 | __fill_index_info); | ||
1955 | |||
1956 | if (ret < 0) | ||
1957 | goto out; | ||
1958 | |||
1959 | if (num >= 0) { | ||
1960 | if (!info->used[num]) | ||
1961 | ret = num; | ||
1962 | else | ||
1963 | ret = -ENFILE; | ||
1964 | |||
1965 | goto out; | ||
1966 | } | ||
1967 | |||
1968 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) { | ||
1969 | if (info->used[i]) | ||
1970 | continue; | ||
1971 | ret = i; | ||
1972 | goto out; | ||
1973 | } | ||
1974 | |||
1975 | out: | ||
1976 | kfree(info); | ||
1977 | return ret; | ||
1978 | } | ||
1979 | |||
1903 | static const struct file_operations video_fops; | 1980 | static const struct file_operations video_fops; |
1904 | 1981 | ||
1982 | int video_register_device(struct video_device *vfd, int type, int nr) | ||
1983 | { | ||
1984 | return video_register_device_index(vfd, type, nr, -1); | ||
1985 | } | ||
1986 | EXPORT_SYMBOL(video_register_device); | ||
1987 | |||
1905 | /** | 1988 | /** |
1906 | * video_register_device - register video4linux devices | 1989 | * video_register_device - register video4linux devices |
1907 | * @vfd: video device structure we want to register | 1990 | * @vfd: video device structure we want to register |
@@ -1927,7 +2010,8 @@ static const struct file_operations video_fops; | |||
1927 | * %VFL_TYPE_RADIO - A radio card | 2010 | * %VFL_TYPE_RADIO - A radio card |
1928 | */ | 2011 | */ |
1929 | 2012 | ||
1930 | int video_register_device(struct video_device *vfd, int type, int nr) | 2013 | int video_register_device_index(struct video_device *vfd, int type, int nr, |
2014 | int index) | ||
1931 | { | 2015 | { |
1932 | int i=0; | 2016 | int i=0; |
1933 | int base; | 2017 | int base; |
@@ -1984,6 +2068,16 @@ int video_register_device(struct video_device *vfd, int type, int nr) | |||
1984 | } | 2068 | } |
1985 | video_device[i]=vfd; | 2069 | video_device[i]=vfd; |
1986 | vfd->minor=i; | 2070 | vfd->minor=i; |
2071 | |||
2072 | ret = get_index(vfd, index); | ||
2073 | if (ret < 0) { | ||
2074 | printk(KERN_ERR "%s: get_index failed\n", | ||
2075 | __func__); | ||
2076 | goto fail_minor; | ||
2077 | } | ||
2078 | |||
2079 | vfd->index = ret; | ||
2080 | |||
1987 | mutex_unlock(&videodev_lock); | 2081 | mutex_unlock(&videodev_lock); |
1988 | mutex_init(&vfd->lock); | 2082 | mutex_init(&vfd->lock); |
1989 | 2083 | ||
@@ -2017,7 +2111,7 @@ fail_minor: | |||
2017 | mutex_unlock(&videodev_lock); | 2111 | mutex_unlock(&videodev_lock); |
2018 | return ret; | 2112 | return ret; |
2019 | } | 2113 | } |
2020 | EXPORT_SYMBOL(video_register_device); | 2114 | EXPORT_SYMBOL(video_register_device_index); |
2021 | 2115 | ||
2022 | /** | 2116 | /** |
2023 | * video_unregister_device - unregister a video4linux device | 2117 | * 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 | |||
96 | int type; /* v4l1 */ | 96 | int type; /* v4l1 */ |
97 | int type2; /* v4l2 */ | 97 | int type2; /* v4l2 */ |
98 | int minor; | 98 | int minor; |
99 | /* attribute to diferentiate multiple indexs on one physical device */ | ||
100 | int index; | ||
99 | 101 | ||
100 | int debug; /* Activates debug level*/ | 102 | int debug; /* Activates debug level*/ |
101 | 103 | ||
@@ -347,6 +349,8 @@ void *priv; | |||
347 | 349 | ||
348 | /* Version 2 functions */ | 350 | /* Version 2 functions */ |
349 | extern int video_register_device(struct video_device *vfd, int type, int nr); | 351 | extern int video_register_device(struct video_device *vfd, int type, int nr); |
352 | int video_register_device_index(struct video_device *vfd, int type, int nr, | ||
353 | int index); | ||
350 | void video_unregister_device(struct video_device *); | 354 | void video_unregister_device(struct video_device *); |
351 | extern int video_ioctl2(struct inode *inode, struct file *file, | 355 | extern int video_ioctl2(struct inode *inode, struct file *file, |
352 | unsigned int cmd, unsigned long arg); | 356 | unsigned int cmd, unsigned long arg); |