v4l2_async_subdev_notifier_register 分析
作者:互联网
Linux v4l2架构学习总链接
int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
struct v4l2_async_notifier *notifier)
{
int ret;
/*
* 有条件限制
* 1. subdev不能为空
* 2. v4l2_dev值为NULL
* 任意一个满足都不可以
* 这里的v4l2_dev,只有注册video节点的时候才会被赋值
*/
if (WARN_ON(!sd || notifier->v4l2_dev))
return -EINVAL;
notifier->sd = sd;
ret = __v4l2_async_notifier_register(notifier);
if (ret)
notifier->sd = NULL;
return ret;
}
static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
{
struct device *dev =
notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
struct v4l2_async_subdev *asd;
int ret;
int i;
if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
return -EINVAL;
INIT_LIST_HEAD(¬ifier->waiting);
INIT_LIST_HEAD(¬ifier->done);
mutex_lock(&list_lock);
/*
* 对于notifier->subdevs中有数据的情况
*/
for (i = 0; i < notifier->num_subdevs; i++) {
asd = notifier->subdevs[i];
switch (asd->match_type) {
case V4L2_ASYNC_MATCH_CUSTOM:
case V4L2_ASYNC_MATCH_DEVNAME:
case V4L2_ASYNC_MATCH_I2C:
break;
/*
* 重点分析 V4L2_ASYNC_MATCH_FWNODE
*/
case V4L2_ASYNC_MATCH_FWNODE:
if (v4l2_async_notifier_fwnode_has_async_subdev(
notifier, asd->match.fwnode, i)) {
dev_err(dev,
"fwnode has already been registered or in notifier's subdev list\n");
ret = -EEXIST;
goto err_unlock;
}
break;
default:
dev_err(dev, "Invalid match type %u on %p\n",
asd->match_type, asd);
ret = -EINVAL;
goto err_unlock;
}
/*
* asd挂载到notifier->waiting上
* 这里的notifier是mipi csi phy的,不是imx291的
* asd对应的是imx291的dts节点
*/
list_add_tail(&asd->list, ¬ifier->waiting);
}
/*
* 这里暂时认为v4l2_dev = NULL
* 所以不执行
*/
ret = v4l2_async_notifier_try_all_subdevs(notifier);
if (ret < 0)
goto err_unbind;
/*
* 这里暂时认为notifier->waiting不为空
* 所以不执行
*/
ret = v4l2_async_notifier_try_complete(notifier);
if (ret < 0)
goto err_unbind;
/* Keep also completed notifiers on the list */
list_add(¬ifier->list, ¬ifier_list);
mutex_unlock(&list_lock);
return 0;
}
v4l2_async_subdev_notifier_register
-> __v4l2_async_notifier_register
-> v4l2_async_notifier_fwnode_has_async_subdev
这里代入情景分析
2.2 -- 基于RV1126平台imx291分析 --- imx291注册
2.3 -- 基于RV1126平台imx291分析 --- mipi-csi-phy注册
注册了imx291,现在在注册mipi-csi-phy,调用到了这个函数
现在的情况是
notifier->num_subdevs = 1
asd->match.fwnode 指向imx291 dts的节点
notifier_list链表上只有imx291的notifier
static bool v4l2_async_notifier_fwnode_has_async_subdev(
struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
unsigned int this_index)
{
unsigned int j;
lockdep_assert_held(&list_lock);
/*
* 这里的for循环只是为了检测subdevs是不是重复
*/
/* Check that an fwnode is not being added more than once. */
for (j = 0; j < this_index; j++) {
struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
asd->match.fwnode ==
other_asd->match.fwnode)
return true;
}
/*
* 根据情景代入可以知道
* notifier_list上只有一个imx291的notifier
*/
/* Check than an fwnode did not exist in other notifiers. */
list_for_each_entry(notifier, ¬ifier_list, list)
if (__v4l2_async_notifier_fwnode_has_async_subdev(
notifier, fwnode))
return true;
return false;
}
static bool __v4l2_async_notifier_fwnode_has_async_subdev(
struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
{
struct v4l2_async_subdev *asd;
struct v4l2_subdev *sd;
/*
* 判断notifier->waiting链表上的asd 和当前的fwnode值是否相等
* 正常来说这里不会出现,除非注册了2次
*/
list_for_each_entry(asd, ¬ifier->waiting, list) {
if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
continue;
if (asd->match.fwnode == fwnode)
return true;
}
/*
* 判断notifier->done链表上的subdev和当前的fwnode值是否相等
*/
list_for_each_entry(sd, ¬ifier->done, async_list) {
if (WARN_ON(!sd->asd))
continue;
if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
continue;
if (sd->asd->match.fwnode == fwnode)
return true;
}
return false;
}
标签:fwnode,subdev,register,list,asd,async,v4l2,notifier 来源: https://blog.csdn.net/ldl617/article/details/115548594