vin core驱动入口

vin core驱动由vin驱动调用被注册到系统中:(vin.c vin_init())

这里调用vin_core.c:

Probe方法

根据DST配置信息,系统共有8个vinc设备,分别是vinc0vinc7,DST中使能了vinc0vinc5。驱动和设备匹配后将运行probe方法:

static int vin_core_probe(struct platform_device *pdev)
{//1、从DST中获取信息填充vinc结构体//2、分配DMA内存//3、中断请求//4、初始化capture这个v4l2子设备ret = vin_initialize_capture_subdev(vinc);
}


参考《nvp6134驱动》的解释,这个函数首先调用了v4l2_subdev_init()初始化v4l2_subdev结构体变量sd,然后调用median_entity_init()初始化了一个名字叫"vin_cap.0"之类的entity,最后将vinc结构体设置为subdev的私有数据。与nvp6134驱动不同的是,这里注册的entity是具有sink pad和source pad的,即它前面有entity,后面也有entity,而nvp6134的只有source pad,即它前面没有entity。
另外,这个函数最后设置了两个ops。其中“vin_capture_sd_internal_ops”很重要。下文会详解。

这里有两个疑问:

  1. 这个“vin_cap.0”子设备如何挂载到“sunxi-vin”的v4l2总设备上?
  2. 这个entity的下一个entity是什么?

回答问题1:
上面vin_initialize_capture_subdev()函数中初始化的subdev实际是vinc–>vid_cap.subdev。
在vin.c vin_probe()–>vin_md_register_entities()方法调用sunxi_vin_core_get_dev()获得vinc并保存到vind–>vinc[]数组中,而sunxi_vin_core_get_dev()实则返回全局数组变量vin_core_gbl[]中指定的成员(vin_core_gbl[]在probe被初始化):

在前面调用vin_core_probe()时会把每个vinc的信息保存到全局变量vin_core_gb1,此时sunxi_vin_core_get_dev()将逐个获取vin_core,然后调用vin_md_register_core_entity()注册到V4l2_device:

注:vin_pipe_ops是结构体vin_pipeline_ops变量,很重要,后续分析。
通过vin_md_register_core_entity()–>v4l2_device_register_subdev()将“vin_cap.0”子设备注册到“sunxi-vin”。
这样构成一下的层次关系:

回答问题2:
下一个entity就是一个video device,看接下来的分析。

初始化video device

在本文上面提到的vin_core_probe()–>vin_initialize_capture_subdev()函数最后有:


vin_capture_sd_internal_ops是v4l2_subdev_internal_ops结构体变量,根据v4l2_subdev_internal_ops结构体的注释,当subdev被注册时registered函数被调用,被调用时vin_capture_subdev_registered()的参数将被设置为v4l2_subdev对象的指针,对于vin驱动来说,就是上面注册的子设备vinc–>vid_cap.subdev。
注册时会回调registered 函数,即vin_capture_subdev_registered()。

涉及v4l2_ctrl,暂时不分析。vin_init_video()是个重要函数,其创建/dev/video%d设备给应用程序使用,即应用程序可以通过她open\ioctl\close,获得Camera视频数据。在《T7 v4l2 videobuf 2.docx》中有简单介绍这个函数如何对videobuf和vb2_queue初始化。而应用程序如何通过Ioctl调到vin_ioctl_ops[]的过程可参考《V4L2框架-control.docx》。
vin_init_video()前面代码如下:

1.介绍一下video_device结构体

video_device 可以动态的分配:

struct video_device *vdev = video_device_alloc();
if (vdev == NULL)return -ENOMEM;
vdev->release = video_device_release;

如果需要将 video_device 结构体嵌入到更大的结构体里面的话,就需要设置 vdev 的 release 成员。内核提供了两个默认的 release回调函数,如下:

video_device_release()       // 仅仅调用kfree释放分配的内存,用于动态分配情况下
video_device_release_empty() // 不做任何事情,静态变量

以下的函数成员需要被设置:

  • v4l2_dev:必须指向v4l2_device父设备
  • vfl_dir:VFL_DIR_RX(capture设备)、VFL_DIR_TX(输出设备)、VFL_DIR_M2M(codec设备)
  • fops:设置v4l2_file_operations结构体
  • ioctl_ops:ioctls,可以通过设备节点被用户空间程序访问,需设置fops的.unlocked_ioctl指向video_ioctl2
  • lock:如果想要在驱动空间里做锁操作,可以设置为NULL。否则需要指向一个已经初始化的mutex_lock结构体
  • queue:指向一个vb2_queue结构体,如果queue->lock不为空,那么与队列相关的ioctls就会使用queue内部的锁,这样的话就不用等待其它类型的ioctls操作
  • prio:对优先级进行跟踪,用在VIDIOC_G/S_PRIORITY上,如果为空的话就会使用v4l2_device里面的v4l2_prio_state
  • dev_parent:指向v4l2_device即可

2.video_device 的注册

video_device 的注册函数如下:

    ret = video_register_device(&cap->vdev, VFL_TYPE_GRABBER, cap->vinc->id);

该代码会注册一个字符设备驱动程序并在用户空间生成一个设备节点。如果 v4l2_device 父设备的 mdev 成员不为空的话,video_device 的 entity 会被自动的注册到 media framework 里面。函数最后一个参数是设备节点索引号,如果是 -1 的话就取用第一个内核中可用的索引号值。注册的设备类型以及用户空间中的节点名称取决于以下标识:

    VFL_TYPE_GRABBER: videoX 输入输出设备VFL_TYPE_VBI: vbiX VFL_TYPE_RADIO: radioX 硬件定义的音频调谐设备VFL_TYPE_SDR: swradioX 软件定义的音频调谐设备

所以,对于vin core驱动来说,生成了类似/dev/videoXX的节点,其中XX是第三个参数的值。
当一个设备节点被创建时,相关属性也会被创建,可以在 /sys/class/video4linux 里面看到这些设备文件夹,在文件夹里面可以看到 ‘name’,‘debug’,'index’等属性,可以使用 cat 命令查看。’ debug’ 可以用于 video 设备调试,每个 video 设备都会创建一个 ‘debug’ 属性,该属性以文件夹的形式存在与 /sys/class/video4linux// 下面以供使能 log file operation。’ debug’是一个位掩码,以下位可以被设置:

    0x01:记录ioctl名字与错误码。设置0x08位可以只记录VIDIOC_(D)QBUF0x02:记录ioctl的参数与错误码。设置0x08位可以只记录VIDIOC_(D)QBUF0x04:记录file ops操作。设置0x08位可以只记录read&write成员的操作0x08:如上所示0x10:记录poll操作

当以上的位被设置的时候,发生相关的调用或者操作的时候内核就会打印出来相关的调用信息到终端上面。

3.video设备的清理

当 video 设备节点需要被移除或者USB设备断开时,需要执行以下函数:

    video_unregister_device(vdev);

来进行设备的卸载,该函数会移除 /dev 下的设备节点文件,同时不要忘记调用 media_entity_cleanup 来清理 entity。

4.其他

如果要集成到 media_framework 里面,就需要设置 video_device 里面的 media_entity 成员,同时需要提供 media_pad,例如vin_init_video()下部分有:

cap->vd_pad只有MEDIA_PAD_FL_SINK,没有MEDIA_PAD_FL_SOURCE,即它只接受收据,所以它将是vin驱动中整个media link的终点——最后一个Media Entity。
但是,从打印信息来看,8个vinc设备却只有4次调用vin_capture_subdev_registered(),为什么?


在调用vin_md_register_core_entity()有个判断(15行到18行代码),即但valid_idx无效时直接跳过,根据代码或下面打印信息提示:

只有sensor 0是有效的,所以在DST中,这是rear_sensor为<0x0>的才能调用vin_md_register_core_entity(),也就是这样vinc0~vinc3能通过,这难道对应4路摄像头?。(答案是肯定的)

vin_init_video()其他代码是关于video buffer的,这里不分析,可以参考《V4L2框架-videobuf2》。

vin驱动的Ioctl入口

这一段解释为什么应用程序的IOCTL调用会转到vin_ioctl_ops结构体所指定的函数。
下面摘自《V4L2驱动框架简单分析.docx》,先简单说明ioctl框架:

=====================》
你可能观察到用户空间对V4L2设备的操作基本都是ioctl来实现的,V4L2设备都有大量可操作的功能(配置寄存器),所以V4L2的ioctl也是十分庞大的。它是一个怎样的框架,是怎么实现的呢?
Ioctl框架是由v4l2_ioctl.c文件实现,文件中定义结构体数组v4l2_ioctls,可以看做是ioctl指令和回调函数的关系表。用户空间调用系统调用ioctl,传递下来ioctl指令,然后通过查找此关系表找到对应回调函数。
以下是截取数组的两项:

IOCTL_INFO_FNC(VIDIOC_QUERYBUF, v4l_querybuf,v4l_print_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_buffer, length)),
IOCTL_INFO_STD(VIDIOC_G_FBUF, vidioc_g_fbuf,v4l_print_framebuffer, 0),

内核提供两个宏(IOCTL_INFO_FNC和IOCTL_INFO_STD)来初始化结构体,参数依次是ioctl指令、回调函数或者v4l2_ioctl_ops结构体成员、debug函数、flag。如果回调函数是v4l2_ioctl_ops结构体成员,则使用IOCTL_INFO_STD;如果回调函数是v4l2_ioctl.c自己实现的,则使用IOCTL_INFO_FNC。
IOCTL调用的流程图如下:

用户空间通过打开/dev/目录下的设备节点,获取到文件的file结构体,通过系统调用ioctl把cmd和arg传入到内核。通过一系列的调用后最终会调用到__video_do_ioctl函数,然后通过cmd检索v4l2_ioctls[],判断是INFO_FL_STD还是INFO_FL_FUNC。如果是INFO_FL_STD会直接调用到视频设备驱动中video_device->v4l2_ioctl_ops函数集。如果是INFO_FL_FUNC会先调用到v4l2自己实现的标准回调函数,然后根据arg再调用到video_device->v4l2_ioctl_ops或v4l2_fh->v4l2_ctrl_handler函数集。

《===============================
部分IOCTL最终会调用到vin_ioctl_ops里面的函数:

ioctls 与 locking

V4L 核心层提供了可选的锁服务,最主要的就是 video_device 里面的锁,用来进行 ioctls 的同步。如果使用了 videobuf2 框架,那么 video_device->queue->lock 锁也会被用来做 queue 相关的 ioctls 同步。使用不同的锁有很多优点,比如一些设置相关的 ioctls 花费的时间比较长,如果使用独立的锁,VIDIOC_DQBUF就不用等待设置操作的完成就可以执行,这个在网络摄像机驱动中很常见。当然,也可以完全由驱动本身去完成锁操作,这时可以设置所有的锁成员为NULL并实现一个驱动自己的锁。
vin core驱动里面,cap->vdev.lock和q->lock的锁使用同一个的,所以在启动流传输后,应用程序尽量不要再操作ioctls。
如果使用旧的 videobuf,需要将 video_device 的锁传递给 videobuf queue 初始化函数,如果 videobuf 正在等待一帧数据的到达,此时会将锁暂时释放,等数据到达之后再次加锁,否则别的处理程序就无法访问。所以不推荐使用旧的 videobuf。如果是在 videobuf2 框架下,需要实现 wait_prepare 与 wait_finish 回调函数去释放或者获取锁,如果使用了 queue->lock,可以使用 V4L2 提供的回调 vb2_ops_wait_prepare/finish 帮助函数来完成加锁与解锁的操作,它们会使用 queue->lock这个锁(此时一定要将该锁初始化)。

vin core驱动在vin.c中的相关代码

最后再提一提vin_pipeline_ops结构体:

应用程序调用VIDIOC_S_INPUT时,最终调用到vin_video.c的vidioc_s_input()–>__vin_pipeline_open(&cap->pipe, &cap->vdev.entity, true)。

static int __vin_pipeline_open(struct vin_pipeline *p,struct media_entity *me, bool prepare)
{struct vin_md *vind;struct v4l2_subdev *sd;struct sensor_item sensor;int ret;if (prepare)vin_md_prepare_pipeline(p, me);sd = p->sd[VIN_IND_SENSOR];if (sd == NULL)return -EINVAL;ret = vin_pipeline_s_power(p, 1);if (!ret)return 0;return ret;
}

首先调用vin_md_prepare_pipeline(),如果应用程序操作的是/dev/video0节点,则打印信息如下:

[VIN_LOG_MD]vin_md_prepare_pipeline entity is vin_cap.0, group id is 0x2000
[VIN_LOG_MD]vin_md_prepare_pipeline entity is sunxi_scaler.0, group id is 0x1000
[VIN_LOG_MD]vin_md_prepare_pipeline entity is sunxi_isp.0, group id is 0x800
[VIN_LOG_MD]vin_md_prepare_pipeline entity is sunxi_csi.2, group id is 0x400
[VIN_LOG_MD]vin_md_prepare_pipeline entity is nvp6134, group id is 0x100

运行目的就是将pipe涉及到的Sensor、CSI、ISP、Scaler、vin_cap这些subdev保存到cap->pipe->sd[],方便管理。
函数接下来调用vin_pipeline_s_power()启动各个子模块的电源,分别调用了子模块中v4l2_subdev_core_ops结构体定义的s_power所指函数,看了代码,除nvp6134的sensor_power()有比较重要的设置,其他模块都很简单。

__vin_pipeline_s_stream()参考《nvp6134驱动》

全志T7 vin core驱动相关推荐

  1. 全志T7 vin驱动入口

    vin驱动入口 vin驱动代码主要在drivers\media\platform\sunxi-vin\vin.c,该文件里面的所有函数几乎用static修饰,即只能被本驱动模块内部使用.分析vin驱动 ...

  2. 全志T7 Display驱动分析

    本文档在<全志T7 Display驱动简介.docx>基础上进行补充说明,主要的目的是想了解系统总共有多少个图像层可以给应用程序使用,好让以后应用程序如何同叠加图像层来高效显示画面. DS ...

  3. mysql .net core_MySQL官方.NET Core驱动已出,支持EF Core

    千呼万唤始出来MySQL官方.NET Core驱动已出,支持EF Core. 昨天MySQL官方已经发布了.NET Core 驱动,目前还是预览版,不过功能已经可用. NuGet 地址:https:/ ...

  4. 全志T7 Display驱动简介

    可先阅读<Sunxi_display2模块使用文档.pdf>.<图形开发用户指南.pdf> DE:Display Engine Write-Back:capture data ...

  5. 全志T7 nvp6134驱动

    文件结构 nvp6134c.c nvp6134驱动入口.与T7 sensor_helper.c结合完成v4l2驱动的注册等. csi_dev_nvp6134.c nvp6134芯片寄存器初始化 vid ...

  6. 基于全志A64平台v4l2驱动分析

    纪念再一次使用这里,刚好开通好博客,写下近年来的第一篇. 最近要做一个全志A64平台的vfe驱动培训,组织了下v4l2与vfe驱动分析.这里记录下. 全志A64芯片csi部份不自带isp(其实是有带一 ...

  7. 全志T7/T507 Qt5.12.5移植记录

    1.概述 Qt5.12.5移植过程中遇到一些坑,特意记录下来. 主要包括编译.运行.环境配置三个部分. 2.编译配置 2.1.配置脚本 新建setenvs512.sh脚本,设置编译环境和选项,放入Qt ...

  8. 全志t3linux驱动_全志T3 Linux显示驱动分析

    1.总体架构 全志T3处理器的显示框架是基于标准Linux的帧缓冲架构,其结构如图 1.1所示.显示控制器DE的驱动架构如图 1.2所示,包括屏蔽差异的显示管理抽象层,以及显示图层驱动.显示设备驱动. ...

  9. 全志T3 Linux显示驱动分析

    1.总体架构 全志T3处理器的显示框架是基于标准Linux的帧缓冲架构,其结构如图 1.1所示.显示控制器DE的驱动架构如图 1.2所示,包括屏蔽差异的显示管理抽象层,以及显示图层驱动.显示设备驱动. ...

最新文章

  1. 线程 、进程、协程 三者区别
  2. 汇编语言学习笔记-按指定的字体输出文本
  3. 计算机网络知识简单介绍
  4. 【Java从0到架构师】JDBC、Spring JDBC、JUnit
  5. 中国铁塔行业市场企业投资及运营策略分析报告2022-2028年版
  6. 构建词表与抽样——【torch学习笔记】
  7. java 关键字小结
  8. ANSYS 15 直接优化分析
  9. python 百度ai 牌照识别_Python用百度AI实现文字识别功能!(银行卡,营业执照,等识别)...
  10. 移动通信-抗衰落技术
  11. Kubernetes实践:使用k8s部署微服务应用
  12. python制作七夕礼物_OpenCV+Python制作程序七夕(情人节)礼物
  13. 解释器模式计算机Demo
  14. C++::namespace
  15. 原来PWM这么简单!通过锯齿波作为载波和调制波经过比较,产生相应的PWM输出波形
  16. android收集备忘录恢复工具,安卓手机备忘录删除了怎么恢复?仅有一种方法可以恢复!...
  17. decode和encode 区别
  18. mybatis整合sqlite
  19. Nexus 3.31.1 maven 私服 服务器配置篇 linux
  20. 快速阅读——《认知篇》

热门文章

  1. 2019年全国一二线城市程序员工资大调查,快来看看你有没有拖后腿!
  2. 100坚持行动反思篇---清明节有感
  3. Devc++软件下载后双击软件打不开问题
  4. 用递归求i的平方,再求和
  5. JAVA智慧公寓系统演示录屏2021计算机毕业设计Mybatis+系统+数据库+调试部署
  6. 23考研截至目前,计算机/软件等专业调剂信息集合!
  7. 软件测试之接口测试总结
  8. ol4鼠标移动事件,将鼠标位置px转换为地图坐标
  9. 前端css动画_很棒的前端资源和CSS动画课程
  10. 记第一款游戏《大炮小兵》发布