NXP

3.3 应用程序中函数调用的底层执行流程

2019-07-12 13:27发布

3.1节分析的probe函数中,它的核心函数video_register_devicepart3中(v4l2-core/v4l2-dev.c文件),通过vdev->cdev->ops= &v4l2_fops;将字符设备的结构体cdevfile_operations函数集指向了v4l2_fops,如下所示: 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, };
open函数和ioctl函数为例来分析这个底层的调用过程: 当应用程序调用open函数的时候,就会调用这个v4l2_open函数,如下所示: static int v4l2_open(struct inode *inode, struct file *filp) { struct video_device *vdev; int ret = 0; /* Check if the video device is available */ mutex_lock(&videodev_lock); vdev = video_devdata(filp); /* return ENODEV if the video device has already been removed. */ if (vdev == NULL || !video_is_registered(vdev)) { mutex_unlock(&videodev_lock); return -ENODEV; } /* and increase the device refcount */ video_get(vdev); mutex_unlock(&videodev_lock); if (vdev->fops->open) { if (video_is_registered(vdev)) ret = vdev->fops->open(filp); else ret = -ENODEV; } if (vdev->debug) printk(KERN_DEBUG "%s: open (%d) ", video_device_node_name(vdev), ret); /* decrease the refcount in case of an error */ if (ret) video_put(vdev); return ret; } 看这个函数,它经过一系列的判断和操作,最终通过我标红那一句,调用到video_device结构体里面fops函数集的open函数。(以上这些分析是v4l2-dev.c中的) 体现在mxc_v4l2_capture.c中就是:在init_camera_struct函数中,通过*(cam->video_dev)= mxc_v4l_template;这一句话,将video_device指向了mxc_v4l_template,所以应用程序调用open函数,最终就会依次调用mxc_v4l_template->fops->open,即 mxc_v4l_template--->mxc_v4l_fops--->mxc_v4l_open 上面分析的是应用程序如果调用open函数的话,底层函数的执行流程,最终就会执行到我们mxc_v4l2_capture.c中的mxc_v4l_open函数。
同样对于ioctl函数来说,比如应用程序调用了一个ioctl函数,作为一个字符设备,肯定会调用到v4l2_fops结构体中的v4l2_ioctl函数,ret= vdev->fops->ioctl(filp, cmd, arg); 最终在mxc_v4l2_capture.c中会依次调用mxc_v4l_template--->mxc_v4l_fops--->mxc_v4l_ioctl
mxc_v4l_ioctl函数如下所示 static long mxc_v4l_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { pr_debug("In MVC:mxc_v4l_ioctl "); return video_usercopy(file, cmd, arg, mxc_v4l_do_ioctl); } 它通过video_usercopy函数,这个video_usercopy函数会进行一些检查及错误分析,最终会调用到mxc_v4l_do_ioctl函数,在mxc_v4l_do_ioctl函数中会根据不同的宏,通过一个switch语句来分别执行不同的过程。