在驱动代码中,一般都是在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的作用是什么?