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篇文章,都是注册的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;
}

你可能感兴趣的:(#,v4l2,疑难函数分析,java,spring,数据结构)