1. V4L2驱动框架初探

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*

验证方法与判定标准

  1. 设备节点存在:执行ls -l /dev/video*,应看到新增的/dev/video0(若系统已有其他video设备,编号可能顺延,以dmesg | tail输出为准)。
  2. 内核日志确认:执行dmesg | tail,应看到v4l2-minimal: registered as /dev/videoN。
  3. 设备能力查询:执行v4l2-ctl -d /dev/videoN --all(需安装v4l-utils),输出中应包含Driver name: v4l2-minimal且Device Caps含Video Capture。
  4. 卸载清理:执行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,这是预期行为——本案例仅验证设备节点注册与生命周期管理。