3. 实现VIDIOC_QUERYCAP查询设备能力
任务说明
实现V4L2设备驱动的ioctl处理函数,支持VIDIOC_QUERYCAP命令,向应用层返回设备驱动名称(driver)、总线信息(bus_info)、驱动版本号(version)及设备能力标志(capabilities)。本案例以虚拟摄像头驱动为最小实现,不涉及真实硬件。
核心实现
#include <linux/videodev2.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#define VIRTUAL_CAM_DRIVER_NAME "virtual_cam"
#define VIRTUAL_CAM_BUS_INFO "platform:virtual_cam"
static int virtcam_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
/* 驱动名称:必须以\0结尾,且不超过16字节(含\0) */
strscpy(cap->driver, VIRTUAL_CAM_DRIVER_NAME, sizeof(cap->driver));
/* 总线信息:描述设备挂载位置,不超过32字节 */
strscpy(cap->bus_info, VIRTUAL_CAM_BUS_INFO, sizeof(cap->bus_info));
/* 内核版本号:使用LINUX_VERSION_CODE宏自动生成 */
cap->version = LINUX_VERSION_CODE;
/* 设备能力:仅声明支持视频采集和流式I/O */
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
/* 设备特定能力(可选):此处与capabilities保持一致 */
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
return 0;
}
/* 关联到v4l2_ioctl_ops结构体 */
static const struct v4l2_ioctl_ops virtcam_ioctl_ops = {
.vidioc_querycap = virtcam_querycap,
};
/* 最小video_device注册示例 */
static struct video_device virtcam_vdev = {
.name = "Virtual Camera",
.vfl_dir = VFL_DIR_RX,
.ioctl_ops = &virtcam_ioctl_ops,
.release = video_device_release_empty,
};
static int __init virtcam_init(void)
{
return video_register_device(&virtcam_vdev, VFL_TYPE_VIDEO, -1);
}
static void __exit virtcam_exit(void)
{
video_unregister_device(&virtcam_vdev);
}
module_init(virtcam_init);
module_exit(virtcam_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Virtual camera driver for VIDIOC_QUERYCAP demo");
关键说明
strscpy确保字符串安全拷贝并强制\0结尾,避免缓冲区溢出。cap->version直接使用内核版本宏,应用层可通过该字段判断驱动适配的内核API版本。capabilities与device_caps的区别:前者表示整个设备支持的能力,后者表示当前打开的设备节点支持的能力。本案例两者一致。- 若需支持
VIDIOC_QUERYCAP以外的ioctl,只需在virtcam_ioctl_ops中继续添加对应的回调函数。
编译与加载
# 编译(需内核头文件与build目录)
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
# 加载模块
sudo insmod virtcam.ko
# 查看生成的设备节点(通常为 /dev/video0)
ls -l /dev/video*
验证方法
使用v4l2-ctl工具查询设备能力:
v4l2-ctl -d /dev/video0 --all
通过条件:输出中应包含:
- Driver name:
virtual_cam - Bus info:
platform:virtual_cam - Version: 与当前内核版本对应的数值(如
6.8.0) - Device Caps:
Video Capture | Streaming
若v4l2-ctl不可用,也可用以下C程序直接调用ioctl验证:
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
int main(void) {
int fd = open("/dev/video0", O_RDWR);
if (fd < 0) { perror("open"); return 1; }
struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
perror("VIDIOC_QUERYCAP");
close(fd);
return 1;
}
printf("driver: %s\n", cap.driver);
printf("bus_info: %s\n", cap.bus_info);
printf("version: %u.%u.%u\n",
(cap.version >> 16) & 0xFF,
(cap.version >> 8) & 0xFF,
cap.version & 0xFF);
printf("capabilities: 0x%08x\n", cap.capabilities);
close(fd);
return 0;
}
编译运行:gcc test_querycap.c -o test_querycap && ./test_querycap,程序应打印上述字段且无错误返回。