- v4l2视频驱动的一些命令都是通过ioctl函数来实现的,比如:VIDIOC_QUERYCAP、VIDIOC_QBUF、VIDIOC_DQBUF、VIDIOC_STREAMON、VIDIOC_STREAMOFF等
1. ioctl
1.1 什么是ioctl
-
概述:
ioctl
是设备驱动程序中对设备的I/O通道
进行管理的接口函数
。 -
所谓对
I/O通道
进行管理,就是对设备的一些特性进行控制
,例如串口的传输波特率、马达的转速等等。 -
作用: 一个
字符设备驱动
通常会实现设备打开
、关闭
、读
、写
等功能,在一些需要细分的情境下,如果需要扩展新的功能,通常以增设
ioctl() 命令
的方式实现。例:当你用read
,write
不能完成某一功能时,就用ioctl
来操作。
配合一些头文件(v4l2-controls.h / videodev2.h
),根据命令,实现对摄像头的操作,如:白平衡、聚焦、曝光、饱和度、亮度
…
#include <sys/ioctl.h> //需要引用的头文件
//参数一:文件描述符
//参数二:设备驱动命令,执行对应操作
//参数三:根据参数二变化
int ioctl(int fd, int cmd, ...) ;
1.1 v4l2_ioctl函数
- 只要是命令都会涉及到
v4l2_ioctl
方法的处理,源代码如下:
static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
//
struct video_device *vdev = video_devdata(filp);
int ret = -ENODEV;
if (vdev->fops->unlocked_ioctl) {
struct mutex *lock = v4l2_ioctl_get_lock(vdev, cmd);
if (lock && mutex_lock_interruptible(lock))
return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
//关联文件为:./ambarella/kernel/linux-4.14/drivers/media/v4l2-core/v4l2-ioctl.c:2956:long video_ioctl2(struct file *file,
if (lock)
mutex_unlock(lock);
} else
ret = -ENOTTY;
return ret;
}
1.2 video_ioctl2函数
v4l2-ioctl.c:文件的long video_ioctl2
函数如下:
long video_ioctl2(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, __video_do_ioctl);
// 关联文件为:./ambarella/kernel/linux-4.14/include/media/v4l2-ioctl.h:711:long int video_usercopy(struct file *file, unsigned int cmd,
}
1.3 video_usercopy函数
v4l2-ioctl.c:文件的 video_usercopy
函数:
long video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, v4l2_kioctl func)
{
...
// 前面都是一些检查,发现是写命令则把数据从用户空间拷贝到内核空间
if (copy_from_user(parg, (void __user *)arg, n))
goto out;
...
/* Handles IOCTL */
err = func(file, cmd, parg);
}
1.4 __video_fo_ioctl函数
static long __video_do_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
...
default_info.ioctl = cmd;
default_info.flags = 0;
default_info.debug = v4l_print_default;
info = &default_info;
...
// 重点执行下面的函数指针
write_only = _IOC_DIR(cmd) == _IOC_WRITE;
if (info->flags & INFO_FL_STD) {
typedef int (*vidioc_op)(struct file *file, void *fh, void *p);
const void *p = vfd->ioctl_ops;
const vidioc_op *vidioc = p + info->u.offset;
ret = (*vidioc)(file, fh, arg);
} else if (info->flags & INFO_FL_FUNC) {
ret = info->u.func(ops, file, fh, arg);
} else if (!ops->vidioc_default) {
ret = -ENOTTY;
} else {
ret = ops->vidioc_default(file, fh,
vfh ? v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0,
cmd, arg);
}
return ret;
}
v4l2
驱动复杂就在这些ioctl
上,下面按照应用层与驱动的交互顺序来具体的分析这些ioctl
。
2. ioctl 流程深入分析
应用空间的一个视频 app
与驱动的交互流程大致如下图所示