4. V4L2框架基础:Video for Linux 2核心数据结构与注册流程

V4L2(Video for Linux 2)是Linux内核中视频设备驱动的标准框架,也是RK平台Sensor驱动与ISP交互的核心通道。理解V4L2的三大核心数据结构——video_device、v4l2_device、v4l2_subdev——及其注册流程,是进行RAW数据采集性能调优的前提。

学习提示: 在RK平台上,Sensor通常作为v4l2_subdev注册,而ISP Capture节点作为video_device注册。两者通过v4l2_device进行管理,形成“Subdev + Video Node”的经典架构。

4.1 三大核心数据结构概览

下表从角色、职责、关键成员三个维度对比了V4L2的三大核心数据结构:

数据结构 角色 核心职责 关键成员
v4l2_device 顶层管理容器 管理所有子设备(Subdev)和视频节点,提供统一的调试/电源管理接口 subdevs链表、ctrl_handler、dev(父设备)
video_device 用户空间接口 创建/dev/videoX节点,实现open/close/ioctl等文件操作 fops、v4l2_dev、queue(vb2队列)
v4l2_subdev 硬件组件抽象 封装Sensor、MIPI桥、AF驱动等硬件控制逻辑,通过pad与media_entity连接 ops(操作函数集)、pad数组、v4l2_dev、ctrl_handler

4.2 v4l2_device:顶层管理容器

v4l2_device是整个V4L2设备树的根节点。在RK平台上,通常由ISP驱动或Video Capture驱动在 probe 阶段创建并注册。

// 分配与初始化
struct v4l2_device *v4l2_dev;
v4l2_dev = devm_kzalloc(dev, sizeof(*v4l2_dev), GFP_KERNEL);
v4l2_device_init(v4l2_dev, dev);

// 注册(通常在父设备 probe 中完成)
v4l2_device_register(subdev_dev, v4l2_dev);
关键点: v4l2_device不直接创建/dev节点,它只作为内部管理容器。所有子设备通过v4l2_device_register_subdev()挂接到其subdevs链表上。

4.3 video_device:用户空间接口

video_device是用户空间与内核驱动交互的桥梁。每个video_device对应一个/dev/videoX节点。在RK RAW数据采集场景中,这个节点通常对应ISP的Capture通道。

// 定义文件操作集
static const struct v4l2_file_operations rkisp_fops = {
    .owner      = THIS_MODULE,
    .open       = rkisp_fop_open,
    .release    = rkisp_fop_release,
    .unlocked_ioctl = video_ioctl2,
    .mmap       = rkisp_mmap,
    .poll       = rkisp_poll,
};

// 分配与初始化 video_device
struct video_device *vdev;
vdev = video_device_alloc();
vdev->fops     = &rkisp_fops;
vdev->v4l2_dev = &isp->v4l2_dev;
vdev->queue    = &isp->vb2_queue;
vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;

// 注册 video_device
video_register_device(vdev, VFL_TYPE_VIDEO, -1);
性能调优注意: video_device的queue成员指向vb2_queue,这是RAW数据缓冲区的管理核心。在RK平台上,vb2_queue的buf_struct_size和min_buffers_needed设置直接影响DMA缓冲区的分配策略和采集延迟。

4.4 v4l2_subdev:硬件组件抽象

v4l2_subdev是V4L2框架中最灵活的数据结构,用于抽象Camera Sensor、MIPI D-PHY、AF马达等硬件组件。在RK平台上,Sensor驱动通常实现为v4l2_subdev,并通过media_entity与ISP的Capture Subdev连接。

// 定义 subdev 操作函数集
static const struct v4l2_subdev_video_ops sensor_video_ops = {
    .s_stream = sensor_s_stream,   // 启动/停止流
    .g_frame_interval = sensor_g_frame_interval,
    .s_frame_interval = sensor_s_frame_interval,
};

static const struct v4l2_subdev_core_ops sensor_core_ops = {
    .s_power = sensor_s_power,     // 电源管理
};

static const struct v4l2_subdev_ops sensor_ops = {
    .core  = &sensor_core_ops,
    .video = &sensor_video_ops,
};

// 初始化 subdev
struct v4l2_subdev *sd;
v4l2_subdev_init(sd, &sensor_ops);
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
snprintf(sd->name, sizeof(sd->name), "%s %s", dev->driver->name, dev_name(dev));

// 注册 subdev 到 v4l2_device
v4l2_device_register_subdev(v4l2_dev, sd);

4.5 注册流程与媒体拓扑

在RK平台上,V4L2设备的注册遵循“自底向上”的顺序:先注册v4l2_device,再注册v4l2_subdev,最后注册video_device。同时,通过media_entity和media_pad建立设备间的数据流拓扑。

// 创建 media link:Sensor -> ISP
struct media_pad *source_pad = &sensor_sd->entity.pads[0]; // Sensor 输出 pad
struct media_pad *sink_pad   = &isp_sd->entity.pads[0];   // ISP 输入 pad
media_create_pad_link(&sensor_sd->entity, 0,
                      &isp_sd->entity, 0, 0);
RK平台实践: 在RK3588/RK3568上,Sensor的v4l2_subdev注册后,需要通过media-ctl工具或驱动内部调用media_create_pad_link()建立从Sensor到ISP的链路,否则用户空间无法通过/dev/videoX采集到RAW数据。

4.6 核心数据结构关系图

下图展示了V4L2三大核心数据结构在RK平台上的组织关系与注册流程:

V4L2核心数据结构关系与注册流程 V4L2核心数据结构关系与注册流程(RK平台) v4l2_device 顶层管理容器(ISP驱动创建) ① 先注册 v4l2_subdev (Sensor) 硬件抽象:MIPI Sensor ops: s_stream / s_power v4l2_subdev (ISP) 硬件抽象:ISP输入 ops: s_stream / s_fmt register_subdev register_subdev media link pad:0 → pad:0 ② 后注册 ② 后注册 video_device 用户空间接口:/dev/videoX fops: open/ioctl/mmap/poll v4l2_dev 指针 vb2_queue (DMA缓冲区队列) buf_struct_size / min_buffers_needed queue 指针 用户空间应用程序 open / ioctl / mmap / poll 系统调用 注册流程总结: ① 父设备 probe → v4l2_device_register() 创建顶层容器 ② Sensor/ISP subdev probe → v4l2_device_register_subdev() 注册子设备 ③ media_create_pad_link() 建立 Sensor→ISP 数据链路 ④ video_device probe → video_register_device() 创建 /dev/videoX 节点

4.7 注册流程关键步骤

在RK平台上,完整的V4L2设备注册流程分为以下四个阶段:

  1. 阶段一:v4l2_device 注册 — 由ISP驱动或Video Capture驱动在 probe 中调用 v4l2_device_register(),创建顶层管理容器。
  2. 阶段二:v4l2_subdev 注册 — Sensor驱动、MIPI D-PHY驱动等调用 v4l2_device_register_subdev() 将自身挂接到 v4l2_device 的 subdevs 链表。
  3. 阶段三:media link 建立 — 通过 media_create_pad_link() 在Sensor Subdev的输出Pad与ISP Subdev的输入Pad之间建立数据流连接。
  4. 阶段四:video_device 注册 — ISP Capture驱动调用 video_register_device() 创建 /dev/videoX 节点,并关联 vb2_queue 用于RAW数据缓冲区管理。
性能调优关联: 注册顺序影响设备初始化时序。在RK平台上,如果video_device在v4l2_subdev之前注册,用户空间可能在Sensor未就绪时尝试打开设备,导致采集失败。建议严格遵循“v4l2_device → subdev → media link → video_device”的顺序。

4.8 数据结构对比总结

对比维度 v4l2_device video_device v4l2_subdev
用户空间可见 否 是(/dev/videoX) 否(通过media-ctl间接可见)
生命周期 父设备 probe → remove 注册后常驻 随硬件模块 probe/remove
核心操作 管理子设备、调试 文件操作、缓冲区管理 硬件控制(流、格式、电源)
RK平台典型实例 rkisp_v4l2_dev rkisp_maindev / rkisp_selfpath sensor_subdev / isp_subdev
性能影响 低(管理开销) 高(缓冲区分配、中断处理) 中(流控制、格式协商)
调试技巧: 在RK平台上,可以通过 ls /dev/video* 查看所有视频节点;通过 media-ctl -p -d /dev/media0 查看完整的媒体拓扑,包括所有v4l2_subdev实体和pad连接关系。