v4l2中ioctl的调用流程
2015-09-21 16:04
375 查看
leesagacious 原创,欢迎转载
看看这个结构体张什么样
经过以上分析,可以看出当应用程序调用ioctl的时候,首先调用通用框架v4l2_fops中的ioctl,
在v4l2_fops中的ioctl是v4l2_ioctl,在v4l2_ioctl中,会调用具体设备(这里是vivi_template)
file_operation中定义的unlocked_ioctl,
在vivi_template中的unlocked_ioctl是video_ioctl2,这个video_ioctl2会根据命令来调用vivi_template
中定义的ioctl_ops中定义的函数
vivi入口函数: vivi_init( )
[code]vivi_init(void) static int __init vivi_init(void) { ..... for(i = 0;i < n_devs;i++){ //这里的n_devs的值是 1 //调用了这个函数,来创建设备 ret = vivi_create_instance(i); } }
vivi_create_instance(int inst)
[code] static int __init vivi_create_instance(int inst) { struct video_device * vfd; ...... //动态分配了一个video_device,这是一个核心的结构体 vfd = video_device_alloc(); if(!vfd){ goto unreg_dev; } /**这里vfd被设置为vivi_template了, 在后面的代码中会把这个vfd根据次设备号放入到video_device[]中, 那么这个数组中存放的都是vivi_template了, 在其他函数依据次设备号从这个数组中获取vide_device,获取的就是vivi_template */ *vfd = vivi_templaate; /**注册video_device, VFL_TYPE_GRABBER:会根据这个类型,来选择设备的名字和次设备号 node_nr 值为-1,表示第一个可用的数字,比如/dev/video0 /dev/video1 那么接下来的这个设备就是video2了,下面详细讲解 */ ret = video_register_device(vfd,VFL_TYPE_GRABBER,node_nr); }
注册video_device :video_register_device()
[code]int video_register_device(struct video_device *vdev, int type, int nr) { //调用这个函数来注册video_device return __video_register_device(vdev, type, nr, 1); } static int __video_register_device() { .... vdev->minor = -1; //次设备号被设置为-1,表示这个video_device还没有被注册过 WARN_ON(!vdev->release){ if(!vdev->release){ //如果要注册的video_device没有提供release函数,就会报错。 return -EINVAL; } } //根据传入的类型,来选择设备的名字,传入的类型是VFL_TYPE_GRABBER switch (type) { case VFL_TYPE_GRABBER: name_base = "video"; break; case VFL_TYPE_VTX: name_base = "vtx"; break; case VFL_TYPE_VBI: name_base = "vbi"; break; case VFL_TYPE_RADIO: name_base = "radio"; break; default: printk(KERN_ERR "%s called with unknown type: %d\n", __func__, type); return -EINVAL; } ..... vdev->cdev = cdev_alloc(); //动态分配cdev if(vdev->cdev == NULL){ return -ENOMEM; goto cleanup; } /** cdev的file_operations被设置为了v4l2_fops 应用程序调用open、read、ioctl....系统调用时,v4l2_fops中对应的函数会被调用 */ vdev->cdev->ops = &v4l2_fops; vdev->cdev->owner = owner; ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);//添加到内核 ..... //任何一个设备的注册都要经过这个函数,注册过程请见另一篇博文 ret = device_register(&vdev->dev); //注册这个设备 .... mutex_lock(&videodev_lock); //获取互斥锁 /** 依据次设备号位下标,将video_device(这里就是vivi_template)放入到video_device中, 以后在其他函数中依据次设备号从这个数组中获取的都是vivi_tempalte */ video_device[vdev->minor] = vdev; mutex_unlock(&videodev_lock); //解锁 }
vivi_template
根据上面的分析,vivi_template在入口函数中就已经被放入到了video_device[]中了,以后从video_device[]中获取到的就是vivi_template,看看这个结构体张什么样
[code] static struct video_device vivi_template = { .name = "vivi", .fops = &vivi_fops, //file_operations,为vfs提供调用接口 //查询设备性能、设置、获取、列:举数据格式、制式、缓冲区、启动摄像头.....涉及到整个数据的获取过程 .ioctl_ops = &vivi_ioctl_ops, .release = video_device_release, //用于一些制式的操作。对于摄像头驱动,不是必需的 .tvnorms = V4L2_STD_525_60, .current_norm = V4L2_STD_NTSC_M, };
通用的file_operations : v4l2_fops
[code]/** 一下定义的这些函数,对应与应用程序调用open、ioclt系统调用 看我们要讨论的unlocked_ioctl ,它对应与应用程序中的ioctl() */ static const struct file_operations v4l2_fops = { .owner = THIS_MODULE, .read = v4l2_read, .write = v4l2_write, .open = v4l2_open, .get_unmapped_area = v4l2_get_unmapped_area, .mmap = v4l2_mmap, .unlocked_ioctl = v4l2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = v4l2_compat_ioctl32, #endif .release = v4l2_release, .poll = v4l2_poll, .llseek = no_llseek, };
v4l2_ioctl
当应用程序调用ioctl的时候,v4l2_fops 结构中定义的v4l2_ioctl函数会被调用[code] static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { /**根据次设备号位下标,从video_device[]数组中取出video_device, 这里取出来的是vivi_tempalte */ struct video_device *vdev = video_devdata(filp); /** 如果vivi_template的v4l2_file_operations中定义了unlocked_ioctl 就调用这个unlocked_ioctl */ if (vdev->fops->unlocked_ioctl) { if (vdev->lock && mutex_lock_interruptible(vdev->lock)) return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); }
vivi_template 中的fops
[code] static const struct v4l2_file_operations vivi_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vivi_close, .read = vivi_read, .poll = vivi_poll, /** 经过上面的分析,当应用程序调用ioctl的时候 这个函数会被调用 */ .unlocked_ioctl = video_ioctl2, .mmap = vivi_mmap, };
video_ioctl2
[code]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
[code]static long __video_do_ioctl(struct file *file,unsigned int cmd, void *arg) { //依据次设备号位下标,从video_device[]数组中取出来vivi_tempalte struct video_device *vfd = video_devdata(file); //获取vivi_tempalte的ioctl_ops const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; ...... 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; } }
经过以上分析,可以看出当应用程序调用ioctl的时候,首先调用通用框架v4l2_fops中的ioctl,
在v4l2_fops中的ioctl是v4l2_ioctl,在v4l2_ioctl中,会调用具体设备(这里是vivi_template)
file_operation中定义的unlocked_ioctl,
在vivi_template中的unlocked_ioctl是video_ioctl2,这个video_ioctl2会根据命令来调用vivi_template
中定义的ioctl_ops中定义的函数
相关文章推荐
- 上一个的后续,想想还是做个记录。
- android 百分比布局(percentLayout),妈妈再也不用担心适配问题了
- OCP-V13-681
- asp.net 一般处理程序session 为 null
- android 事件总线 -- Otto(一)
- 移动端APP产品设计需要考虑哪些因素?
- EXPLAIN 关键字可以 查看 sql执行 的详细过程
- 修改Linux时间一般涉及到3个命令: date, clock, hwclock
- spark小技巧-mapPartitions
- spark小技巧-mapPartitions
- spark小技巧-mapPartitions
- android开发步步为营之77:android数据库ORM之greenDAO
- js中||和&&短路原理,精简代码方法
- spark小技巧-mapPartitions
- 使用vector出现的错误 subscript out of range
- 新浪面试题 快速排序非递归实现
- EXPLAIN 关键字可以 查看 sql执行 的详细过程
- 学习一样新东西行而有效的方法 学习捷径 一项由10个步骤组成的学习方法
- CruiseControl.Net来进行持续化集成
- Android-在线查看源码