Fixing Linux Device Name Fluctuations After Reboot Using udev (Practical Example with PiKVM CSI Camera)
In a PiKVM environment built on a Raspberry Pi 3 Model B, we introduced a CSI-connected camera module to externally monitor the server’s front LED indicators and physical operational status. For the video streaming daemon, we adopted the lightweight and low-latency ustreamer (service name: ustreamer-csi), configured to stream MJPEG via port 8081.
During the initial setup, /dev/video0 was specified directly in the configuration file, and we confirmed that the video could be previewed smoothly via a web browser without any issues.
Implementing a Mechanism to Reliably Recognize the Camera Device After Reboots
However, after rebooting the system, checking uStreamer’s streaming status revealed that while the web server itself responded, the video stream had stopped.
Upon checking the API endpoint (/state), we found “online": false and “captured_fps": 0 as shown below, indicating that not a single frame was being acquired from the device.
{
"ok": true,
"result": {
"source": {
"resolution": {
"width": 640,
"height": 480
},
"online": false,
"desired_fps": 0,
"captured_fps": 0
},
"stream": {
"queued_fps": 0,
"clients": 0
}
}
}
Logging in via SSH after every reboot to check the device number and manually reconfigure the service is not practical. We needed to implement a mechanism that would automatically and reliably recognize the camera device and resume streaming even after an OS reboot, without human intervention.
Dynamic Allocation of /dev/video Numbers and Raspberry Pi-Specific Device Structures
To identify the cause of the issue, we checked the kernel logs.
dmesg | grep video
Part of the output was as follows:
bcm2835-isp bcm2835-isp: Device node output[0] registered as /dev/video13 bcm2835-codec bcm2835-codec: Device registered as /dev/video10 bcm2835_v4l2-0: V4L2 device registered as video2 - stills mode > 1280x720 bcm2835-codec bcm2835-codec: Device registered as /dev/video18
Due to the kernel initialization order, the bcm2835-v4l2 device for the CSI camera was registered as /dev/video2. Because the service definition hardcoded /dev/video0, a mismatch occurred, causing the open operation to fail.
The challenge here is the large number of V4L2 devices unique to the Raspberry Pi. Since the SoC’s internal hardware codec (bcm2835-codec) and Image Signal Processor (bcm2835-isp) generate numerous nodes (video10 to video23, etc.), simply specifying an “available video node" cannot accurately pinpoint the correct camera device.
Also, it is important to note that conditions like ATTR{name}=="mmal service 16.1″ found in older documentation do not match current environments, and on actual hardware, it is identified as camera0.
Generating a Fixed Symbolic Link (/dev/csi-camera) via udev Rules
Rather than trying to fix the device number itself, we use udev rules to automatically generate a unique symbolic link, /dev/csi-camera, that always points to the CSI camera.
Checking Actual Device Attributes
First, we extracted attributes available for udev conditions from the device currently recognized as the camera.
udevadm info --attribute-walk --name=/dev/video2
The key attributes extracted were as follows:
looking at device '/devices/platform/soc/3f00b840.mailbox/bcm2835-camera/video4linux/video2':
KERNEL=="video2"
SUBSYSTEM=="video4linux"
ATTR{index}"0"
ATTR{name}"camera0"
looking at parent device '/devices/platform/soc/3f00b840.mailbox/bcm2835-camera':
KERNELS=="bcm2835-camera"
SUBSYSTEMS=="vchiq-bus"
DRIVERS=="bcm2835-camera"
To avoid confusing it with other device nodes, we ensured uniqueness by combining ATTR{name}=="camera0″ with the parent device’s KERNELS=="bcm2835-camera" and DRIVERS=="bcm2835-camera".
Creating and Applying udev Rules
Make the PiKVM file system writable and create the rule file.
rwnano /etc/udev/rules.d/99-csi-camera.rules
Write the following single line into the file /etc/udev/rules.d/99-csi-camera.rules.
SUBSYSTEM=="video4linux", ATTR{name}"camera0", KERNELS"bcm2835-camera", DRIVERS=="bcm2835-camera", ATTR{index}=="0", SYMLINK+="csi-camera", TAG+="systemd", ENV{SYSTEMD_ALIAS}="/dev/csi-camera"
By adding TAG+="systemd" and ENV{SYSTEMD_ALIAS}="/dev/csi-camera", the udev-generated link is recognized as a systemd device unit (dev-csi\x2dcamera.device). After setting this up, reload the rules to apply them.
udevadm control --reload-rules udevadm trigger --subsystem-match=video4linux udevadm settle ro
Verifying the Symbolic Link
Check if the link is generated normally.
ls -l /dev/csi-camera readlink -f /dev/csi-camera
If it points to the actual device like /dev/csi-camera -> video2, it is successful.
Configuring Stable Systemd Service Startup Using the Fixed Device
We utilize the generated /dev/csi-camera from the uStreamer service. In addition to simply changing the path, configuring systemd’s startup order control (waiting for the device) prevents races where the service starts up before the camera device is recognized and fails.
Checking the Systemd Device Unit Name
Check the escaped device unit name handled by systemd.
systemd-escape --path --suffix=device /dev/csi-camera
Output result:
dev-csi\x2dcamera.device
Updating the Service Definition Edit the service configuration file to specify the fixed path and add dependencies.
rwnano /etc/systemd/system/ustreamer-csi.service
The contents of the configuration file /etc/systemd/system/ustreamer-csi.service are as follows:
[Unit] Description=uStreamer for CSI Camera Requires=dev-csi\x2dcamera.device After=network.target dev-csi\x2dcamera.device [Service] ExecStart=/usr/bin/ustreamer --device=/dev/csi-camera --host=0.0.0.0 --port=8081 Restart=always RestartSec=3 User=root [Install] WantedBy=multi-user.target
By specifying dev-csi\x2dcamera.device in Requires and After, the service is guaranteed to start at the timing when udev completes the device link generation. Apply the settings, restart the service, and return the file system to read-only.
systemctl daemon-reload systemctl restart ustreamer-csi ro
Ensuring Reliable Streaming via /dev/csi-camera and Applicability to Other Devices After completing the configuration, we checked uStreamer’s streaming status again.
curl -s http://127.0.0.1:8081/state
In the output, “online": true was displayed, frame rates were counted normally, and we confirmed that the stream video was displayed seamlessly from the browser as well. After running multiple OS reboot tests, we verified that even if the CSI camera’s physical number fluctuated to video0 or video2, the service started 100% reliably via /dev/csi-camera. This approach of “generating a fixed symbolic link from unique conditions using udev, and controlling service startup order with TAG+="systemd"" is applicable not only to cameras but to any devices prone to number fluctuations on Linux, such as USB-serial converters (/dev/ttyUSB*) or external storage.
Conclusion
We addressed the issue where the CSI camera’s device number fluctuates upon PiKVM reboot, causing uStreamer streaming to stop. By investigating attributes with udevadm to identify conditions including parent device information, we generated a fixed link /dev/csi-camera using udev rules. Furthermore, by linking it with systemd device dependencies (Requires), we established an environment where video streaming recovers automatically and reliably even after an OS reboot. This method is applicable to all kinds of Linux devices such as USB serial ports.
