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

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

int __v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
{
	struct v4l2_ctrl *ctrl;
	int ret = 0;

	if (hdl == NULL)
		return 0;

	lockdep_assert_held(hdl->lock);

	list_for_each_entry(ctrl, &hdl->ctrls, node)
		ctrl->done = false;

	list_for_each_entry(ctrl, &hdl->ctrls, node) {
		struct v4l2_ctrl *master = ctrl->cluster[0];
		int i;

		/* Skip if this control was already handled by a cluster. */
		/* Skip button controls and read-only controls. */
		if (ctrl->done || ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
		    (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
			continue;

		for (i = 0; i < master->ncontrols; i++) {
			if (master->cluster[i]) {
				cur_to_new(master->cluster[i]);
				master->cluster[i]->is_new = 1;
				master->cluster[i]->done = true;
			}
		}
		ret = call_op(master, s_ctrl);
		if (ret)
			break;
	}

	return ret;
}

函数中2次遍历handler中的ctrl,这里只关心第二次的遍历

对于类型BUTTON及标记了只读的的ctrl,直接忽略

首次,ctrl->cluster,cluster是簇的意思,一簇簇代表了一个集合,也表示数量较多。那么这个ctrl->cluster的作用是什么?

其实我们之前的分析见到过这个在 handler_new_ref中

        /*
         * 对于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 one
		   element, 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;
	}

注释中有写到调用v4l2_ctrl_add_handler的时候,这里if条件可能会满足,对应的驱动调用应该是

v4l2_async_match_notify
    v4l2_ctrl_add_handler
        v4l2_ctrl_add_handler

        v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler, NULL);

这是之前分析subdev注册的时候,分析过的,但是因为当时忽略了handler,所以没有分析    

int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
    struct v4l2_ctrl_handler *add, 
    bool (*filter)(const struct v4l2_ctrl *ctrl))
{
	struct v4l2_ctrl_ref *ref;
	int ret = 0;

	/* Do nothing if either handler is NULL or if they are the same */
	if (!hdl || !add || hdl == add)
		return 0;
	if (hdl->error)
		return hdl->error;
	mutex_lock(add->lock);
	list_for_each_entry(ref, &add->ctrl_refs, node) {
		struct v4l2_ctrl *ctrl = ref->ctrl;

		/* Skip handler-private controls. */
		if (ctrl->is_private)
			continue;
		/* And control classes */
		if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
			continue;
		/* Filter any unwanted controls */
		if (filter && !filter(ctrl))
			continue;
		ret = handler_new_ref(hdl, ctrl);
		if (ret)
			break;
	}
	mutex_unlock(add->lock);
	return ret;
}

可以看到是将subdev的handler中每一个ctl添加到了video的handler中,而且每一个ctrl都会有一个cluster,但是实际上我们的代码video没有handler,所以这里执行不到,所以不去分析。

对于cluster来说,最主要的还是v4l2_ctrl_cluster,这个的作用就是把相关的或者一类的ctrl放到一个簇中,当对第一个ctrl使能的时候,这个簇内的其他ctrl也会被使能。下面贴一下代码可以看看

drivers/media/common/cx2341x.c

int cx2341x_handler_init(struct cx2341x_handler *cxhdl,
			 unsigned nr_of_controls_hint)
{
    ...

    v4l2_ctrl_handler_init(hdl, nr_of_controls_hint);

    cxhdl->audio_sampling_freq = cx2341x_ctrl_new_menu(hdl,
			V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
			V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 0,
			V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
    cxhdl->video_b_frames = cx2341x_ctrl_new_std(hdl,
			V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 33, 1, 2);
    ...

    v4l2_ctrl_cluster(8, &cxhdl->audio_sampling_freq);
    v4l2_ctrl_cluster(2, &cxhdl->video_b_frames);
    ...
}

 对于其中的数字8还有2是不是有些迷惑,这里看看v4l2_ctrl_cluster的源码

void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
{
	bool has_volatiles = false;
	int i;

	/* The first control is the master control and it must not be NULL */
	if (WARN_ON(ncontrols == 0 || controls[0] == NULL))
		return;

	for (i = 0; i < ncontrols; i++) {
		if (controls[i]) {
			controls[i]->cluster = controls;
			controls[i]->ncontrols = ncontrols;
			if (controls[i]->flags & V4L2_CTRL_FLAG_VOLATILE)
				has_volatiles = true;
		}
	}
	controls[0]->has_volatiles = has_volatiles;
}

首先这里要注意的是传入的参数controls是二级指针,controls[x]则是对应controls变量的存储地址,这里有controls[i]的操作,说明这是个连续地址

找到上面2个ctrl的定义

struct cx2341x_handler {
    ...
    struct {
		/* audio cluster */
		struct v4l2_ctrl *audio_sampling_freq;
		struct v4l2_ctrl *audio_encoding;
		struct v4l2_ctrl *audio_l2_bitrate;
		struct v4l2_ctrl *audio_mode;
		struct v4l2_ctrl *audio_mode_extension;
		struct v4l2_ctrl *audio_emphasis;
		struct v4l2_ctrl *audio_crc;
		struct v4l2_ctrl *audio_ac3_bitrate;
	};
    ...
    struct {
		/* video gop cluster */
		struct v4l2_ctrl *video_b_frames;
		struct v4l2_ctrl *video_gop_size;
	};
    ...
}

可以看到在定义的时候,是把ctrl按功能模块进行划分的,放到结构体中,所以ctrl的地址就是连续的,对应的数量就是8和2这两个数据的由来。

这样就明白了cluster是什么,如何生成的,已经如何使用的,那么后面就继续分析handler的使能。

最后还有个疑问,master->cluster[i]->is_new = 1,这个is_new的作用是什么?

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dianlong_lee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值