五、v4l2 ctrl 函数初始化

五、v4l2 ctrl 函数初始化,第1张

xxx_v4l2_ctrl结构体定义
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_new_std

当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]为例

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/873192.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存