Linux v4l2架构学习总链接

handler初始化代码调用如下:

v4l2_ctrl_handler_init(handler, 9);

对应源码:

#define v4l2_ctrl_handler_init(hdl, nr_of_controls_hint)     \v4l2_ctrl_handler_init_class(hdl, nr_of_controls_hint, NULL, NULL)int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,unsigned nr_of_controls_hint,struct lock_class_key *key, const char *name)
{mutex_init(&hdl->_lock);hdl->lock = &hdl->_lock;lockdep_set_class_and_name(hdl->lock, key, name);INIT_LIST_HEAD(&hdl->ctrls);INIT_LIST_HEAD(&hdl->ctrl_refs);/** 这里有个对8求商的操作* 传入的nr_of_controls_hint值为9* 所以这里的nr_of_buckets = 1 + 9/8 = 2*/hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;/** 这里注意 buckets的类型是 struct v4l2_ctrl_ref **buckets;* 所以sizeof(hdl->buckets[0]) 对应的大小是 struct v4l2_ctl_ref ** 也就是指针的大小,32位系统这个值为4,64位系统这个值为8* 这里也可以知道 hdl->buckets[0] 用于存储buckets的地址*/hdl->buckets = kvmalloc_array(hdl->nr_of_buckets,sizeof(hdl->buckets[0]),GFP_KERNEL | __GFP_ZERO);hdl->error = hdl->buckets ? 0 : -ENOMEM;return hdl->error;
}

初始化比较简单,接着分析注册相关的代码

static const s64 link_freq_menu_items[] = {MIPI_FREQ_360M,MIPI_FREQ_648M,
};link_freq = v4l2_ctrl_new_int_menu(handler, NULL,V4L2_CID_LINK_FREQ,1, 0, link_freq_menu_items);

v4l2_ctrl_new_initn_menu() 代码如下

struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,const struct v4l2_ctrl_ops *ops,u32 id, u8 _max, u8 _def, const s64 *qmenu_int)
{const char *name;enum v4l2_ctrl_type type;s64 min;u64 step;s64 max = _max;s64 def = _def;u32 flags;/** 根据下面的分析可以知道* name : "Link Frequenncy"* type : V4L2_CTRL_TYPE_INTEGER_MENU* flags : 0* min  : 局部变量没有赋值,值未知* max  : 参数传入 1* step : 局部变量没有赋值,值未知* def  : 参数传入 0*/v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);if (type != V4L2_CTRL_TYPE_INTEGER_MENU) {handler_set_err(hdl, -EINVAL);return NULL;}return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,0, max, 0, def, NULL, 0,flags, NULL, qmenu_int, NULL);
}

v4l2_ctrl_new_initn_menu() -> v4l2_ctrl_fill()

const char *v4l2_ctrl_get_name(u32 id)
{switch (id) {...case V4L2_CID_LINK_FREQ:       return "Link Frequency";...}
}void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags)
{*name = v4l2_ctrl_get_name(id);*flags = 0;switch (id) {...case V4L2_CID_LINK_FREQ:*type = V4L2_CTRL_TYPE_INTEGER_MENU;break;...}
}

v4l2_ctrl_new_initn_menu() -> v4l2_ctrl_new()

static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,const struct v4l2_ctrl_ops *ops,const struct v4l2_ctrl_type_ops *type_ops,u32 id, const char *name, enum v4l2_ctrl_type type,s64 min, s64 max, u64 step, s64 def,const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size,u32 flags, const char * const *qmenu,const s64 *qmenu_int, void *priv)
{struct v4l2_ctrl *ctrl;unsigned sz_extra;unsigned nr_of_dims = 0;unsigned elems = 1;bool is_array;unsigned tot_ctrl_size;unsigned idx;void *data;int err;if (hdl->error)return NULL;/** 根据传入的参数分析* ops       : NULL* type_ops  : NULL* id        : V4L2_CID_LINK_FREQ* name      : Link Frequency* type      : V4l2_CTRL_TYPE_INTEGER_MENU* min       : 0* max       : 1* step      : 0* def       : 0* dims      : NULL* elem_size : 0* flags      : 0* qmenu     : NULL* qmenu_int : link_freq_menu_items* priv      : NULL*/while (dims && dims[nr_of_dims]) {elems *= dims[nr_of_dims];nr_of_dims++;if (nr_of_dims == V4L2_CTRL_MAX_DIMS)break;}is_array = nr_of_dims > 0;/* Prefill elem_size for all types handled by std_type_ops */switch (type) {case V4L2_CTRL_TYPE_INTEGER64:elem_size = sizeof(s64);break;case V4L2_CTRL_TYPE_STRING:elem_size = max + 1;break;case V4L2_CTRL_TYPE_U8:elem_size = sizeof(u8);break;case V4L2_CTRL_TYPE_U16:elem_size = sizeof(u16);break;case V4L2_CTRL_TYPE_U32:elem_size = sizeof(u32);break;default:if (type < V4L2_CTRL_COMPOUND_TYPES)elem_size = sizeof(s32);break;}/** 对于不同的类型,elem_size值不一样*/tot_ctrl_size = elem_size * elems;/** 这里分析的是V4L2_CTRL_TYPE_INTEGER_MENU* 需要检查qmenu_init是否为NULL*//* Sanity checks */if (id == 0 || name == NULL || !elem_size ||id >= V4L2_CID_PRIVATE_BASE ||(type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||(type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {handler_set_err(hdl, -ERANGE);return NULL;}/** check_range检查如下* 对于 V4L2_CTRL_TYPE_INTEGER_MENU* if (min > max || def < min || def > max)* return -ERANGE;* if (step && ((1 << def) & step))*      return -EINVAL;*/err = check_range(type, min, max, step, def);if (err) {handler_set_err(hdl, err);return NULL;}if (is_array &&(type == V4L2_CTRL_TYPE_BUTTON ||type == V4L2_CTRL_TYPE_CTRL_CLASS)) {handler_set_err(hdl, -EINVAL);return NULL;}sz_extra = 0;if (type == V4L2_CTRL_TYPE_BUTTON)flags |= V4L2_CTRL_FLAG_WRITE_ONLY |V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)flags |= V4L2_CTRL_FLAG_READ_ONLY;else if (type == V4L2_CTRL_TYPE_INTEGER64 ||type == V4L2_CTRL_TYPE_STRING ||type >= V4L2_CTRL_COMPOUND_TYPES ||is_array)sz_extra += 2 * tot_ctrl_size;/** 创建一个ctrl*/ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);if (ctrl == NULL) {handler_set_err(hdl, -ENOMEM);return NULL;}INIT_LIST_HEAD(&ctrl->node);INIT_LIST_HEAD(&ctrl->ev_subs);/** 填充ctrl成员*/ctrl->handler = hdl;ctrl->ops = ops;/** 注意type_ops为NULL的话,这里会赋值std_type_ops*/ctrl->type_ops = type_ops ? type_ops : &std_type_ops;ctrl->id = id;ctrl->name = name;ctrl->type = type;ctrl->flags = flags;ctrl->minimum = min;ctrl->maximum = max;ctrl->step = step;/* 默认值 */ctrl->default_value = def;/* * !is_array == 1* type != V4L2_CTRL_TYPE_STRING* is_string == 0*/ctrl->is_string = !is_array && type == V4L2_CTRL_TYPE_STRING;/** is_ptr == 0*/ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;/** !ctrl->is_ptr == 1* type != V4L2_CTRL_TYPE_INTEGER64* is_int == 1*/ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;ctrl->is_array = is_array;ctrl->elems = elems;ctrl->nr_of_dims = nr_of_dims;if (nr_of_dims)memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0]));ctrl->elem_size = elem_size;if (type == V4L2_CTRL_TYPE_MENU)ctrl->qmenu = qmenu;else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)/** ctrl->qmenu_int = link_freq_menu_items*/ctrl->qmenu_int = qmenu_int;ctrl->priv = priv;/** ctrl->cur.val = 0* ctrl->val = 0*/ctrl->cur.val = ctrl->val = def;/** 因为sz_extra = 0* 所以data没有指向的地址 为NULL*/data = &ctrl[1];if (!ctrl->is_int) {ctrl->p_new.p = data;ctrl->p_cur.p = data + tot_ctrl_size;} else {/** @p_cur:通过联合表示的控件的当前值,该联合提供了一种通过指针访问控件类型的标准方法。* @p_new:通过联合表示控件的新值,该联合提供了一种通过指针访问控件类型的标准方法。*/ctrl->p_new.p = &ctrl->val;ctrl->p_cur.p = &ctrl->cur.val;}/* * elems值为1 * type_ops->init*     std_init()* 对于type为V4L2_CTRL_TYPE_INTEGER_MENU* ptr.p_s32[idx] = ctrl->default_value*/for (idx = 0; idx < elems; idx++) {ctrl->type_ops->init(ctrl, idx, ctrl->p_cur);ctrl->type_ops->init(ctrl, idx, ctrl->p_new);}if (handler_new_ref(hdl, ctrl)) {kvfree(ctrl);return NULL;}mutex_lock(hdl->lock);/** 将ctrl通过node挂载到hdl底ctrls链表上*/list_add_tail(&ctrl->node, &hdl->ctrls);mutex_unlock(hdl->lock);return ctrl;
}

v4l2_ctrl_new_initn_menu() -> v4l2_ctrl_new() -> handler_new_ref()

static int handler_new_ref(struct v4l2_ctrl_handler *hdl,struct v4l2_ctrl *ctrl)
{struct v4l2_ctrl_ref *ref;struct v4l2_ctrl_ref *new_ref;u32 id = ctrl->id;/** 这里获取ctrl所属的类* 比如当前分析的V4L2_CID_LINK_FREQ* 所属的类为 V4L2_CTRL_CLASS_IMAGE_PROC*/u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1;/** 这里将不同的id放入多个buckets中,方便快速查找*/int bucket = id % hdl->nr_of_buckets;    /* which bucket to use *//** Automatically add the control class if it is not yet present and* the new control is not a compound control.*//** 如果尚不存在控件类并且新控件不是复合控件,则自动添加该控件类。 * 对于控件类这里先不分析,等分析完V4L2_CID_LINK_FREQ* 再回来看这个*/if (ctrl->type < V4L2_CTRL_COMPOUND_TYPES &&id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL)if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0))return hdl->error;if (hdl->error)return hdl->error;/** ref是reference的缩写,参考的意思*/new_ref = kzalloc(sizeof(*new_ref), GFP_KERNEL);if (!new_ref)return handler_set_err(hdl, -ENOMEM);/** 填充ctrl*/new_ref->ctrl = ctrl;/** 对于v4l2_ctrl_add_handler调用当前函数的时候* ctrl->handler != hdl* 所以这里加上判断* 但是if中的代码暂时没有看明白....*/if (ctrl->handler == hdl) {/* By default each control starts in a cluster of its own.new_ref->ctrl is basically a cluster array with oneelement, so that's perfect to use as the cluster pointer.But only do this for the handler that owns the control. */ctrl->cluster = &new_ref->ctrl;ctrl->ncontrols = 1;}INIT_LIST_HEAD(&new_ref->node);mutex_lock(hdl->lock);/* Add immediately at the end of the list if the list is empty, or ifthe last element in the list has a lower ID.This ensures that when elements are added in ascending order theinsertion is an O(1) operation. *//** new_ref是根据id排列挂载到hdl->ctrl_refs上的* 1. hdl->ctrl_refs链表是空的,直接添加就可以* 2. 链表上最后一个成员ID比当前的ID小*    链表上有数据,说明已经排列过了,所以这里也可以直接添加*/if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) {list_add_tail(&new_ref->node, &hdl->ctrl_refs);goto insert_in_hash;}/** 上面的条件都不符合,这里要找到合适的位置添加*//* Find insert position in sorted list */list_for_each_entry(ref, &hdl->ctrl_refs, node) {if (ref->ctrl->id < id)continue;/* Don't add duplicates */if (ref->ctrl->id == id) {kfree(new_ref);goto unlock;}/** 找到合适的位置,添加*/list_add(&new_ref->node, ref->node.prev);break;}insert_in_hash:/** 之前说过buckets是为了实现快速查找* 这里直接通过hdl->buckets[bucket]指向new_ref*//* Insert the control node in the hash */new_ref->next = hdl->buckets[bucket];hdl->buckets[bucket] = new_ref;unlock:mutex_unlock(hdl->lock);return 0;
}

以上就完成了handler ctrl的注册

假设11个ctrl,ID为1~11,这里先不考虑ctrl class,注册顺序 1 3 4 6 7 8 10 11 9 2 5

v4l2架构专题模块handler分析 --- handler的初始化及handler ctrl注册相关推荐

  1. v4l2架构专题模块handler分析 -- handler ctrl的注册2

    Linux v4l2架构学习总链接 上一篇文章中忽略了ctrl class,这里补上 static int handler_new_ref(struct v4l2_ctrl_handler *hdl, ...

  2. v4l2架构专题模块handler分析 -- handler使能(1)cluster

    在驱动代码中,一般都是在probe中初始化handler及创建ctrl,在stream_on的时候会去使能handler,对应的函数是 __v4l2_ctrl_handler_setup int __ ...

  3. Linux v4l2架构学习

    写在开始之前. 网上有很多文章讲v4l2架构,讲的都很好,但是很多都是讲讲主要的结构体已经注册接口这些,个人觉得入门还是要深入的去看代码,至少把整个流程粗略的看一遍,才能真正的了解架构是什么样的,调用 ...

  4. linux v4l2架构分析之v4l2_ctrl_handler初始化及添加v4l2_ctrl的过程分析

    本文根据原代码分析v4l2的handler初始化以及添加ctrl的过程,会涉及v4l2_ctrl_handler.v4l2_ctrl.v4l2_ctrl_ref结构体的分析,以及介绍v4l2_ctrl ...

  5. java bs架构书_基于BS架构的图书借阅管理模块的分析与设计(JSP+MySQL)(新品)

    基于BS架构的图书借阅管理模块的分析与设计(JSP+MySQL)(新品) 来源:2BYSJ.cn 资料编号:2SJ295500 资料等级:★★★★★ %D7%CA%C1%CF%B1%E0%BA%C5% ...

  6. 基于Ti Omap3x 分析v4l2架构

    1 概述 本文将基于Ti Omap3x这个典型的实例来分析v4l2在具体media场景中的应用.通过分析app层的行为以及driver层的实现来对整个多媒体框架有一个大概的认识.内容主要包括主要包括v ...

  7. Camera V4L2 架构分析

    转自:点击打开链接 V4L2相关代码位于linux-3.4/drivers/media/video目录中. v4l2-dev.c文件提供设备节点实现与用户层数据交流,设备节点在/dev/目录下以vid ...

  8. EDUSOHO踩坑笔记之六:edusoho架构及模块分析

    EDUSOHO踩坑笔记之六:edusoho架构及模块分析 从目录结构.入口文件.配置.控制器.服务层.模型.模块组成等几个角度,进行架构的描述.本文档是以8.0的版本为基准的说明,与其他版本会有些区别 ...

  9. Camera | 5.Linux v4l2架构(基于rk3568)

    上一篇我们讲解了如何编写基于V4L2的应用程序编写,本文主要讲解内核中V4L2架构,以及一些最重要的结构体.注册函数. 厂家在实现自己的摄像头控制器驱动时,总体上都遵循这个架构来实现,但是不同厂家.不 ...

最新文章

  1. 日本的GMO增加了比特币现金,和另外3种用于贷款项目的加密货币
  2. 人工智能写的散文之白色月光下
  3. activemq的使用(四)
  4. 数据库 sqlite 进阶
  5. Lecture 3 Divide and Conquer
  6. 转载:jQuery 1.3.3 新功能
  7. MybatisPlus报错: org.apache.velocity.context.Context(已解决)
  8. 在拓扑引擎内检测到故障,错误代码255
  9. 关于天猫魔盒tmb100系列 开机灯亮显示器无反应的问题分析
  10. 如何实现一个以中国为中心的世界地图
  11. 软件测试思想者 - 再识王阳明
  12. 第四章-整合管理【核心词:批准】
  13. Markdown 格式参考-中文文案排版指北
  14. Request method ‘PUT‘ not supported
  15. 小米电视安装 Plex 打造家庭影院
  16. CorelDRAW 入门知识
  17. 伴随着我娃成长的运维平台(持续开源..)
  18. 基于java的心理健康网站的设计与实现_基于JavaEE心理健康教育网站的设计与开发.doc...
  19. Oracle 体系结构(26)—— 查询用户权限
  20. python 跳出两层循环

热门文章

  1. 魅族手机照片没了怎么恢复
  2. 文字在div中水平居中,垂直居中
  3. php 计算月差,php计算月份差
  4. 服务器 战地4 无限载入,战地4卡在loading界面无限载入_战地4无限载入解决方法...
  5. 服务器端与客户端之间进行数据传输与交换的格式(xml与JSON)
  6. 银行营销策略数据分析 - 智能定位
  7. android 检测 Home 键
  8. **手机丢失之后如果通过更简单的手机定位系统找回手机?**
  9. 区块链是如何存数据的?
  10. 【面试系列三】面试是面试者与面试官的双向沟通,如何抓住面试官的小尾巴以及面试过程中需要避开的一些减分项!