Skip to contentSkip to conversation

V4L: add "function" sysfs attribute to v4l devices

PATCH In review Kees Cook 3 participants 10 messages Apr 17, 2008 – May 14, 2008 Media (V4L/DVB)

lore
Share & tools
lore

Kees Cook

author
#0 lore raw

PATCH 1/2 V4L: add "function" sysfs attribute to v4l devices

From: Kay Sievers <[email protected]>

This adds a "function" string to help userspace to identify the type of device if multiple streams are available for a single v4l device.

This is meant to be used with udev, to create persistent device links for v4l devices, which will not depend on module-loading/device-enumeration order.

---
 drivers/media/video/v4l2-common.c |   39 ++++++++++++++++++++++++++++++++++++++
 drivers/media/video/videodev.c    |   13 ++++++++++++
 include/linux/videodev2.h         |   16 +++++++++++++++
 include/media/v4l2-common.h       |    3 ++
 include/media/v4l2-dev.h          |    1 
 5 files changed, 72 insertions(+)

---

linux/drivers/media/video/v4l2-common.c +39 -0
diff -r 6aa6656852cb linux/drivers/media/video/v4l2-common.c
@@ -81,6 +81,45 @@ MODULE_LICENSE("GPL");
  *  Video Standard Operations (contributed by Michael Schimek)
  */
 
+/*
+ * Exports "function" string to userspace to identify the type of device
+ * if multiple streams are available for a single device.
+ *
+ * Types/string names should be reused if possible, instead of adding
+ * new very device specific types, they must _uniquely_ identify all
+ * streams belonging to the _same_ device though.
+ *
+ * No single device must export multiple streams with the same function
+ * string, because userspace uses this to find the correct device node.
+ *
+ * Unlike the free-text "name", it must be an easily machine useable
+ * string containing only [a-z0-9._-] characters.
+ *
+ * Strings must not change without a valid reason, they are part of the
+ * sysfs ABI.
+ *
+ */
+static const char *v4l2_function_type_names[] = {
+	[V4L2_FN_VIDEO_CAP]		= "vid-cap",
+	[V4L2_FN_VIDEO_OUT]		= "vid-out",
+	[V4L2_FN_MPEG_CAP]		= "mpeg-cap",
+	[V4L2_FN_MPEG_OUT]		= "mpeg-out",
+	[V4L2_FN_YUV_CAP]		= "yuv-cap",
+	[V4L2_FN_YUV_OUT]		= "yuv-out",
+	[V4L2_FN_VBI_CAP]		= "vbi-cap",
+	[V4L2_FN_VBI_OUT]		= "vbi-out",
+	[V4L2_FN_PCM_CAP]		= "pcm-cap",
+	[V4L2_FN_PCM_OUT]		= "pcm-out",
+	[V4L2_FN_RADIO_CAP]		= "radio-cap",
+};
+
+const char *v4l2_function_name(enum v4l2_function_type function)
+{
+	if (function > 0 && function < ARRAY_SIZE(v4l2_function_type_names))
+		return v4l2_function_type_names[function];
+	return NULL;
+}
+EXPORT_SYMBOL(v4l2_function_name);
 
 /* ----------------------------------------------------------------- */
 /* priority handling                                                 */
linux/drivers/media/video/videodev.c +13 -0
diff -r 6aa6656852cb linux/drivers/media/video/videodev.c
@@ -451,6 +451,18 @@ static DEVICE_ATTR(dev, S_IRUGO, show_de
 static DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
 #endif
 
+static ssize_t show_function(struct device *cd,
+			     struct device_attribute *attr, char *buf)
+{
+	struct video_device *vfd = container_of(cd, struct video_device,
+						class_dev);
+	const char *function_name = v4l2_function_name(vfd->function);
+
+	if (!function_name)
+		return -ENOSYS;
+	return sprintf(buf, "%s\n", v4l2_function_name(vfd->function));
+}
+
 struct video_device *video_device_alloc(void)
 {
 	struct video_device *vfd;
@@ -486,6 +498,7 @@ static void video_release(struct device 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
 static struct device_attribute video_device_attrs[] = {
 	__ATTR(name, S_IRUGO, show_name, NULL),
+	__ATTR(function, S_IRUGO, show_function, NULL),
 	__ATTR_NULL
 };
 #endif
linux/include/linux/videodev2.h +16 -0
diff -r 6aa6656852cb linux/include/linux/videodev2.h
@@ -138,6 +138,22 @@ enum v4l2_field {
 	 (field) == V4L2_FIELD_INTERLACED_BT ||\
 	 (field) == V4L2_FIELD_SEQ_TB ||\
 	 (field) == V4L2_FIELD_SEQ_BT)
+
+/* Exports "function" string to userspace to identify type of device */
+enum v4l2_function_type {
+	V4L2_FN_UNDEFINED,
+	V4L2_FN_VIDEO_CAP,
+	V4L2_FN_VIDEO_OUT,
+	V4L2_FN_MPEG_CAP,
+	V4L2_FN_MPEG_OUT,
+	V4L2_FN_YUV_CAP,
+	V4L2_FN_YUV_OUT,
+	V4L2_FN_VBI_CAP,
+	V4L2_FN_VBI_OUT,
+	V4L2_FN_PCM_CAP,
+	V4L2_FN_PCM_OUT,
+	V4L2_FN_RADIO_CAP,
+};
 
 enum v4l2_buf_type {
 	V4L2_BUF_TYPE_VIDEO_CAPTURE        = 1,
linux/include/media/v4l2-common.h +3 -0
diff -r 6aa6656852cb linux/include/media/v4l2-common.h
@@ -67,6 +67,9 @@
 			v4l_client_printk(KERN_DEBUG, client, fmt , ## arg); \
 	} while (0)
 
+
+/* map function enum to string */
+extern const char *v4l2_function_name(enum v4l2_function_type function);
 
 /* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */
 #define v4l_print_ioctl(name, cmd)  		 \
linux/include/media/v4l2-dev.h +1 -0
diff -r 6aa6656852cb linux/include/media/v4l2-dev.h
@@ -112,6 +112,7 @@ struct video_device
 	char name[32];
 	int type;       /* v4l1 */
 	int type2;      /* v4l2 */
+	enum v4l2_function_type function; /* sysfs string */
 	int minor;
 
 	int debug;	/* Activates debug level*/
Signature · 6 lines
Kees Cook                                            @outflux.net

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
#1 lore raw

Hi Kees,

Quoted 42 lines · Kees Cook

From: Kay Sievers <[email protected]>

This adds a "function" string to help userspace to identify the type of device if multiple streams are available for a single v4l device.

This is meant to be used with udev, to create persistent device links for v4l devices, which will not depend on module-loading/device-enumeration order.

---
 drivers/media/video/v4l2-common.c |   39
++++++++++++++++++++++++++++++++++++++ drivers/media/video/videodev.c    | 
 13 ++++++++++++
 include/linux/videodev2.h         |   16 +++++++++++++++
 include/media/v4l2-common.h       |    3 ++
 include/media/v4l2-dev.h          |    1
 5 files changed, 72 insertions(+)

---
diff -r 6aa6656852cb linux/drivers/media/video/v4l2-common.c
--- a/linux/drivers/media/video/v4l2-common.c Wed Apr 16 13:13:15 2008
-0300 +++ b/linux/drivers/media/video/v4l2-common.c Wed Apr 16 17:52:29
2008 -0700 @@ -81,6 +81,45 @@ MODULE_LICENSE("GPL");
* Video Standard Operations (contributed by Michael Schimek) */

linux/drivers/media/video/v4l2-common.c +15 -0
+/*
+ * Exports "function" string to userspace to identify the type of device
+ * if multiple streams are available for a single device.
+ *
+ * Types/string names should be reused if possible, instead of adding
+ * new very device specific types, they must _uniquely_ identify all
+ * streams belonging to the _same_ device though.
+ *
+ * No single device must export multiple streams with the same function
+ * string, because userspace uses this to find the correct device node.
+ *
+ * Unlike the free-text "name", it must be an easily machine useable
+ * string containing only [a-z0-9._-] characters.
+ *
+ * Strings must not change without a valid reason, they are part of the

linux/drivers/media/video/v4l2-common.c MODULE_LICENSE("GPL"); · line 108

Quoted 10 lines
linux/drivers/media/video/v4l2-common.c +10 -0
+ * sysfs ABI.
+ *
+ */
+static const char *v4l2_function_type_names[] = {
+	[V4L2_FN_VIDEO_CAP]		= "vid-cap",
+	[V4L2_FN_VIDEO_OUT]		= "vid-out",
+	[V4L2_FN_MPEG_CAP]		= "mpeg-cap",
+	[V4L2_FN_MPEG_OUT]		= "mpeg-out",
+	[V4L2_FN_YUV_CAP]		= "yuv-cap",
+	[V4L2_FN_YUV_OUT]		= "yuv-out",

I don't like those. Video capture devices can encode pixels in a variety of formats. MPEG and YUV are only two special cases. You will find devices encoding in RGB, Bayer, MJPEG, ... as well as some proprietary formats.

If I understand your problem correctly, you want to differentiate between multiple v4l devices created by a single driver for a single hardware device. Using the above functions might work for ivtv but rules out devices that output multiple streams in the same format.

Wouldn't it be better to fix the ivtv driver to use a single device node for both compressed and uncompressed streams ?

Quoted 90 lines
linux/drivers/media/video/v4l2-common.c +14 -0
+	[V4L2_FN_VBI_CAP]		= "vbi-cap",
+	[V4L2_FN_VBI_OUT]		= "vbi-out",
+	[V4L2_FN_PCM_CAP]		= "pcm-cap",
+	[V4L2_FN_PCM_OUT]		= "pcm-out",
+	[V4L2_FN_RADIO_CAP]		= "radio-cap",
+};
+
+const char *v4l2_function_name(enum v4l2_function_type function)
+{
+	if (function > 0 && function < ARRAY_SIZE(v4l2_function_type_names))
+		return v4l2_function_type_names[function];
+	return NULL;
+}
+EXPORT_SYMBOL(v4l2_function_name);
 
 /* ----------------------------------------------------------------- */
 /* priority handling                                                 */

diff -r 6aa6656852cb linux/drivers/media/video/videodev.c

linux/drivers/media/video/videodev.c +13 -0
@@ -451,6 +451,18 @@ static DEVICE_ATTR(dev, S_IRUGO, show_de
 static DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
 #endif
 
+static ssize_t show_function(struct device *cd,
+			     struct device_attribute *attr, char *buf)
+{
+	struct video_device *vfd = container_of(cd, struct video_device,
+						class_dev);
+	const char *function_name = v4l2_function_name(vfd->function);
+
+	if (!function_name)
+		return -ENOSYS;
+	return sprintf(buf, "%s\n", v4l2_function_name(vfd->function));
+}
+
 struct video_device *video_device_alloc(void)
 {
 	struct video_device *vfd;
@@ -486,6 +498,7 @@ static void video_release(struct device
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
 static struct device_attribute video_device_attrs[] = {
 	__ATTR(name, S_IRUGO, show_name, NULL),
+	__ATTR(function, S_IRUGO, show_function, NULL),
 	__ATTR_NULL
 };
 #endif

diff -r 6aa6656852cb linux/include/linux/videodev2.h

linux/include/linux/videodev2.h +16 -0
@@ -138,6 +138,22 @@ enum v4l2_field {
 	 (field) == V4L2_FIELD_INTERLACED_BT ||\
 	 (field) == V4L2_FIELD_SEQ_TB ||\
 	 (field) == V4L2_FIELD_SEQ_BT)
+
+/* Exports "function" string to userspace to identify type of device */
+enum v4l2_function_type {
+	V4L2_FN_UNDEFINED,
+	V4L2_FN_VIDEO_CAP,
+	V4L2_FN_VIDEO_OUT,
+	V4L2_FN_MPEG_CAP,
+	V4L2_FN_MPEG_OUT,
+	V4L2_FN_YUV_CAP,
+	V4L2_FN_YUV_OUT,
+	V4L2_FN_VBI_CAP,
+	V4L2_FN_VBI_OUT,
+	V4L2_FN_PCM_CAP,
+	V4L2_FN_PCM_OUT,
+	V4L2_FN_RADIO_CAP,
+};
 
 enum v4l2_buf_type {
 	V4L2_BUF_TYPE_VIDEO_CAPTURE        = 1,

diff -r 6aa6656852cb linux/include/media/v4l2-common.h

linux/include/media/v4l2-common.h +3 -0
@@ -67,6 +67,9 @@
 			v4l_client_printk(KERN_DEBUG, client, fmt , ## arg); \
 	} while (0)
 
+
+/* map function enum to string */
+extern const char *v4l2_function_name(enum v4l2_function_type function);
 
 /* Use this macro for non-I2C drivers. Pass the driver name as the first
 arg. */ #define v4l_print_ioctl(name, cmd)  		 \

diff -r 6aa6656852cb linux/include/media/v4l2-dev.h

linux/include/media/v4l2-dev.h struct video_device · line 118

Quoted 7 lines
linux/include/media/v4l2-dev.h +1 -0
@@ -112,6 +112,7 @@ struct video_device
 	char name[32];
 	int type;       /* v4l1 */
 	int type2;      /* v4l2 */
+	enum v4l2_function_type function; /* sysfs string */
 	int minor;
 
 	int debug;	/* Activates debug level*/

Best regards,

Laurent Pinchart

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

author
#2 lore raw

Hi Laurent,

Quoted 12 lines · Laurent Pinchart

linux/drivers/media/video/v4l2-common.c MODULE_LICENSE("GPL"); · line 108

Quoted 7 lines · Kees Cook
linux/drivers/media/video/v4l2-common.c +7 -0
+static const char *v4l2_function_type_names[] = {
+	[V4L2_FN_VIDEO_CAP]		= "vid-cap",
+	[V4L2_FN_VIDEO_OUT]		= "vid-out",
+	[V4L2_FN_MPEG_CAP]		= "mpeg-cap",
+	[V4L2_FN_MPEG_OUT]		= "mpeg-out",
+	[V4L2_FN_YUV_CAP]		= "yuv-cap",
+	[V4L2_FN_YUV_OUT]		= "yuv-out",

I don't like those. Video capture devices can encode pixels in a variety of formats. MPEG and YUV are only two special cases. You will find devices encoding in RGB, Bayer, MJPEG, ... as well as some proprietary formats.

If these devices have a variable encoding method, perhaps just use "vid-cap" as the general rule. (In the case that the output formats are selectable from a given device node at runtime.)

Quoted 7 lines

If I understand your problem correctly, you want to differentiate between multiple v4l devices created by a single driver for a single hardware device. Using the above functions might work for ivtv but rules out devices that output multiple streams in the same format.

Wouldn't it be better to fix the ivtv driver to use a single device node for both compressed and uncompressed streams ?

I'm not very familiar with the v4l code base, so I don't have a good answer about if it's right or not. The core problem does tend to boil down to dealing with drivers that create multiple device nodes for the same physical hardware (ivtv is not alone in this regard).

I don't know what the semantics are for device mode vs device node in v4l, but it seems that since there are multiple nodes being created for a given piece of hardware, something needs to be exported to sysfs to distinguish them.

-Kees

Signature · 6 lines
Kees Cook                                            @outflux.net

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
#3 lore raw
Quoted 17 lines · Kees Cook

Hi Laurent,

Quoted 13 lines · Laurent Pinchart

linux/drivers/media/video/v4l2-common.c MODULE_LICENSE("GPL"); · line 108

Quoted 7 lines · Kees Cook
linux/drivers/media/video/v4l2-common.c +7 -0
+static const char *v4l2_function_type_names[] = {
+	[V4L2_FN_VIDEO_CAP]		= "vid-cap",
+	[V4L2_FN_VIDEO_OUT]		= "vid-out",
+	[V4L2_FN_MPEG_CAP]		= "mpeg-cap",
+	[V4L2_FN_MPEG_OUT]		= "mpeg-out",
+	[V4L2_FN_YUV_CAP]		= "yuv-cap",
+	[V4L2_FN_YUV_OUT]		= "yuv-out",

I don't like those. Video capture devices can encode pixels in a variety of formats. MPEG and YUV are only two special cases. You will find devices encoding in RGB, Bayer, MJPEG, ... as well as some proprietary formats.

Quoted 3 lines

If these devices have a variable encoding method, perhaps just use "vid-cap" as the general rule. (In the case that the output formats are selectable from a given device node at runtime.)

That would indeed be better. The function name should be derived from the v4l type if possible.

Quoted 13 lines
Quoted 7 lines

If I understand your problem correctly, you want to differentiate between multiple v4l devices created by a single driver for a single hardware device. Using the above functions might work for ivtv but rules out devices that output multiple streams in the same format.

Wouldn't it be better to fix the ivtv driver to use a single device node for both compressed and uncompressed streams ?

I'm not very familiar with the v4l code base, so I don't have a good answer about if it's right or not. The core problem does tend to boil down to dealing with drivers that create multiple device nodes for the same physical hardware (ivtv is not alone in this regard).

Quoted 4 lines

I don't know what the semantics are for device mode vs device node in v4l, but it seems that since there are multiple nodes being created for a given piece of hardware, something needs to be exported to sysfs to distinguish them.

Good point.

v4l drivers create several device nodes for good or not-so-good reasons. I think we can classify the hardware/drivers in several categories:

1. The device supports multiple concurrent data streams for different kind of data. The is most often found for audio/video or video/vbi. Audio is handled through alsa, and video and vbi are handled through v4l. The driver then creates a device node for each video/vbi data stream. The devices can easily be distinguished by their v4l type.

2. The device supports a single data stream with a selectable data format. The driver will create a single device node, format selection is handled through the v4l API.

3. The device supports multiple concurrent data streams for a single kind of data. ivtv falls under this case. The most common use case is a device with several video pipes (usually 2) that can be used simultaneously to stream the same data (in different or identical formats, either fixed or configurable).

Case 3 is the only one to cause device node naming issues. I'm not sure if the driver does the right thing when it creates several device nodes. Should the peripheral be seen as a single device that allows access by two users simultaneously, or should it be seen as two fixed-format devices ? Each solution will probably come with its own set of issues.

Laurent Pinchart

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

author
#4 lore raw

Hi Laurent,

Quoted 16 lines · Laurent Pinchart
Quoted 15 lines · Kees Cook
Quoted 13 lines · Laurent Pinchart

linux/drivers/media/video/v4l2-common.c MODULE_LICENSE("GPL"); · line 108

Quoted 7 lines · Kees Cook
linux/drivers/media/video/v4l2-common.c +7 -0
+static const char *v4l2_function_type_names[] = {
+	[V4L2_FN_VIDEO_CAP]		= "vid-cap",
+	[V4L2_FN_VIDEO_OUT]		= "vid-out",
+	[V4L2_FN_MPEG_CAP]		= "mpeg-cap",
+	[V4L2_FN_MPEG_OUT]		= "mpeg-out",
+	[V4L2_FN_YUV_CAP]		= "yuv-cap",
+	[V4L2_FN_YUV_OUT]		= "yuv-out",

I don't like those. Video capture devices can encode pixels in a variety of formats. MPEG and YUV are only two special cases. You will find devices encoding in RGB, Bayer, MJPEG, ... as well as some proprietary formats.

Quoted 6 lines
Quoted 3 lines

If these devices have a variable encoding method, perhaps just use "vid-cap" as the general rule. (In the case that the output formats are selectable from a given device node at runtime.)

That would indeed be better. The function name should be derived from the v4l type if possible.

Sure, but I think Kay's point was this it needs to be relatively "static" so that userspace (and udev) can depend on it not changing very much. I am not attached to any of the names in the proposed patch -- they work for me, but I'd be happy to see a different list if it were more sensible.

Quoted 16 lines
Quoted 4 lines

I don't know what the semantics are for device mode vs device node in v4l, but it seems that since there are multiple nodes being created for a given piece of hardware, something needs to be exported to sysfs to distinguish them.

Good point.

v4l drivers create several device nodes for good or not-so-good reasons. I think we can classify the hardware/drivers in several categories:

1. The device supports multiple concurrent data streams for different kind of data. The is most often found for audio/video or video/vbi. Audio is handled through alsa, and video and vbi are handled through v4l. The driver then creates a device node for each video/vbi data stream. The devices can easily be distinguished by their v4l type.

Quoted 8 lines

2. The device supports a single data stream with a selectable data format. The driver will create a single device node, format selection is handled through the v4l API.

3. The device supports multiple concurrent data streams for a single kind of data. ivtv falls under this case. The most common use case is a device with several video pipes (usually 2) that can be used simultaneously to stream the same data (in different or identical formats, either fixed or configurable).

Right -- case 3 is where the main problems and special-cases appeared when trying to work out a viable "static" path for udev to use to address a given v4l device.

Quoted 5 lines

Case 3 is the only one to cause device node naming issues. I'm not sure if the driver does the right thing when it creates several device nodes. Should the peripheral be seen as a single device that allows access by two users simultaneously, or should it be seen as two fixed-format devices ? Each solution will probably come with its own set of issues.

Whatever the situation, I doubt it will change soon for ivtv (or the others), so I'd like to see the basic functionality of the patch adopted. If there are things about it that aren't good, or could be improved about it, can you provide an updated patch to address any concerns? I think taking the patch through some iterations could help focus the discussion about it.

Thanks!

-Kees

Signature · 6 lines
Kees Cook                                            @outflux.net

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
#5 lore raw
Quoted 23 lines · Kees Cook

Hi Laurent,

Quoted 20 lines · Laurent Pinchart
Quoted 18 lines · Kees Cook
Quoted 13 lines · Laurent Pinchart

linux/drivers/media/video/v4l2-common.c MODULE_LICENSE("GPL"); · line 108

Quoted 7 lines · Kees Cook
linux/drivers/media/video/v4l2-common.c +7 -0
+static const char *v4l2_function_type_names[] = {
+	[V4L2_FN_VIDEO_CAP]		= "vid-cap",
+	[V4L2_FN_VIDEO_OUT]		= "vid-out",
+	[V4L2_FN_MPEG_CAP]		= "mpeg-cap",
+	[V4L2_FN_MPEG_OUT]		= "mpeg-out",
+	[V4L2_FN_YUV_CAP]		= "yuv-cap",
+	[V4L2_FN_YUV_OUT]		= "yuv-out",

I don't like those. Video capture devices can encode pixels in a variety of formats. MPEG and YUV are only two special cases. You will find devices encoding in RGB, Bayer, MJPEG, ... as well as some proprietary formats.

If these devices have a variable encoding method, perhaps just use "vid-cap" as the general rule. (In the case that the output formats are selectable from a given device node at runtime.)

Quoted 8 lines
Quoted 2 lines

That would indeed be better. The function name should be derived from the v4l type if possible.

Sure, but I think Kay's point was this it needs to be relatively "static" so that userspace (and udev) can depend on it not changing very much. I am not attached to any of the names in the proposed patch -- they work for me, but I'd be happy to see a different list if it were more sensible.

I'd like 'compressed' and 'uncompressed' better than 'mpeg' and 'yuv'.

Quoted 36 lines
Quoted 20 lines
Quoted 4 lines

I don't know what the semantics are for device mode vs device node in v4l, but it seems that since there are multiple nodes being created for a given piece of hardware, something needs to be exported to sysfs to distinguish them.

Good point.

v4l drivers create several device nodes for good or not-so-good reasons. I think we can classify the hardware/drivers in several categories:

1. The device supports multiple concurrent data streams for different kind of data. The is most often found for audio/video or video/vbi. Audio is handled through alsa, and video and vbi are handled through v4l. The driver then creates a device node for each video/vbi data stream. The devices can easily be distinguished by their v4l type.

2. The device supports a single data stream with a selectable data format. The driver will create a single device node, format selection is handled through the v4l API.

Quoted 5 lines

3. The device supports multiple concurrent data streams for a single kind of data. ivtv falls under this case. The most common use case is a device with several video pipes (usually 2) that can be used simultaneously to stream the same data (in different or identical formats, either fixed or configurable).

Right -- case 3 is where the main problems and special-cases appeared when trying to work out a viable "static" path for udev to use to address a given v4l device.

Quoted 5 lines

Case 3 is the only one to cause device node naming issues. I'm not sure if the driver does the right thing when it creates several device nodes. Should the peripheral be seen as a single device that allows access by two users simultaneously, or should it be seen as two fixed-format devices ? Each solution will probably come with its own set of issues.

Quoted 6 lines

Whatever the situation, I doubt it will change soon for ivtv (or the others), so I'd like to see the basic functionality of the patch adopted. If there are things about it that aren't good, or could be improved about it, can you provide an updated patch to address any concerns? I think taking the patch through some iterations could help focus the discussion about it.

My main concern is that the new function member duplicates the type member without adding much.

There's also something I don't get. Your issue is that you need a stable device node path for userspace applications. Depending on various parameters the video devices will be enumerated in a different order, screwing up the configuration. Why don't you just use the physical device path instead of adding a function ? Sure, the ivtv driver will create two device nodes, but it will do so in a fixed order, so the names will be predictable.

Best regards,

Laurent Pinchart

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

#6 lore raw

PATCH 1/1 v4l: Introduce "stream" attribute for persistent video4linux device nodes

Disclaimer: I am not attached to the name, "stream". Open to suggestion.

Kees introduced a patch set last week that attempts to get stable device naming for v4l. The set used a string attribute called function to allow udev to assemble a unique and stable path for device nodes.

This patch is similar. However, instead of a string an integer is used called "stream". If the driver calls video_register_device in the same order every time it is loaded then we can end up with something like this with the right udev rules[1]:

/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

Kees: I don't have a device that creates multiple device nodes. Please test with ivtv. :D

video_register_device_stream is available to drivers to request a specific stream number.

---
[1] Place the attached udev rules in /etc/udev/rules.d/60-persistent-v4l.rules

 linux/drivers/media/video/videodev.c |   96 ++++++++++++++++++++++++++++++++++-
 linux/include/media/v4l2-dev.h       |    4 +
 2 files changed, 98 insertions(+), 2 deletions(-)
linux/drivers/media/video/videodev.c +94 -2
Index: v4l-dvb-clean/linux/drivers/media/video/videodev.c
===================================================================
@@ -428,6 +428,14 @@ EXPORT_SYMBOL(v4l_printk_ioctl);
  *	sysfs stuff
  */
 
+static ssize_t show_stream(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->stream);
+}
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
 static ssize_t show_name(struct class_device *cd, char *buf)
 #else
@@ -486,6 +494,7 @@ static void video_release(struct device 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
 static struct device_attribute video_device_attrs[] = {
 	__ATTR(name, S_IRUGO, show_name, NULL),
+	__ATTR(stream, S_IRUGO, show_stream, NULL),
 	__ATTR_NULL
 };
 #endif
@@ -2013,8 +2022,81 @@ out:
 }
 EXPORT_SYMBOL(video_ioctl2);
 
+struct stream_number_info {
+	struct device *dev;
+	unsigned int used[VIDEO_NUM_DEVICES];
+};
+
+static int __fill_stream_number_info(struct device *cd, void *data)
+{
+	struct stream_number_info *info = data;
+	struct video_device *vfd = container_of(cd, struct video_device,
+						class_dev);
+
+	if (info->dev == vfd->dev)
+		info->used[vfd->stream] = 1;
+
+	return 0;
+}
+
+/**
+ * assign_stream_number - assign stream number based on parent device
+ * @vdev: video_device to assign stream 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 stream number if
+ * successful.
+ */
+static int get_stream_number(struct video_device *vdev, int num)
+{
+	struct stream_number_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_stream_number_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])
+			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_stream(vfd, type, nr, -1);
+}
+EXPORT_SYMBOL(video_register_device);
+
 /**
  *	video_register_device - register video4linux devices
  *	@vfd:  video device structure we want to register
@@ -2040,7 +2122,8 @@ static const struct file_operations vide
  *	%VFL_TYPE_RADIO - A radio card
  */
 
-int video_register_device(struct video_device *vfd, int type, int nr)
+int video_register_device_stream(struct video_device *vfd, int type, int nr,
+					int stream)
 {
 	int i=0;
 	int base;
@@ -2143,6 +2226,15 @@ int video_register_device(struct video_d
 	}
 #endif
 
+	ret = get_stream_number(vfd, stream);
+	if (ret < 0) {
+		printk(KERN_ERR "%s: get_stream_number failed\n",
+		       __func__);
+		goto fail_minor;
+	}
+
+	vfd->stream = ret;
+
 #if 1 /* keep */
 	/* needed until all drivers are fixed */
 	if (!vfd->release)
@@ -2159,7 +2251,7 @@ fail_minor:
 	mutex_unlock(&videodev_lock);
 	return ret;
 }
-EXPORT_SYMBOL(video_register_device);
+EXPORT_SYMBOL(video_register_device_stream);
 
 /**
  *	video_unregister_device - unregister a video4linux device
linux/include/media/v4l2-dev.h +4 -0
Index: v4l-dvb-clean/linux/include/media/v4l2-dev.h
===================================================================
@@ -113,6 +113,8 @@ struct video_device
 	int type;       /* v4l1 */
 	int type2;      /* v4l2 */
 	int minor;
+	/* attribute to diferentiate multiple streams on one physical device */
+	int stream;
 
 	int debug;	/* Activates debug level*/
 
@@ -373,6 +375,8 @@ void *priv;
 
 /* Version 2 functions */
 extern int video_register_device(struct video_device *vfd, int type, int nr);
+int video_register_device_stream(struct video_device *vfd, int type, int nr,
+					int stream);
 void video_unregister_device(struct video_device *);
 extern int video_ioctl2(struct inode *inode, struct file *file,
 			  unsigned int cmd, unsigned long arg);
# do not edit this file, it will be overwritten on update

ACTION!="add|change", GOTO="persistent_v4l_end" SUBSYSTEM!="video4linux", GOTO="persistent_v4l_end"

# check for valid "stream" number
TEST!="stream", GOTO="persistent_v4l_end"
ATTR{stream}!="?*", GOTO="persistent_v4l_end"

IMPORT{program}="path_id %p"
ENV{ID_PATH}=="?*", KERNEL=="video*", SYMLINK+="v4l/by-path/$env{ID_PATH}-video$attr{stream}" ENV{ID_PATH}=="?*", KERNEL=="audio*", SYMLINK+="v4l/by-path/$env{ID_PATH}-audio$attr{stream}"

LABEL="persistent_v4l_end"

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

author
#7 lore raw

Re: [PATCH] v4l: Introduce "stream" attribute for persistent video4linux device nodes

Hi,

Quoted 3 lines · Brandon Philips

Kees introduced a patch set last week that attempts to get stable device naming for v4l. The set used a string attribute called function to allow udev to assemble a unique and stable path for device nodes.

Just a quick correction: that patch was 99% Kay's. :) I just jammed stuff into individual drivers, and have been trying to run with it. Thanks for cooking up an alternative we can poke at. :)

Quoted 8 lines

This patch is similar. However, instead of a string an integer is used called "stream". If the driver calls video_register_device in the same order every time it is loaded then we can end up with something like this with the right udev rules[1]:

/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

This would certainly work for me, and is much cleaner as far as not needing to change each v4l device driver. I do remember Kay objecting to the idea of internal driver enumeration being exported to udev, but I'll let him speak up if this method is a problem too. :)

Quoted 2 lines

Kees: I don't have a device that creates multiple device nodes. Please test with ivtv. :D

If Kay ACKs it, I will give it a spin -- I would expect it to run just fine, though. :)

-Kees

Signature · 6 lines
Kees Cook                                            @outflux.net

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
author
#8 lore raw

Re: [PATCH] v4l: Introduce "stream" attribute for persistent video4linux device nodes

In reply to Brandon Philips

Hi Brandon,

Quoted 2 lines · Brandon Philips

Kees: I don't have a device that creates multiple device nodes. Please test with ivtv. :D

Unfortunately, this doesn't work with ivtv -- each device has a streamid of 0. (video0, video24, video32 all on the same PCI path reported stream 0)

Note that I backported this to 2.6.24 to test, so perhaps I did something wrong. I will double-check...

-Kees

Signature · 6 lines
Kees Cook                                            @outflux.net

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
#9 lore raw

Re: [PATCH] v4l: Introduce "stream" attribute for persistent video4linux device nodes

Quoted 7 lines · Kees Cook
Quoted 2 lines · Brandon Philips

Kees: I don't have a device that creates multiple device nodes. Please test with ivtv. :D

Unfortunately, this doesn't work with ivtv -- each device has a streamid of 0. (video0, video24, video32 all on the same PCI path reported stream 0)

Could you please try this one? I think I see the problem. Updated 60-persistent-v4l.rules attached.

[PATCH] v4l: Introduce "index" attribute for persistent video4linux device nodes

Kees introduced a patch set last week that attempts to get stable device naming for v4l. The set used a string attribute called function to allow udev to assemble a unique and stable path for device nodes.

This patch is similar. However, instead of a string an integer is used called "index". If the driver calls video_register_device in the same order every time it is loaded then we should end up with something like this with the right udev rules:

/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

However, I don't have a device that creates multiple indexes. Kees, please test with ivtv. :D

video_register_device_index is available to drivers to request a specific index number.

---
 drivers/media/video/videodev.c |   98 ++++++++++++++++++++++++++++++++++++++++-
 include/media/v4l2-dev.h       |    4 +
 2 files changed, 100 insertions(+), 2 deletions(-)
drivers/media/video/videodev.c +96 -2
Index: linux-2.6/drivers/media/video/videodev.c
===================================================================
@@ -424,6 +424,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)
 {
@@ -462,6 +470,7 @@ static void video_release(struct device 
 
 static struct device_attribute video_device_attrs[] = {
 	__ATTR(name, S_IRUGO, show_name, NULL),
+	__ATTR(index, S_IRUGO, show_index, NULL),
 	__ATTR_NULL
 };
 
@@ -1976,8 +1985,82 @@ out:
 }
 EXPORT_SYMBOL(video_ioctl2);
 
+static 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
@@ -2003,7 +2086,8 @@ static const struct file_operations vide
  *	%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;
@@ -2060,6 +2144,16 @@ int video_register_device(struct video_d
 	}
 	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);
 
@@ -2093,7 +2187,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
include/media/v4l2-dev.h +4 -0
Index: linux-2.6/include/media/v4l2-dev.h
===================================================================
@@ -97,6 +97,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*/
 
@@ -343,6 +345,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);
# do not edit this file, it will be overwritten on update

ACTION!="add|change", GOTO="persistent_v4l_end" SUBSYSTEM!="video4linux", GOTO="persistent_v4l_end"

# check for valid "index" number
TEST!="index", GOTO="persistent_v4l_end"
ATTR{index}!="?*", GOTO="persistent_v4l_end"

IMPORT{program}="path_id %p"
ENV{ID_PATH}=="?*", KERNEL=="video*", SYMLINK+="v4l/by-path/$env{ID_PATH}-video$attr{index}" ENV{ID_PATH}=="?*", KERNEL=="audio*", SYMLINK+="v4l/by-path/$env{ID_PATH}-audio$attr{index}"

LABEL="persistent_v4l_end"

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list