1. V4L2驱动框架初探
任务目标
编写一个最简V4L2虚拟视频设备驱动,向内核注册一个video_device,加载后能在/dev下生成video0节点,卸载时节点自动消失。
环境与依赖
- Linux内核源码树(本案例基于5.15版本验证)
- 内核已开启
CONFIG_VIDEO_DEV与CONFIG_MEDIA_SUPPORT - 开发板或虚拟机可加载内核模块(
insmod/rmmod)
关键完整代码
创建文件v4l2_minimal.c:
#include <linux/module.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-dev.h>
static struct video_device vdev;
static int v4l2_minimal_open(struct file *fp)
{
return 0;
}
static const struct v4l2_file_operations v4l2_minimal_fops = {
.owner = THIS_MODULE,
.open = v4l2_minimal_open,
};
static int __init v4l2_minimal_init(void)
{
int ret;
strscpy(vdev.name, "v4l2-minimal", sizeof(vdev.name));
vdev.release = video_device_release_empty;
vdev.fops = &v4l2_minimal_fops;
vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE;
ret = video_register_device(&vdev, VFL_TYPE_VIDEO, -1);
if (ret < 0)
return ret;
pr_info("v4l2-minimal: registered as /dev/video%d\n", vdev.num);
return 0;
}
static void __exit v4l2_minimal_exit(void)
{
video_unregister_device(&vdev);
pr_info("v4l2-minimal: unregistered\n");
}
module_init(v4l2_minimal_init);
module_exit(v4l2_minimal_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Minimal V4L2 virtual video device");
Makefile
obj-m := v4l2_minimal.o
KDIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
编译与加载
make
sudo insmod v4l2_minimal.ko
ls -l /dev/video*
验证方法与判定标准
- 设备节点存在:执行
ls -l /dev/video*,应看到新增的/dev/video0(若系统已有其他video设备,编号可能顺延,以dmesg | tail输出为准)。 - 内核日志确认:执行
dmesg | tail,应看到v4l2-minimal: registered as /dev/videoN。 - 设备能力查询:执行
v4l2-ctl -d /dev/videoN --all(需安装v4l-utils),输出中应包含Driver name: v4l2-minimal且Device Caps含Video Capture。 - 卸载清理:执行
sudo rmmod v4l2_minimal后,/dev/videoN节点消失,dmesg显示unregistered。
常见问题
- 编译报错找不到
media/v4l2-device.h:确认内核源码已包含media子系统头文件,且KDIR指向的内核已配置CONFIG_MEDIA_SUPPORT=y。 - 注册返回-ENODEV:检查内核是否加载了
videodev模块(modprobe videodev),或确认内核编译时未将V4L2核心设为模块且未加载。 - 打开设备节点失败:本驱动仅实现
open回调,未实现ioctl等操作。若应用调用VIDIOC_QUERYCAP会返回ENOTTY,这是预期行为——本案例仅验证设备节点注册与生命周期管理。