struct xxx_v4l2_ctrl {
struct v4l2_device *v4l2_dev;
struct video_device *video_dev;
uint32_t ctx_id;
struct v4l2_ctrl_handler ctrl_hdl_std_ctrl;
struct v4l2_ctrl_handler ctrl_hdl_cst_ctrl;
};
v4l2_ctrl_handler结构体定义
struct v4l2_ctrl_handler {
struct mutex _lock;
struct mutex *lock;
struct list_head ctrls;
struct list_head ctrl_refs;
struct v4l2_ctrl_ref *cached;
struct v4l2_ctrl_ref **buckets;
v4l2_ctrl_notify_fnc notify;
void *notify_priva;
u16 nr_of_buckets;
int error;
};
v4l2_ctrl结构体定义
struct v4l2_ctrl {
struct list_head node;
struct list_head ev_subs;
struct v4l2_ctrl_handler *handler;
struct v4l2_ctrl **cluster;
unsigned int ncontrols;
unsigned int done:1;
unsigned int is_new:1;
unsigned int has_changed:1;
unsigned int is_private:1;
unsigned int is_auto:1;
unsigned int is_int:1;
unsigned int is_string:1;
unsigned int is_ptr:1;
unsigned int is_array:1;
unsigned int has_volatiles:1;
unsigned int call_notify:1;
unsigned int manual_mode_value:8;
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 minimum, maximum, default_value;
u32 elems;
u32 elem_size;
u32 dims[V4L2_CTRL_MAX_DIMS];
u32 nr_of_dims;
union {
u64 step;
u64 menu_skip_mask;
};
union {
const char * const *qmenu;
const s64 *qmenu_int;
};
unsigned long flags;
void *priv;
s32 val;
struct {
s32 val;
} cur;
union v4l2_ctrl_ptr p_new;
union v4l2_ctrl_ptr p_cur;
}
//dev->xxx_v4l2_ctrl.v4l2_dev = dev->v4l2_dev;
//dev->xxx_v4l2_ctrl.video_dev = &dev->video_dev;
//v4l2_ctrl_init(ctx_id, &dev->xxx_v4l2_ctrl);
int v4l2_ctrl_init( uint32_t ctx_id, xxx_v4l2_ctrl *ctrl )
{
struct v4l2_ctrl_handler *hdl_std_ctrl = &ctrl->ctrl_hdl_std_ctrl;//标准控制
struct v4l2_ctrl_handler *hdl_cst_ctrl = &ctrl->ctrl_hdl_cst_ctrl;//自定义控制
struct v4l2_ctrl *tmp_ctrl;
struct v4l2_ctrl_config tmp_ctrl_cfg;
struct v4l2_ctrl_config tmp_ctrl_cfg;
/* Init and add standard controls */
/*
hdl_std_ctrl
1、初始化handler集合的ctrl头节点
2、初始化handler集合的refs头节点
3、初始化buckets的个数
hdl->nr_of_buckets表明桶的数量,一个桶最多可以存放8个control,buckets表明用来存放的地址,假如有24个control,那就要用到3个桶,hdl->nr_of_buckets = 3
buckets[0]存放8个v4l2_ref指针
在struct v4l2_ctrl_handler结构体类型内部还有一个cache成员,其他类型是struct
*/
v4l2_ctrl_handler_init(hdl_std_ctrl, 10);//10个控制
//新增一个control
ADD_CTRL_STD(V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
}
v4l2_ctrl_handler结构体
struct v4l2_ctrl_handler {
struct mutex _lock;
struct mutex *lock;
struct list_head ctrls;
struct list_head ctrl_refs;
struct v4l2_ctrl_ref *cached;
struct v4l2_ctrl_ref **buckets;
v4l2_ctrl_notify_fnc notify;
void *notify_priva;
u16 nr_of_buckets;
int error;
};
v4l2_ctrl_handler_init初始化
#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,...)
{
hdl->lock = &hdl->_lock;
mutex_init(hdl->lock);
lockdep_set_class_and_name(hdl->lock, key, name);
INIT_LIST_HEAD(&hdl->ctrls);
INIT_LIST_HEAD(&hdl->ctrl_refs);
hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;//10个控制需要两个桶
...
/*
* 这里注意 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;
}
hdl->nr_of_buckets = 1 + nr_of_controls_hint/8,这表明桶的数量,这里可以得出一个桶能放置8个v4l2_ctrl_ref指针,
再看下buckets成员类型,是struct v4l2_ctrl_ref**类型的,表明这个参数用来存放桶的地址,一共有nr_of_buckets个桶会被记录到buckets[n]数组内
当v4l2_ctrl_handler_init初始化结束后,基本的ctrl链表和ctrl_ref指针链表以及buckets大小分配完毕
新增一个control v4l2_ctrl_new_std( handler_ctrl, &isp_v4l2_ctrl_ops,V4L2_CID_BRIGHTNESS, … );
struct v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, u32 id,....)
{
const char *name;
enum v4l2_ctrl_type type;
u32 flags;
...
return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, min, max, step, def, NULL, 0....);
}
v4l2_ctrl_new
在这个函数中,初始化一个v4l2_ctrl,把v4l2_ctrl的id、ops、handler、name都初始化了
static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,const struct v4l2_ctrl_ops *ops,,,u32 id)
{
struct v4l2_ctrl *ctrl;
...
INIT_LIST_HEAD(&ctrl->node);
ctrl->handler = hdl;
ctrl->ops = ops;
ctrl->type_ops = type_ops ? type_ops : &std_type_ops;
ctrl->id = id;
ctrl->name = name;
...
handler_new_ref(hdl,ctrl);
}
handler_new_ref
无论是 v4l2_ctrl_new_std、v4l2_ctrl_new_std_menu、v4l2_ctrl_new_custom最终都会调到一个地方,那就是 handler_new_ref 函数
static int handler_new_ref(struct v4l2_ctrl_handler *hdl, struct *ctrl)
{
struct v4l2_ctrl_ref *refs;
struct v4l2_ctrl_ref new_ref;
u32 id = ctrl->id;
u32 class_ctrl = V4L2_CTRL_ID2_WHICH(id) | 1;
int bucket = id % hdl->nr_of_buckets;
...
new_ref = kzalloc(sizeof(*new_ref),GFP_KERNEL);
if (!new_ref)
return handler_set_err(hdl, -ENOMEM);
new_ref->ctrl = ctrl;//新建的v4l2_ctrl_ref指向了新添加的v4l2_ctrl
if (ctrl->handler == hdl) {
//在后面拿control值时,直接从cluster中取值
ctrl->cluster = &new_ref->ctrl;
ctrl->ncontrols = 1;
}
...
INIT_LIST_HEAD(&new_ref->node);
/* 如果为空,或者大于尾端的id,在尾端插入ref节点 */
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;
}
/* 否则遍历 [ctrl_refs] 链表,直到找到第一个 id 值比将要插入的 contorl 的 id 大的
* [v4l2_ctrl_ref] 实例化对象 [ref],然后把新的 [new_ref] 插入到这个 [ref] 前面 */
list_for_each_entry(ref, &hdl->ctrl_refs, node) {
if (ref->ctrl->id < id)
continue;
if (ref->ctrl->id == id) {
kfree(new_ref);
goto unlock;
}
list_add(&new_ref->node, ref->node.prev);
break;
}
/* 由此可见,ctrl_ref链表中的实例new_ref(指向一个control) 都是按照id值升序排列的,完成了v4l2_ctrl_handler->ctrl_refs链表的插入动作之后,还有最后一步,那就是把新的ctrl_ref放入到一个哈希表中,也就是前面说的桶*/
insert_in_hash:
new_ref->next = hdl->buckets[bucket];
hdl->buckets[bucket] = new_ref;
unlock: mutex_unlock(hdl->lock);
return 0;
}
这里的bucket根据id找到对应的桶,假如一共有2个桶 buckets[0]、buckets[1],假设有8个control的id分别是1-8,通过取模运算,2、4、6、8放在了buckets[0]中,1、3、5、7放到了buckets[0]中,查找的时候也是按照桶排序查找
insert_in_hash:
/* Insert the control node in the hash */
new_ref->next = hdl->buckets[bucket];
hdl->buckets[bucket] = new_ref;
这个函数的作用是把新的ctrl_ref放入到哈希表中,也就是前面的桶
他的作用是把开头使用的id % hdl->nr_of_buckets索引到的桶里面的第一项v4l2_ctrl_ref地址赋值给新的new_ref的next成员,然后把新的new_ref地址赋值给索引到的桶
现在以buckets[1]为例
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)