Jetson Camera Drivers - Fixed V4L2 Video Devices

From RidgeRun Developer Connection
Jump to: navigation, search

Overview

The following changes allow to define a fixed name for the V4L2 video device created when loading a camera driver. These changes were tested on JP-4.5.1 and JP 4.6. After applying them, recompile both the kernel and device tree and update them into your Jetson board.

Device-tree Changes

Define devnode field on the specific VI port node:

/ {
    ....
    host1x {
        /* VI Setup */
        vi@15700000 {
            ports {
                port@0 {
                    reg = <0>;
                    camera_vi_in0: endpoint {
                        devnode = "video1"; /* V4L2 Device name as preferred by the user */
                        port-index = <4>;
                        vc-id = <0>;
                        bus-width = <4>;
                        remote-endpoint = <&camera_csi_out0>;
                    };
                };
             ....

Kernel Changes

Apply the following changes to fix video device names.

  • kernel/kernel-4.9/drivers/media/v4l2-core/v4l2-dev.c
@@ -825,6 +825,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
 	int minor_offset = 0;
 	int minor_cnt = VIDEO_NUM_DEVICES;
 	const char *name_base;
+	int n = 0;
+	int valid_name = 1;
 
 	/* A minor value of -1 marks this video device as never
 	   having been registered */
@@ -964,7 +966,42 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
 	vdev->dev.class = &video_class;
 	vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
 	vdev->dev.parent = vdev->dev_parent;
-	dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
+	if (VFL_TYPE_GRABBER == type) {
+
+		/* If no video name was assigned in the device tree then assign one */
+		if (strcmp(vdev->name, "") == 0) {
+			snprintf(vdev->name, sizeof(vdev->name), "%s%d", name_base, vdev->num);
+		}
+
+		/* Compare the name we just set with every other device to check that there
+		   isn't other with an equal name */
+		do {
+			/* Assume that the name is valid, otherwise it will be set to 0 and the
+			   loop will continue */
+			valid_name = 1;
+			for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
+				if (video_device[i] != NULL) {
+					if (video_device[i]->dev.kobj.name != NULL) {
+						/* If we find another device with the same name then start the
+						   check again with the next videoX name, where X is the n
+						   counter */
+						if (strcmp(video_device[i]->dev.kobj.name, vdev->name) == 0) {
+							snprintf(vdev->name, sizeof(vdev->name), "%s%d", name_base, n);
+							n++;
+							valid_name = 0;
+							break;
+						}
+					}
+				}
+			}
+			/* If a valid name was found we will exit with the final name set,
+			   otherwise repeat the loop to check the new proposed name */
+		} while (!valid_name);
+
+		dev_set_name(&vdev->dev, "%s", vdev->name);
+	} else {
+		dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
+	}
 	ret = device_register(&vdev->dev);
 	if (ret < 0) {
 		printk(KERN_ERR "%s: device_register failed\n", __func__);
  • kernel/nvidia/drivers/media/platform/tegra/camera/vi/channel.c
@@ -2290,6 +2290,16 @@ int tegra_channel_init_video(struct tegra_channel *chan)
 	chan->video->ctrl_handler = &chan->ctrl_handler;
 	chan->video->lock = &chan->video_lock;
 
+	/* Validate that the name fits */
+	if (ARRAY_SIZE(chan->video->name) >= ARRAY_SIZE(chan->devnode_name)) {
+		strncpy(chan->video->name, chan->devnode_name, ARRAY_SIZE(
+				chan->devnode_name));
+	} else {
+		ret = -ENOMEM;
+		dev_err(&chan->video->dev, "Not enough space for channel video name");
+		goto ctrl_init_error;
+	}
+
 	video_set_drvdata(chan->video, chan);
 
 	return ret;
  • kernel/nvidia/drivers/media/platform/tegra/camera/vi/graph.c
@@ -518,6 +518,7 @@ int tegra_vi_get_port_info(struct tegra_channel *chan,
 	struct device_node *port;
 	int value = 0xFFFF;
 	int ret = 0, i;
+	const char *temp_str = NULL;
 
 	ports = of_get_child_by_name(node, "ports");
 	if (ports == NULL)
@@ -550,6 +551,20 @@ int tegra_vi_get_port_info(struct tegra_channel *chan,
 				return -EINVAL;
 			}
 
+			/* Get video device name */
+			ret = of_property_read_string(ep, "devnode", &temp_str);
+			if (ret < 0) {
+				strcpy(chan->devnode_name, "");
+				dev_err(chan->vi->dev, "devnode name not defined\n");
+			} else {
+				/* Validate that the name plus the null character fits */
+				if (ARRAY_SIZE(chan->devnode_name) >= strlen(temp_str) + 1) {
+					strncpy(chan->devnode_name, temp_str, strlen(temp_str) + 1);
+				} else {
+					dev_err(chan->vi->dev, "Not enough space for devnode name");
+					return -ENOMEM;
+				}
+			}
 			/* Get CSI port */
 			ret = of_property_read_u32(ep, "port-index", &value);
 			if (ret < 0)
  • kernel/nvidia/include/media/mc_common.h
@@ -48,6 +48,8 @@
 #define TEGRA_MEM_FORMAT 0
 #define TEGRA_ISP_FORMAT 1
 
+#define V4L2_VIDEO_DEVICE_NAME_SIZE 32
+
 enum channel_capture_state {
 	CAPTURE_IDLE = 0,
 	CAPTURE_GOOD,
@@ -263,6 +265,7 @@ struct tegra_channel {
 
 	atomic_t syncpt_depth;
 	struct rw_semaphore reset_lock;
+	char devnode_name[V4L2_VIDEO_DEVICE_NAME_SIZE];
 };
 
 #define to_tegra_channel(vdev) \


RidgeRun Resources

Quick Start Client Engagement Process RidgeRun Blog Homepage
Technical and Sales Support RidgeRun Online Store RidgeRun Videos Contact Us

OOjs UI icon message-progressive.svg Contact Us

Visit our Main Website for the RidgeRun Products and Online Store. RidgeRun Engineering informations are available in RidgeRun Professional Services, RidgeRun Subscription Model and Client Engagement Process wiki pages. Please email to support@ridgerun.com for technical questions and contactus@ridgerun.com for other queries. Contact details for sponsoring the RidgeRun GStreamer projects are available in Sponsor Projects page. Ridgerun-logo.svg
RR Contact Us.png