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(&notifier->waiting);
	INIT_LIST_HEAD(&notifier->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, &notifier->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(&notifier->list, &notifier_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, &notifier_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, &notifier->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, &notifier->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;
}

 

上一篇:babel实战之@babel/register


下一篇:ShareMouse破解方法