基于RV1126平台imx291分析 --- media部件连接 二

Linux v4l2架构学习总链接

二,mipi csi 与mipi csi phy

这里直接贴出来bount函数

static const struct
v4l2_async_notifier_operations csi2_async_ops = {
	.bound = csi2_notifier_bound,
	.unbind = csi2_notifier_unbind,
};

static int
csi2_notifier_bound(struct v4l2_async_notifier *notifier,
		    struct v4l2_subdev *sd,
		    struct v4l2_async_subdev *asd)
{
	struct csi2_dev *csi2 = container_of(notifier,
			struct csi2_dev,
			notifier);
	struct csi2_sensor *sensor;
	struct media_link *link;
	unsigned int pad, ret;

	if (csi2->num_sensors == ARRAY_SIZE(csi2->sensors))
		return -EBUSY;

	sensor = &csi2->sensors[csi2->num_sensors++];

        /*
         * 这里的sd是mipi csi phy的subdev
         */

	sensor->sd = sd;

        /*
         * mipi csi phy 的entity有2个pad
         * 1个sink pad,1个source pad
         * 这里是要找到source pad
         * 为什么要找source呢?
         * 因为source才是下一级需要的
         * 可以看到这里只考虑了一个pad
         * 因为写驱动的人知道source media 及 sink media的pad的个数
         */

	for (pad = 0; pad < sd->entity.num_pads; pad++)
		if (sensor->sd->entity.pads[pad].flags
					& MEDIA_PAD_FL_SOURCE)
			break;

        /*
         * 这里表示没有找到source pad
         * 返回-ENXIO
         */

	if (pad == sensor->sd->entity.num_pads) {
		dev_err(csi2->dev,
			"failed to find src pad for %s\n",
			sd->name);

		return -ENXIO;
	}

        /*
         * 这里重点分析
         */

	ret = media_create_pad_link(&sensor->sd->entity, pad,
				    &csi2->sd.entity, RK_CSI2_PAD_SINK,
				    0/* csi2->num_sensors != 1 ? 0 : MEDIA_LNK_FL_ENABLED */);
	if (ret) {
		dev_err(csi2->dev,
			"failed to create link for %s\n",
			sd->name);
		return ret;
	}


        /*
         * 从entity的links链表上,找到第一个link
         * 主意这个entity是mipi-csi的,不是mipi-csi-phy的
         */


	link = list_first_entry(&csi2->sd.entity.links, struct media_link, list);
	ret = media_entity_setup_link(link, MEDIA_LNK_FL_ENABLED);
	if (ret) {
		dev_err(csi2->dev,
			"failed to create link for %s\n",
			sensor->sd->name);
		return ret;
	}

	return 0;
}

 csi2_notifier_bound() -> media_create_pad_link()

int
media_create_pad_link(struct media_entity *source, u16 source_pad,
			 struct media_entity *sink, u16 sink_pad, u32 flags)
{
	struct media_link *link;
	struct media_link *backlink;

	BUG_ON(source == NULL || sink == NULL);
	BUG_ON(source_pad >= source->num_pads);
	BUG_ON(sink_pad >= sink->num_pads);

        /*
         * 创建一个link
         * 这个link连接到source的links链表
         */

	link = media_add_link(&source->links);
	if (link == NULL)
		return -ENOMEM;

        /*
         * link的source指向source的source pad
         * link的sink指向sink的sink pad
         */
    

	link->source = &source->pads[source_pad];
	link->sink = &sink->pads[sink_pad];
	link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK;

	/* Initialize graph object embedded at the new link */
    
        /*
         * 之前分析imx291 mipi-csi-phy mipi-csi的时候
         * 都是因为这个graph_obj.mdev为NULL
         * 而无法深入分析
         * 那么现在的source其mdev是怎么得到的呢?
         * 在函数 v4l2_device_register_subdev中
         * 调用 media_device_register_entity 设置的
         * 这里建议去看
         * v4l2_async_subdev_notifier_register 分析
         * https://blog.csdn.net/ldl617/article/details/115548594
         * 另外主意这里的所有点entity都已经链接到了media的entities链表
         * 
         * media_gobj_create已经分析了很多次了
         * 将link通过greph_obj链接到media的links链表
         */

	media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
			&link->graph_obj);

	/* Create the backlink. Backlinks are used to help graph traversal and
	 * are not reported to userspace.
	 */

        /*
         * 创建一个backlink,链接到sink底links
         * 虽说是反向link
         * 但是source和sink指向还是没有改变的
         * 最后is_backlink = true 用于表示这是个反向link
         */
        
    	backlink = media_add_link(&sink->links);
	if (backlink == NULL) {
		__media_entity_remove_link(source, link);
		return -ENOMEM;
	}

	backlink->source = &source->pads[source_pad];
	backlink->sink = &sink->pads[sink_pad];
	backlink->flags = flags;
	backlink->is_backlink = true;

	/* Initialize graph object embedded at the new link */
        
        /*
         * 将backlink通过graph_obj链接到media的links
         */
    
	media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK,
			&backlink->graph_obj);

        /*    
         * link和backlink关联起来
         */

	link->reverse = backlink;
	backlink->reverse = link;

        /*
         * 更新sink的links和backlinks数量
         * 更新source的links数量
         */

	sink->num_backlinks++;
	sink->num_links++;
	source->num_links++;

	return 0;
}

csi2_notifier_bound() -> media_entity_setup_link()

media_entity_setup_link(link, MEDIA_LNK_FL_ENABLED);
int media_entity_setup_link(struct media_link *link, u32 flags)
{
	int ret;

	mutex_lock(&link->graph_obj.mdev->graph_mutex);
	ret = __media_entity_setup_link(link, flags);
	mutex_unlock(&link->graph_obj.mdev->graph_mutex);

	return ret;
}

int __media_entity_setup_link(struct media_link *link, u32 flags)
{
	const u32 mask = MEDIA_LNK_FL_ENABLED;
	struct media_device *mdev;
	struct media_entity *source, *sink;
	int ret = -EBUSY;

	if (link == NULL)
		return -EINVAL;

	/* The non-modifiable link flags must not be modified. */

        /*
         * link->flags 这里是0
         * flag = MEDIA_LNK_FL_ENABLE
         * 所以if不满足
         */


	if ((link->flags & ~mask) != (flags & ~mask))
		return -EINVAL;

	if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
		return link->flags == flags ? 0 : -EINVAL;

	if (link->flags == flags)
		return 0;

        /*
         * 分别找到source entity
         * 和sink entity
         */


	source = link->source->entity;
	sink = link->sink->entity;

        
        /*
         * stream_count值大于0,可以认为启动了数据流传输
         * 这里没有,所以为0
         */
        

	if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
	    (source->stream_count || sink->stream_count))
		return -EBUSY;

        /*
         * 找到所属的media
         */

	mdev = source->graph_obj.mdev;

        /*
         * 调用media->ops->link_notify
         * 基于RV1126平台imx291分析 --- media注册
         * https://blog.csdn.net/ldl617/article/details/115677554
         * 可以看上面的分析,medv没有ops,所以这里不分析
         */

	if (mdev->ops && mdev->ops->link_notify) {
		ret = mdev->ops->link_notify(link, flags,
					     MEDIA_DEV_NOTIFY_PRE_LINK_CH);
		if (ret < 0)
			return ret;
	}

	ret = __media_entity_setup_link_notify(link, flags);

	if (mdev->ops && mdev->ops->link_notify)
		mdev->ops->link_notify(link, flags,
				       MEDIA_DEV_NOTIFY_POST_LINK_CH);

	return ret;
}

csi2_notifier_bound() -> media_entity_setup_link() -> __media_entity_setup_link_notify()

static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
{
	int ret;

	/* Notify both entities. */

        /*
         * source entity 是mipi-csi-phy
         * sink entity 是mipi csi
         * mipi csi entity有ops = csi_entity_ops
         */

        /* source entity没有ops */

	ret = media_entity_call(link->source->entity, link_setup,
				link->source, link->sink, flags);
	if (ret < 0 && ret != -ENOIOCTLCMD)
		return ret;

        /* 
         * 调用 csi_entity_ops.link_setup 
         * 对应 csi2_link_setup
         */

    	ret = media_entity_call(link->sink->entity, link_setup,
				link->sink, link->source, flags);
	if (ret < 0 && ret != -ENOIOCTLCMD) {
		media_entity_call(link->source->entity, link_setup,
				  link->source, link->sink, link->flags);
		return ret;
	}

        /*
         * 更新link->flags为ENABLE
         * 同时backlink的也更新一下
         */

	link->flags = flags;
	link->reverse->flags = link->flags;

	return 0;
}

csi2_notifier_bound() -> media_entity_setup_link() -> __media_entity_setup_link_notify() -> csi2_link_setup()

static int csi2_link_setup(struct media_entity *entity,
			   const struct media_pad *local,
			   const struct media_pad *remote, u32 flags)
{
	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
	struct csi2_dev *csi2 = sd_to_dev(sd);
	struct v4l2_subdev *remote_sd;
	int ret = 0;

        /*
         * 根据上下文分析
         * entity是sink entity
         * local 是sink pad 
         * remote 是source pad
         * remote->entity是 source mentity
         * flags 是 MEDIA_LNK_FL_ENABLED
         */

        /*
         * sd.entity == remote->entity
         * 根据entity找到subdev
         * 这里的remote_sd就是mipi-csi-phy的subdev
         */

	remote_sd = media_entity_to_v4l2_subdev(remote->entity);

	mutex_lock(&csi2->lock);

        /*
         * local->flags = 0
         */

	if (local->flags & MEDIA_PAD_FL_SOURCE) {
		if (flags & MEDIA_LNK_FL_ENABLED) {
			if (csi2->sink_linked[local->index - 1]) {
				ret = -EBUSY;
				goto out;
			}
			csi2->sink_linked[local->index - 1] = true;
		} else {
			csi2->sink_linked[local->index - 1] = false;
		}
	} else {
		if (flags & MEDIA_LNK_FL_ENABLED) {
			if (csi2->src_sd) {
				ret = -EBUSY;
				goto out;
			}
                        
                        /*
                         * csi2通过src_sd直接关联到mipi-csi-phy的subdev
                         */

			csi2->src_sd = remote_sd;
		} else {
			csi2->src_sd = NULL;
		}
	}

out:
	mutex_unlock(&csi2->lock);
	return ret;
}

最后链接情况如下

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dianlong_lee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值