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篇文章,都是注册的subdev,这里不考虑注册video,不考虑不考虑不考虑。。。
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;
}
v4l2_async_subdev_notifier_register
-> __v4l2_async_notifier_register
-> v4l2_async_notifier_fwnode_has_async_subdev
-> v4l2_async_notifier_try_all_subdevs
注意看到下面的文章后再开始看下面的分析
2.6 -- 基于RV1126平台imx291分析 -- rkcif_mipi注册
目前为止
notifier_list链表上有3个notifier,分别是imx291的, mipi csi phy的及 mipi csi 的
subdev_list链表上有3个subdev,分别是imx291的, mipi csi phy的及 mipi csi 的
mipi csi phy的notifier->waitng上有个asd,asd指向imx291 dts的节点
mipi csi 的notifier->waiting上有个asd,asd指向mipi csi phy dts的节点
rkcif_mipi 的notifier->waiting上有个asd,asd指向mipi csi dts的节点
当前的notifier是rkcif_mipi的,其v4l2_dev不为空
static int v4l2_async_notifier_try_all_subdevs(
struct v4l2_async_notifier *notifier)
{
struct v4l2_device *v4l2_dev =
v4l2_async_notifier_find_v4l2_dev(notifier);
struct v4l2_subdev *sd;
if (!v4l2_dev)
return 0;
again:
/*
* subdev_list链表上有3个subdev,
* 分别是imx291的, mipi csi phy的及 mipi csi 的
*/
list_for_each_entry(sd, &subdev_list, async_list) {
struct v4l2_async_subdev *asd;
int ret;
/*
* v4l2_async_find_match这个比较简单
* 首先从notifier->waiting上取下每一个asd
* 对于当前的rkcif_mipi来说其nontifier->waiting上的asd只有一个
* 这个asd指向mipi csi dts的节点
* 于是 subdev_list上取出mipi csi 的subdev时
* 这个这个asd就和mipi csi 匹配上了
*/
asd = v4l2_async_find_match(notifier, sd);
if (!asd)
continue;
/*
* sd为mipi csi 的subdev
* asd指向mipi csi dts的节点
* notifier是rkcif_mipi的
*/
ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
if (ret < 0)
return ret;
/*
* v4l2_async_match_notify() may lead to registering a
* new notifier and thus changing the async subdevs
* list. In order to proceed safely from here, restart
* parsing the list from the beginning.
*/
goto again;
}
return 0;
}
v4l2_async_subdev_notifier_register
-> __v4l2_async_notifier_register
-> v4l2_async_notifier_fwnode_has_async_subdev
-> v4l2_async_notifier_try_all_subdevs
-> v4l2_async_match_notify
static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
struct v4l2_device *v4l2_dev,
struct v4l2_subdev *sd,
struct v4l2_async_subdev *asd)
{
struct v4l2_async_notifier *subdev_notifier;
int ret;
/*
* 这里主要做2件事情
* 1. 调用sd->internal_ops->registered(sd) 有的话
* 2. sd从nitifier->waiting上移除挂载到v4l2_dev->subdevs上面
* 这个很重要,这是保证subdev能被注册的关键
*/
ret = v4l2_device_register_subdev(v4l2_dev, sd);
if (ret < 0)
return ret;
/*
* 调用notifier->ops->bound
*/
ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
if (ret < 0) {
v4l2_device_unregister_subdev(sd);
return ret;
}
/* Remove from the waiting list */
list_del(&asd->list);
sd->asd = asd;
/*
* 对于subdev之前注册的时候
* 其subdev的notifier都是保存在
* sd->subdev_notifier中
* 现在这个notifier用于保存管理者的notifier,
* 管理者就是上一级的notifier
*/
sd->notifier = notifier;
/*
* 之前sd通过async_list挂载到subdev_list
* 现在将其从subdev_list移除
* 挂载到notifier->done
* 主意notifier是管理者的notifier
*/
/* Move from the global subdevice list to notifier's done */
list_move(&sd->async_list, ¬ifier->done);
/*
* See if the sub-device has a notifier. If not, return here.
*/
/*
* 这句很关键
* 之前忽略了这句导致一直没有理解其他的subdev是怎么注册的
* 这里补贴代码,只说一下原理
* 根据上面的分析,知道sd是mipi csi dts的节点
* 于是就遍历notifier_list找到一个notifier
* 满足notifier->sd == sd
* 哪个notifier满足?
* 肯定是mipi csi 的notifier满足
* 这样就找到了下一级的notifier
*/
subdev_notifier = v4l2_async_find_subdev_notifier(sd);
if (!subdev_notifier || subdev_notifier->parent)
return 0;
/*
* Proceed with checking for the sub-device notifier's async
* sub-devices, and return the result. The error will be handled by the
* caller.
*/
/*
* 建立一个父子关系
*/
subdev_notifier->parent = notifier;
/*
* 这是一个嵌套函数
* 脑补一下后面是怎么执行的
* 继续从subdev_list上找到mipi csi phy的subdev
* 将mipi csi phy 的subdev挂载到v4l2_dev->subdevs上
* 将mipi csi phy 的sd从subdev_list上移除挂载到mipi csi的notifier->done上
*
* 接着找到mipi csi phy的notifer
* 继续从subdev_list上找到imx291的subdev
* 将imx291 的subdev挂载到v4l2_dev->subdevs上
* 将imx291 的sd从subdev_list上移除挂载到mipi csi phy的notifier->done上
*
* 接着找到imx291的notifer
* 由于notifier->waiting上没有设备,所以就不会找的subdev
* 于是就退出嵌套
*/
return v4l2_async_notifier_try_all_subdevs(subdev_notifier);
}
v4l2_async_subdev_notifier_register
-> __v4l2_async_notifier_register
-> v4l2_async_notifier_fwnode_has_async_subdev
-> v4l2_async_notifier_try_all_subdevs
-> v4l2_async_notifier_try_complete
static int v4l2_async_notifier_try_complete(
struct v4l2_async_notifier *notifier)
{
/* Quick check whether there are still more sub-devices here. */
/*
* sd从notifier->waiting上移除
* 是在v4l2_device_register_subdev中执行的
*/
if (!list_empty(¬ifier->waiting))
return 0;
/* Check the entire notifier tree; find the root notifier first. */
/*
* 找到最高级管理者的notifier
* 也就是v4l2_dev的notifier
* 对于我们分析的情景来说
* imx291 的 notifier parent是 mipi csi phy的notifier
* mipi csi phy 的 notifier parent是 mipi csi的notifier
* mipi csi 的 notifier parent是 rkcif_mipi的notifier
* rkcif_mipi 的 notifier parent为空
*/
while (notifier->parent)
notifier = notifier->parent;
/* This is root if it has v4l2_dev. */
if (!notifier->v4l2_dev)
return 0;
/* Is everything ready? */
/*
* 看下面分析
*/
if (!v4l2_async_notifier_can_complete(notifier))
return 0;
/*
* 当所有的notifier->waiting都为空的时候,说明准备好了
* 可以开始注册了
*/
/*
* 这里会调用管理者的notifier的
* ops->complete
* 这里会把所有的subdev都注册
*/
return v4l2_async_notifier_call_complete(notifier);
}
v4l2_async_subdev_notifier_register
-> __v4l2_async_notifier_register
-> v4l2_async_notifier_fwnode_has_async_subdev
-> v4l2_async_notifier_try_all_subdevs
-> v4l2_async_notifier_try_complete
-> v4l2_async_notifier_can_complete
static bool v4l2_async_notifier_can_complete(
struct v4l2_async_notifier *notifier)
{
struct v4l2_subdev *sd;
if (!list_empty(¬ifier->waiting))
return false;
/*
* 从管理者的notifier->done上找到下一级的sd
* 根据下一级的sd找从notifier_list上找到其对应的notifier
* 然后再找下一级...
* 通过确认所有的notifier->waiting为空
* 说明sb都挂载到了v4l2_dev->subdevs上了
* 就知道可以注册subdev了
* 退出的条件是
* 找到最后一个notifer,由于已经是最低级的notifier
* 所以最后一个notifier->done上是空的
*/
list_for_each_entry(sd, ¬ifier->done, async_list) {
struct v4l2_async_notifier *subdev_notifier =
v4l2_async_find_subdev_notifier(sd);
if (subdev_notifier &&
!v4l2_async_notifier_can_complete(subdev_notifier))
return false;
}
return true;
}