完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
二,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 %sn", 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 %sn", 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 %sn", 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; } 最后链接情况如下 |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
基于米尔瑞芯微RK3576核心板/开发板的人脸疲劳检测应用方案
808 浏览 0 评论
1024 浏览 1 评论
887 浏览 1 评论
2113 浏览 1 评论
3373 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-26 18:59 , Processed in 0.503696 second(s), Total 44, Slave 36 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号