Linux v4l2架构学习总链接

rv1126 架构如下

前面分析subdev的时候,是从imx291开始的,这里分析media部件,换个方向,从rkcif_mipi开始

这里有一部分内容需要去看subdev的分析

rkcif_mipi对于media的操作有2个地方

第一处就是注册video的时候

video_register_device()-> video_register_media_controller()

static int video_register_media_controller(struct video_device *vdev)
{
#if defined(CONFIG_MEDIA_CONTROLLER)u32 intf_type;int ret;/* Memory-to-memory devices are more complex and use* their own function to register its mc entities.*/if (!vdev->v4l2_dev->mdev || vdev->vfl_dir == VFL_DIR_M2M)return 0;/** vdev->entity 可以认为就是rkcif_mipi的entity* obj_type表示当前entity的类型* 对于video 就是 MEDIA_ENTITY_TYPE_VIDEO_DEVICE* 对于subdev 则是 MEDIA_ENTITY_TYPE_V4L2_SUBDEV* function的值* 对于video - VFL_TYPE_GRABBER*     值为 MEDIA_ENT_F_IO_V4L* 对于subdev,就需要看情况而定,驱动自己设置*     比如subdev是个sensor,则值为MEDIA_ENT_F_CAM_SENSOR*     比如subdev是个flash,则值为MEDIA_ENT_F_FLASH*     比如subdev是个连接部件,则值为MEDA_ENT_F_VID_IF_BRIDGE*     比如...*/vdev->entity.obj_type = MEDIA_ENTITY_TYPE_VIDEO_DEVICE;vdev->entity.function = MEDIA_ENT_F_UNKNOWN;switch (vdev->vfl_type) {case VFL_TYPE_GRABBER:intf_type = MEDIA_INTF_T_V4L_VIDEO;vdev->entity.function = MEDIA_ENT_F_IO_V4L;break;case VFL_TYPE_VBI:intf_type = MEDIA_INTF_T_V4L_VBI;vdev->entity.function = MEDIA_ENT_F_IO_VBI;break;case VFL_TYPE_SDR:intf_type = MEDIA_INTF_T_V4L_SWRADIO;vdev->entity.function = MEDIA_ENT_F_IO_SWRADIO;break;case VFL_TYPE_TOUCH:intf_type = MEDIA_INTF_T_V4L_TOUCH;vdev->entity.function = MEDIA_ENT_F_IO_V4L;break;case VFL_TYPE_RADIO:intf_type = MEDIA_INTF_T_V4L_RADIO;/** Radio doesn't have an entity at the V4L2 side to represent* radio input or output. Instead, the audio input/output goes* via either physical wires or ALSA.*/break;case VFL_TYPE_SUBDEV:intf_type = MEDIA_INTF_T_V4L_SUBDEV;/* Entity will be created via v4l2_device_register_subdev() */break;default:return 0;}if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN) {/** entity.name 赋值*/vdev->entity.name = vdev->name;/* Needed just for backward compatibility with legacy MC API *//** 这2句没看明白具体要做什么,后面遇到再说吧*/vdev->entity.info.dev.major = VIDEO_MAJOR;vdev->entity.info.dev.minor = vdev->minor;/** 可不可以认为这个函数的作用就是就entity注册到media中* 或者说entity关联到media中* 具体分析在下面*/ret = media_device_register_entity(vdev->v4l2_dev->mdev,&vdev->entity);if (ret < 0) {pr_warn("%s: media_device_register_entity failed\n",__func__);return ret;}}....
#endifreturn 0;
}

video_register_device()-> video_register_media_controller() -> media_device_register_entity()

int __must_check media_device_register_entity(struct media_device *mdev,struct media_entity *entity)
{struct media_entity_notify *notify, *next;unsigned int i;int ret;if (entity->function == MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN ||entity->function == MEDIA_ENT_F_UNKNOWN)dev_warn(mdev->dev,"Entity type for entity %s was not initialized!\n",entity->name);/* Warn if we apparently re-register an entity */WARN_ON(entity->graph_obj.mdev != NULL);/** entity通过graph_obj.medv关联到media* 初始化links个数为0* 其中links是所有的link数量包括前向和反向已经使能是失能的* backlinks记录的是反向的links数量* 那么正向的就是 links - backlinks ?*/entity->graph_obj.mdev = mdev;INIT_LIST_HEAD(&entity->links);entity->num_links = 0;entity->num_backlinks = 0;/** 这里是得到一个编号* internal_idx是entity内部唯一编号,这个编号*/ret = ida_alloc_min(&mdev->entity_internal_idx, 1, GFP_KERNEL);if (ret < 0)return ret;entity->internal_idx = ret;mutex_lock(&mdev->graph_mutex);/** media中记录已分配的最大编号*/mdev->entity_internal_idx_max =max(mdev->entity_internal_idx_max, entity->internal_idx);/* Initialize media_gobj embedded at the entity *//** 将media通过graph_obj挂载到medv->entities链表上* 详细看下面的分析*/media_gobj_create(mdev, MEDIA_GRAPH_ENTITY, &entity->graph_obj);/* Initialize objects at the pads *//** 根据当前这个情景分析,num_pads为0* 这里先不分析*/for (i = 0; i < entity->num_pads; i++)media_gobj_create(mdev, MEDIA_GRAPH_PAD,&entity->pads[i].graph_obj);/** 根据当前这个情景分析,medv->entity_notifier链表上为空* 这里先不分析*//* invoke entity_notify callbacks */list_for_each_entry_safe(notify, next, &mdev->entity_notify, list)notify->notify(entity, notify->notify_data);/** pm是电源相关的* 详细分析在下面*/if (mdev->entity_internal_idx_max>= mdev->pm_count_walk.ent_enum.idx_max) {struct media_graph new = { .top = 0 };/** Initialise the new graph walk before cleaning up* the old one in order not to spoil the graph walk* object of the media device if graph walk init fails.*/ret = media_graph_walk_init(&new, mdev);if (ret) {mutex_unlock(&mdev->graph_mutex);return ret;}/** 在media_graph_walk_init重新分配了一个空间,地址记录在new中* media_graph_walk_cleanup将之前申请的内存空间释放* 释放的原因是,之前的不够用了*/media_graph_walk_cleanup(&mdev->pm_count_walk);/** 更新新的pm_count_walk* 具体的用法后面遇到在分析*/mdev->pm_count_walk = new;}mutex_unlock(&mdev->graph_mutex);return 0;
}

video_register_device()-> video_register_media_controller() -> media_device_register_entity() -> media_gobj_create()

void media_gobj_create(struct media_device *mdev,enum media_gobj_type type,struct media_gobj *gobj)
{BUG_ON(!mdev);/** gobj是&entity->graph_obj* 对于gobj,都有一个自己的ID*/gobj->mdev = mdev;/* Create a per-type unique object ID */gobj->id = media_gobj_gen_id(type, ++mdev->id);/** 对于entity*    挂载到medv->entities链表上* 对于pad*    挂载到medv->pads链表上* 对于link*    挂载到medv->links链表上* 对于interface*    挂载到medv->interface链表上* * 对于整个media来说,应该会有很多的entity,pad,link* 都会被挂载到media的相关链表上*/switch (type) {case MEDIA_GRAPH_ENTITY:list_add_tail(&gobj->list, &mdev->entities);break;case MEDIA_GRAPH_PAD:list_add_tail(&gobj->list, &mdev->pads);break;case MEDIA_GRAPH_LINK:list_add_tail(&gobj->list, &mdev->links);break;case MEDIA_GRAPH_INTF_DEVNODE:list_add_tail(&gobj->list, &mdev->interfaces);break;}/** 用于存储图拓扑版本的单调计数器* 每次拓扑更改时都应增加* 拓扑到底是个什么东西呢?增加一个link也算改变拓扑???*/mdev->topology_version++;dev_dbg_obj(__func__, gobj);
}

video_register_device()-> video_register_media_controller() -> media_device_register_entity() -> media_gobj_walk_init()

__must_check int media_graph_walk_init(struct media_graph *graph, struct media_device *mdev)
{return media_entity_enum_init(&graph->ent_enum, mdev);
}static inline __must_check int media_entity_enum_init(struct media_entity_enum *ent_enum, struct media_device *mdev)
{return __media_entity_enum_init(ent_enum,mdev->entity_internal_idx_max + 1);
}__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,int idx_max)
{/** 加设idx_max值是1 * 64位系统的话,BITS_PER_LONG 为64* 那么ALIGN后 idx_max值就是64*/idx_max = ALIGN(idx_max, BITS_PER_LONG);/** idx_max/ BITS_PER_LONG 计算出有几个long的大小* ent_enum->bmap作用是什么???*/ent_enum->bmap = kcalloc(idx_max / BITS_PER_LONG, sizeof(long),GFP_KERNEL);if (!ent_enum->bmap)return -ENOMEM;bitmap_zero(ent_enum->bmap, idx_max);/** 记录idx_max的值*/ent_enum->idx_max = idx_max;return 0;
}

可以看到注册video节点的时候,调用了media_device_register_entity,会将对于的entity链接到media的entities链表,同时会初始化media的pm_count_walk,电源相关的东西

所以后面如果其他地方调用了media_device_register_entity,同样会做上面的事情。

第二部分对entity添加pad等部件

rkcif_register_stream_vdev()

static int rkcif_register_stream_vdev(struct rkcif_stream *stream,bool is_multi_input)
{...node->pad.flags = MEDIA_PAD_FL_SINK;ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);if (ret < 0)goto unreg;...
}

可以看到只有1个pad,且是一个sink pad

rkcif_register_stream_vdev() -> media_entity_pads_init()

int media_entity_pads_init(struct media_entity *entity, u16 num_pads,struct media_pad *pads)
{struct media_device *mdev = entity->graph_obj.mdev;unsigned int i;if (num_pads >= MEDIA_ENTITY_MAX_PADS)return -E2BIG;/** entity中记录pad个数及pad地址*/entity->num_pads = num_pads;entity->pads = pads;/** rkcif_mipi是有mdev的* 这也是为什么要从rkcif_mipi开始分析* 因为imx291 mipi-csi等是没有mdev的* 下面的部分代码就会执行不了*/if (mdev)mutex_lock(&mdev->graph_mutex);for (i = 0; i < num_pads; i++) {/** 初始化每个pad* 记录所属的entity,这样entity与pad就是你中有我我中有你了*/pads[i].entity = entity;pads[i].index = i;if (mdev)/** media_gobj_create之前分析过了* 主要做4件事* 1. pad通过graph_obj记录medv* 2. pad通过graph_obj获取自己的id* 3. pad链接到mdev->pads链表上* 4. medv->topology_version++*/media_gobj_create(mdev, MEDIA_GRAPH_PAD,&entity->pads[i].graph_obj);}if (mdev)mutex_unlock(&mdev->graph_mutex);return 0;
}

可以看到第二部分操作就是给entity添加一个pad,并将pad链接到media pads链表上。

当前的media相关操作就这些

看到这里会疑惑,这就完了?rkcif_mipi的entity和mipi csi的entity怎么连接的?

这里之所以不分析,是因为现在分析的会很突兀,有些不容易理解,后面会再次通过subdev注册的过程找到相关的代码。

画了一个示意图,主意rkcif_mipi会注册4个video节点,之前的分析只是分析一个。

基于RV1126平台imx291分析 --- media部件注册 rkcif_mipi相关推荐

  1. Android 基于bmob平台的手机登录验证码注册 等功能实现

    首先是基于Bmob 平台,采用MVP 开发模式.效果见图: 下面一 一给出源码: MVP 目录结构: 登录/注册的Activity: package com.example.yangzi.mvp_de ...

  2. 产品分享:Qt+Arm基于RV1126平台的内窥镜软硬整套解决方案(实时影像、冻结、拍照、录像、背光调整、硬件光源调整,其他产品也可使用该平台,如视频监控,物联网产品等等)

    ​若该文为原创文章,转载请注明原文出处 本文章博客地址:[https://hpzwl.blog.csdn.net/article/details/118887440 长期持续带来更多项目与技术分享,咨 ...

  3. linux内核usb驱动框架,基于S3C2440平台的linux2.6.22内核版本的USB驱动框架分析

    基于S3C2440平台的linux2.6.22内核版本的USB驱动框架分析 发布时间:2014-07-18 16:47:31来源:红联作者:linux08071151 driver/usb/host/ ...

  4. 基于边缘计算平台的分析与研究

    摘 要:边缘计算作为万物互联时代的关键技术,具有广泛的应用场景.文章首先分析了边缘计算平台在推广中面临的问题:随后从架构出发分析了典型边缘计算平台,并列举了边缘计算应用场景的需求参数,最后提出了一种边 ...

  5. android手机舆情分析,基于Android平台的环境公共舆情监督系统研究

    摘要: 近年来,随着我国社会经济的持续发展和人民生活水平的不断提高,人们的环境保护意识也在不断增长,其中城市环境质量问题逐渐成为了人们普遍关注的焦点,也成为环保部门和环保从业人员的重点研究方向.环境监 ...

  6. 基于 Thingsboard 平台自定义 RPC 控制类小部件示例

    基于 Thingsboard 平台自定义 RPC 控制类小部件示例 1. 小部件介绍 2. 创建小部件 3. 部件编辑器 3.1 简介 3.2 资源 / HTML / CSS 3.3 JavaScri ...

  7. 浅谈基于物联网技术的地下综合管廊智慧管控平台建设分析

    摘要:本文以物联网.GIS等技术为基础,采用文献研究等方法,在探究我国地下综合管廊管廊现状及相关技术飾基础上,对其智慧管控平台的建设展开了研究,希望能为相关研究及建设提供有价值的参考. 关键词:物联网 ...

  8. 基于SOA的区域卫生信息平台案例分析(转)

    这篇文章是在学习过程中baidud到得,觉得在学习阶段可以看看,用的是ESB做的系统集成. 以下是原文: 一.政策与现状 国务院在<关于深化医药卫生体制改革意见>中明确提出要大力推进医药卫 ...

  9. P2构型并联混合动力汽车Cruise整车仿真模型 基于Cruise平台搭建整车部件等动力学模型,基于MATLAB/Simulink平台完成整车控制策略的建模

    P2构型并联混合动力汽车Cruise整车仿真模型. 1.基于Cruise平台搭建整车部件等动力学模型,基于MATLAB/Simulink平台完成整车控制策略的建模,策略模型具备再生制动,最优制动力分配 ...

  10. 基于ALS的音乐分析及离线推荐系统的设计与实现报告

    文章目录 摘要 数据说明 相关技术介绍 Sqoop概述 Spark概述 协同过滤推荐算法概述 系统设计与实现 数据分析 热门推荐 个性化推荐 前台交互展示 总结 摘要 在互联网时代,各类的音乐网站提供 ...

最新文章

  1. 未来,机器人帮你盖房子
  2. oracle package lock,Oracle 11g下重现library cache lock等待事件
  3. LeetCode 1057. 校园自行车分配(map有序+贪心)
  4. 企业要想迅速壮大,不仅需要大量的人才
  5. C++ Error C2664:无法将参数 1 从“const char [9]”转换为“LPCWSTR”解决方案
  6. OCP考点实战演练02-日常维护篇
  7. html+css 登录界面
  8. win10本机计算机策略,[本地策略组怎么打开]win10本地组策略打开方法
  9. 2022-2028年中国氧化铝陶瓷基板行业竞争现状及投资决策建议报告
  10. NShape(开源矢量图形编辑器) 入门(一)
  11. 文字转化为二维码(数据加密)
  12. What do you think about this itinerary?
  13. AWS之Glue使用方法
  14. 正确写出doublecheck的单例模式
  15. 方向包围盒OBB(oriented bounding box)
  16. 题解 CF133A 【HQ9+】
  17. 对ResNet的理解
  18. NLG评估指标chrF、chrF++介绍
  19. 51单片机最小系统板制作过程
  20. 美通企业周刊 | 中国平安将深度参与深圳公共住房建设;北京环球度假区将引入IMAX影院...

热门文章

  1. Python代码缩进
  2. 7 个优秀 WordPress LMS 在线教育系统插件比较(优点和缺点)
  3. 谭浩强 c语言 swap,C语言谭浩强完整教案.ppt
  4. linux 执行sql loader,sql loader使用例子
  5. 小米蓝牙耳机驱动_硬核拆解——小米蓝牙耳机
  6. 火山软件开发访问网页查找电话号和读写文件应用
  7. kodi pvr 不能安装_Kodi看电视直播教程 安装PVR IPTV Simple Client播放m3u8直播源
  8. matlab怎么画矩形世界地图,matlab绘制世界地图
  9. overleaf换模板
  10. matlab自适应遗传算法代码,matlab自适应遗传算法