本文从零开始,逐步完成一个基于 V4L2/Media Controller 框架的虚拟 MIPI CSI-2 摄像头传感器驱动,覆盖 Sensor 驱动注册 → V4L2 subdev → Media Entity → DT 配置 → QEMU 验证 全流程。
1. 前置条件
确保以下环境已就绪(参考同级页面的 QEMU + 交叉编译工具链搭建指南):
交叉编译器
arm-linux-gnueabihf-gcc 可用已编译 v6.1 内核源码,且开启
CONFIG_VIDEO_DEV、CONFIG_MEDIA_SUPPORT、CONFIG_I2C 支持QEMU mcimx6ul-evk(Cortex-A7)能正常启动 BusyBox rootfs
内核配置中已启用
CONFIG_VIDEO_V4L2、CONFIG_MEDIA_CONTROLLER为什么选 V4L2? V4L2(Video for Linux 2)是 Linux 视频设备的标准子系统,配合 Media Controller 框架可描述复杂的摄像头流水线拓扑(Sensor → CSI → ISP → Video Node),是 MIPI CSI-2 摄像头的首选框架。
2. V4L2 子系统关键概念
概念 | 说明 |
v4l2_subdev | 代表视频流水线中的一个子设备(如 Sensor、ISP),类比 IIO 中的 iio_dev |
v4l2_subdev_ops | 子设备操作集,包含 video(流控制)、pad(格式协商)、core(通用操作)等回调 |
media_entity | Media Controller 中的实体节点,描述设备在流水线拓扑中的位置和连接关系 |
media_pad | 实体的输入/输出端口,Source Pad 输出数据,Sink Pad 接收数据 |
v4l2_async_register_subdev | 异步注册子设备,等待 CSI 桥接驱动就绪后自动完成绑定 |
v4l2_ctrl_handler | V4L2 控件管理器,统一管理曝光、增益、白平衡等参数控件 |
V4L2 摄像头流水线架构
3. 驱动源码
3.1 虚拟摄像头传感器驱动 — fake_cam.c
3.2 关键结构说明
元素 | 作用 |
v4l2_i2c_subdev_init | 初始化 V4L2 子设备并绑定 I2C client,自动设置 sd->dev 和 sd->name |
V4L2_SUBDEV_FL_HAS_DEVNODE | 标记子设备需要创建 /dev/v4l-subdevX 设备节点,允许用户态直接访问 |
media_entity_pads_init | 初始化 Media Entity 的 Pad(Source/Sink),定义设备在流水线中的连接能力 |
MEDIA_ENT_F_CAM_SENSOR | 标记 Entity 功能为摄像头传感器, media-ctl 拓扑图中将显示为 Sensor 节点 |
v4l2_ctrl_handler | 统一管理曝光、增益、翻转等 V4L2 标准控件,用户通过 v4l2-ctl -C 读写 |
v4l2_async_register_subdev | 异步注册子设备,等待 CSI 桥接驱动调用 v4l2_async_notifier 完成绑定 |
fake_cam_pad_ops | Pad 操作集: enum_mbus_code 枚举媒体总线格式,get/set_fmt 协商分辨率 |
fake_cam_s_stream | 流控制回调:CSI 驱动调用此函数启动/停止 Sensor 的 MIPI 数据输出 |
V4L2 subdev 三层操作集:core_ops提供通用功能(日志、电源管理),video_ops控制数据流启停(s_stream),pad_ops处理格式协商(分辨率/像素格式在 pad 层面逐级传递)。这种分层设计使得同一个 Sensor 驱动可适配不同的 CSI 桥接驱动。
4. Makefile
5. 编译模块
编译成功后确认产出:
注意depends: videodev,mc:V4L2 核心(videodev)和 Media Controller(mc)是独立模块,加载fake_cam.ko前必须先加载它们(或内核内建)。
6. 设备树配置
6.1 MIPI CSI-2 Sensor 节点说明
摄像头传感器挂载在 I2C 总线上进行寄存器控制,同时通过 MIPI CSI-2 接口传输图像数据。DT 中需要:
- I2C 子节点声明 Sensor 设备(
reg= I2C 地址)
port子节点描述 MIPI CSI-2 连接(data-lanes、remote-endpoint)
6.2 需要注入的 DT 节点
QEMU 简化说明:QEMU mcimx6ul-evk 不模拟 MIPI CSI-2 控制器,因此port节点中的remote-endpoint无法真正连接 CSI 桥接驱动。本实战重点验证 I2C probe → V4L2 subdev 注册 → Media Entity 创建 → Controls sysfs,实际的media-ctl拓扑和v4l2-ctl --stream需在真实硬件上验证。
6.3 直接修改主 DTB(QEMU 方式)
7. 一键构建脚本 — build.sh
运行方式:
8. QEMU 内加载验证
8.1 启动 QEMU — run_qemu.sh
8.2 加载模块
8.3 确认 probe 调用
8.4 查看 V4L2 subdev 信息
8.5 验证 V4L2 Controls
8.6 验证格式协商
8.7 自动化验证脚本 — verify_cam.sh
预期输出:
QEMU 摄像头限制:QEMU mcimx6ul-evk 不模拟 MIPI CSI-2 控制器和 DMA,因此无法进行v4l2-ctl --stream实际抓帧。本实战重点验证 V4L2 subdev 注册 + Media Entity + Controls + 格式协商 全链路,实际图像采集在真实硬件上验证。
9. 验证清单
make 编译无 warning,产出 fake_cam.komodinfo 输出 depends: videodev,mcfile fake_cam.ko 显示 ARM ELF relocatable设备树中
i2c1 节点下存在 fake_cam@3c 子节点insmod 后 dmesg 显示 probe OK, addr=0x3c, default 640x480/sys/class/video4linux/v4l-subdev0/name 输出 fake_cam 0-003cV4L2 Controls 可列出(exposure / analogue_gain / hflip / vflip)
v4l2-ctl -c exposure=2000 后 dmesg 显示 set exposure=2000格式协商返回 640x480 / 1280x720 / 1920x1080 三种帧大小
verify_cam.sh 全部步骤通过rmmod 后 dmesg 显示 remove called10. 常见问题排查
现象 | 原因 | 解决方案 |
insmod: unknown symbol v4l2_i2c_subdev_init | V4L2 核心模块未加载 | 先 insmod videodev.ko,或内核配置 CONFIG_VIDEO_DEV=y |
insmod: unknown symbol media_entity_pads_init | Media Controller 模块未加载 | 先 insmod mc.ko,或内核配置 CONFIG_MEDIA_SUPPORT=y |
probe 未调用 | DT 中 compatible 不匹配或节点不在 I2C 控制器下 | 确认 compatible = "myvendor,fake-cam" 与驱动 of_match_table 一致 |
/dev/v4l-subdev0 不存在 | 未设置 V4L2_SUBDEV_FL_HAS_DEVNODE 或内核未开启 CONFIG_VIDEO_V4L2_SUBDEV_API | 确认驱动 flags 包含该标志;内核 menuconfig 启用 V4L2 sub-device userspace API |
v4l2-ctl --list-ctrls 为空 | v4l2_ctrl_handler 未正确关联到 sd->ctrl_handler | 确认 cam->sd.ctrl_handler = handler 在 probe 中正确赋值 |
v4l2_async_register_subdev 返回 -ENODEV | V4L2 异步注册找不到匹配的 notifier(QEMU 无 CSI 桥接驱动) | QEMU 下可改用 v4l2_async_register_subdev_sensor 或直接注册非异步子设备 |
media-ctl -p 无输出 | rootfs 中缺少 media-ctl 工具 | 交叉编译 v4l-utils 包并打入 rootfs,或使用 sysfs 手动查看 |
insmod: invalid module format | vermagic 不匹配 | 确保 KERNDIR 指向 QEMU 启动时使用的同一内核树 |
11. 向真实硬件(OV5640 + i.MX8MP)迁移
完成虚拟驱动验证后,迁移到真实 OV5640 MIPI CSI-2 摄像头需替换以下部分:
- probe 中添加 Chip ID 检测
- 替换为真实寄存器操作
- DT compatible 改为
ovti,ov5640,添加完整端口描述
- 添加电源和时钟管理 —
devm_clk_get+devm_regulator_bulk_get+devm_gpiod_get
- 对接 CSI-2 桥接驱动 — i.MX8MP 的
imx8-isi/imx-mipi-csi2驱动通过v4l2_async_notifier自动绑定 Sensor
12. 下一步扩展方向
- Triggered Buffer + DMA 抓帧 — 配合 CSI DMA 控制器实现连续帧捕获,用
v4l2-ctl --stream-mmap验证
- ISP 流水线 — 在 Sensor 和 Video Device 之间插入 ISP 子设备,实现去马赛克、白平衡等处理
- media-ctl 拓扑配置 — 使用
media-ctl -l和media-ctl -V配置完整的 Sensor → CSI → ISP → Video 链路
- V4L2 用户态应用 — 使用
libv4l2编写摄像头预览和录制程序
- IMU + Camera 时间戳同步 — IIO 触发器与 V4L2 缓冲区时间戳对齐,构建完整感知平台







