Jetson Camera Drivers - Fixed V4L2 Video Devices

From RidgeRun Developer Connection
Revision as of 15:39, 6 December 2022 by Jsalas (talk | contribs) (Created page with "==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 an...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
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) \