九鼎创展论坛中文版English
登录 | 立即注册 设为首页收藏本站 切换到宽版
查看: 3624|回复: 1
打印 上一主题 下一主题

V4L2 soc-camera 分析 - 调用关系

[复制链接]
跳转到指定楼层
楼主
发表于 2014-7-10 09:25:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
应用层通过设备节点/dev/videoX打开video4linux devices。/dev/videoX是一个字符设备,主设备号81,次设备号: (0~63)分配给capture设备,64~127分配给radio设备,223~255分配给VBI设备,128~191分配给其他类型的。
如果驱动要注册一个video4linux设备,那么需要调用video_register_device函数。


利用dump_stack函数,可以方便的获取内核函数调用关系。


open调用关系
从调用关系角度来看,open是最复杂的,因为它不仅要执行真正的打开操作,还需要为mmap ioctl设置操作函数。

1. Application 通过open打开设备节点/dev/videoX
2. 进入系统调用sys_open,sys_open调用do_sys_open

3. do_sys_open 调用 do_flip_open

4. do_filp_open 这个函数比较长,大部分都是路径查找相关的代码,这里只需要关注do_last
5. do_last 大部分是路径相关的代码,只需关注finish_open
6. finish_open 调用这个函数时,已经填充好了路径名对应的nameidata结构,调用nameidata_to_flip
7. nameidata_to_flip 调用__dentry_open
8.  __dentry_open会调用chrdev_open,在__dentry_open中有如下代码片段
[cpp] view plaincopy

  •     f->f_op = fops_get(inode->i_fop);  
  •     .....  
  •     if (!open && f->f_op)  
  •         open = f->f_op->open;  
  •     if (open) {  
  •         error = open(inode, f);  
  •         if (error)  
  •             goto cleanup_all;  
  •     }  

当系统进行路径lookup过程中,会把这个设备文件对应的inode读入到内存中,在读取文件inode的过程中,判断这个inode是下列类型中的哪一个:regualr,char,block,pipe。此时,会根据inode类型的不同,赋给inode->i_fop不同的操作函数
在当前的case,shmem_get_inode会调用init_special_inode初始化这个inode,由于/dev/videoX是字符设备,所以inode->i_fop = &def_chr_fops。def_chr_fops.open = chrdev_open

9. chrdev_open 根据设备节点的主次设备好在系统内查找对应的cdev对象,把cdev->ops赋给filp->f_op(这个赋值操作是很重要的步骤,它把filp和具体设备的操作函数联系到一起),当前的case,cdev->ops是v4l2_ops。调用filp->f_op->open就完成了打开操作,flip->f_op->open则是v4l2_open。

10. v4l2_open 中调用vdev->fops->open,对于soc camera来说,我们在调用video_register_device之前,已经把vdev->fops设置为soc_camera_fops。vdev->fops->open也就是调用soc_camera_open

11. 绕了很大一圈,终于调用了soc_camera_open。

mmap调用关系

1. 系统调用mmap_pgoff,mmap_pgoff调用do_mmap_pgoff

2. do_mmap_pgoff,调用mmap_region
3. mmap_region 调用filp->f_op->mmap,在第一次打开文件时,open操作设置了file->f_op为v4l2_ops,file->f_op->mmap则是v4l2_mmap

4. v4l2_mmap,v4l2_mmap调用vdev->fops->mmap,对于soc_camera来说,vdev->fops是soc_camera_ops,所以vdev->fops->mmap是soc_camera_mmap

5. soc_camera_mmap


ioctl调用关系

1. 系统调用ioctl,调用do_vfs_ioctl
2. do_vfs_ioctl ,调用vfs_ioctl

3. vfs_ioctl 代码片段
[cpp] view plaincopy

  • if (filp->f_op->unlocked_ioctl) {  
  •     error = filp->f_op->unlocked_ioctl(filp, cmd, arg);  
  •     if (error == -ENOIOCTLCMD)  
  •         error = -EINVAL;  
  •     goto out;  
  • } else if (filp->f_op->ioctl) {  
  •     lock_kernel();  
  •     error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,  
  •                   filp, cmd, arg);  
  •     unlock_kernel();  
  • }  

在第一次打开文件时,已经设置了filp->f_op为v4l2_ops。注意不同内核版本中v4l2_ops实现是不同的,可能定义了ioctl,也可能定义了unlocked_ioctl。我的kernel v4l2_ops定义如下
[cpp] view plaincopy

  • static const struct file_operations v4l2_fops = {  
  •     .owner = THIS_MODULE,  
  •     .read = v4l2_read,  
  •     .write = v4l2_write,  
  •     .open = v4l2_open,  
  •     .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,  
  • };  

因此filep->f_op_unlocked_ioctl是v4l2_ioctl

5. v4l2_ioctl 代码片段如下
[cpp] view plaincopy

  • 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);  
  •     if (vdev->lock)  
  •         mutex_unlock(vdev->lock);  

soc_camera_fops.unlocked_ioctl = video_ioctl2
6. video_ioctl2 调用__video_do_ioctl
7. __video_do_ioctl,这个函数对参数做一些基本的判断,然后调用video_device的ioctl_ops,对于soc_camera系统来说,是soc_camera_ioctl_ops
8 soc_camera_ioctl_ops实现如下
[cpp] view plaincopy

  • static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {  
  •     .vidioc_querycap     = soc_camera_querycap,  
  •     .vidioc_g_fmt_vid_cap    = soc_camera_g_fmt_vid_cap,  
  •     .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,  
  •     .vidioc_s_fmt_vid_cap    = soc_camera_s_fmt_vid_cap,  
  •     .vidioc_enum_input   = soc_camera_enum_input,  
  •     .vidioc_g_input      = soc_camera_g_input,  
  •     .vidioc_s_input      = soc_camera_s_input,  
  •     .vidioc_s_std        = soc_camera_s_std,  
  •     .vidioc_reqbufs      = soc_camera_reqbufs,  
  •     .vidioc_try_fmt_vid_cap  = soc_camera_try_fmt_vid_cap,  
  •     .vidioc_querybuf     = soc_camera_querybuf,  
  •     .vidioc_qbuf         = soc_camera_qbuf,  
  •     .vidioc_dqbuf        = soc_camera_dqbuf,  
  •     .vidioc_streamon     = soc_camera_streamon,  
  •     .vidioc_streamoff    = soc_camera_streamoff,  
  •     .vidioc_queryctrl    = soc_camera_queryctrl,  
  •     .vidioc_g_ctrl       = soc_camera_g_ctrl,  
  •     .vidioc_s_ctrl       = soc_camera_s_ctrl,  
  •     .vidioc_cropcap      = soc_camera_cropcap,  
  •     .vidioc_g_crop       = soc_camera_g_crop,  
  •     .vidioc_s_crop       = soc_camera_s_crop,  
  •     .vidioc_g_parm       = soc_camera_g_parm,  
  •     .vidioc_s_parm       = soc_camera_s_parm,  
  •     .vidioc_g_chip_ident     = soc_camera_g_chip_ident,  
  • #ifdef CONFIG_VIDEO_ADV_DEBUG  
  •     .vidioc_g_register   = soc_camera_g_register,  
  •     .vidioc_s_register   = soc_camera_s_register,  
  • #endif  
  • };  



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳市九鼎创展科技官方论坛 ( 粤ICP备11028681号-2  

GMT+8, 2024-11-23 10:49 , Processed in 0.018090 second(s), 18 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表