Difference between revisions of "Jetson Camera Drivers - Fixed V4L2 Video Devices"
(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...") |
m |
||
Line 165: | Line 165: | ||
− | [[Category:Jetson | + | [[Category:Jetson]][[Category:Xavier]] |
Revision as of 13:37, 5 January 2023
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) \