Jetson Camera Drivers - Fixed V4L2 Video Devices
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) \