上一篇文章中,已经介绍了v4l2_open、v4l2_read、v4l2_write的调用过程,相对于v4l2_ioctl,它们是比较简单的。下面来分析v4l2_ioctl。注意在这里还是分析以vivi.c为例,进行分析。
app: ioctl
---------------------------------------------------------------------------
drv: v4L2_fops.unlocked_ioctl
.v4L2_ioctl
vdev = video_devdata(filp);
vdev->fops->unlocked_ioctl(filp, cmd, arg);//调用具体设备提供的unlocked_ioctl,因为本篇文章是以vivi.c为例进行分析,.unlocked_ioctl = video_ioctl2
video_ioctl2
video_usercopy(file, cmd, arg, __video_do_ioctl)
__video_do_ioctl
video_ioctl2
long video_ioctl2(struct file *file,unsigned int cmd, unsigned long arg)
{
//根据命令cmd的不同,调用__video_do_ioctl,将数据拷贝到内核空间
return video_usercopy(file, cmd, arg, __video_do_ioctl);
}
__video_do_ioctl
//以次设备号为下标,从video_device[]中取出对应的video_device,此处就是vivi_template
struct video_device *vfd = video_devdata(file);
//获取vivi_template的ioctl_ops
const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
----------
switch (cmd) {
/* --- capabilities ------------------------------------------ */
case VIDIOC_QUERYCAP://cmd命令
{
//v4l2设备的能力结构体
struct v4l2_capability *cap = (struct v4l2_capability *)arg;
if (!ops->vidioc_querycap)
break;
cap->version = LINUX_VERSION_CODE;
//根据不同的cmd,调用到了ioctl_ops中的vidioc_querycap
ret = ops->vidioc_querycap(file, fh, cap);
----
break
}
现总结一下这个过程:
1、video_device被设置成了vivi_template //在函数vivi_create_instance中被设置
2、vdev->cdev->ops = &v4l2_fops; //在函数__video_register_device中被设置
3、video_device[vdev->minor] = vdev;//在函数__video_register_device中被设置
当用户空间调用ioctl的时候,v4l2_fops的v4l2_ioctl将被调用;
在v4l2_ioctl中,vivi_template->fops->unlocked_ioctl(filp, cmd, arg) 即video_ioctl2函数会被调用;
在video_ioctl2中,__video_do_ioctl函数会被调用;
在__video_do_ioctl中,根据cmd来调用vivi_template中的vivi_ioctl_ops结构体中对应的函数。