完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
imx291的dts配置如下
imx291: imx291@1a { compatible = "sony,imx291"; status = "okay"; reg = <0x1a>; ... port { ucam_out2: endpoint { remote-endpoint = <&mipi_in_ucam0>; data-lanes = <1 2 3 4>; }; }; }; 对于endpoint这里先忽略 下面分析驱动 imx291_probe struct imx291 { struct i2c_client *client; ... struct v4l2_subdev subdev; struct media_pad pad; ... bool streaming; bool power_on; ... }; static int imx291_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct device_node *node = dev->of_node; struct imx291 *imx291; struct v4l2_subdev *sd; int ret; imx291 = devm_kzalloc(dev, sizeof(*imx291), GFP_KERNEL); if (!imx291) return -ENOMEM; ... imx291->client = client; ... sd = &imx291->subdev; /* * v4l2_i2c_subdev_init这里不展开分析 * 主要记录一下几点 * sd->ops = &imx291_subdev_ops; * sd->v4l2_dev = NULL; * sd->flags = V4L2_SUBDEV_FL_IS_I2C */ v4l2_i2c_subdev_init(sd, client, &imx291_subdev_ops); /* * 对于controls这里先不分析 * 后面有专题进行分析 */ ret = imx291_initialize_controls(imx291); if (ret) goto err_probe; /* * 这个配置开启了 * 下面这个成员值都先记住就好 */ #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API sd->internal_ops = &imx291_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; #endif /* * media这里也先不分析 * 后面专题 */ #if defined(CONFIG_MEDIA_CONTROLLER) imx291->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &imx291->pad); if (ret < 0) goto err_power_off; #endif ... ret = v4l2_async_register_subdev_sensor_common(sd); if (ret) { dev_err(dev, "v4l2 async register subdev failedn"); goto err_clean_entity; } return 0; ... } imx291_probe -> v4l2_async_register_subdev_sensor_common int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd) { /* * 这里都是使用的异步的方式 * 都是A完成了再通知B */ struct v4l2_async_notifier *notifier; int ret; if (WARN_ON(!sd->dev)) return -ENODEV; notifier = kzalloc(sizeof(*notifier), GFP_KERNEL); if (!notifier) return -ENOMEM; /* * 这里主要解析dts中有没有指定以下3种设备 * 1. flash-leds 闪光灯 * 2. lens-focus 聚焦设备 * 3. ir-cut 红外滤镜 * 这些imx291都没有,忽略 */ ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev, notifier); if (ret < 0) goto out_cleanup; /* 主要就是将notifier挂载到链表notifier_list上 */ ret = v4l2_async_subdev_notifier_register(sd, notifier); if (ret < 0) goto out_cleanup; ret = v4l2_async_register_subdev(sd); if (ret < 0) goto out_unregister; /* subdev和notifier你中有我,我中有你 */ sd->subdev_notifier = notifier; return 0; } imx291_probe -> v4l2_async_register_subdev_sensor_common -> v4l2_async_subdev_notifier_register int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd, struct v4l2_async_notifier *notifier) { int ret; if (WARN_ON(!sd || notifier->v4l2_dev)) return -EINVAL; /* * 记录subdev */ notifier->sd = sd; /* 异步通知注册 主要就是操作notifier */ 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; INIT_LIST_HEAD(¬ifier->waiting); INIT_LIST_HEAD(¬ifier->done); ... /* * num_subdevs值为0,所以这里的for语句分析 */ for (i = 0; i < notifier->num_subdevs; i++) { ... } /* * 条件不满足,暂时不进入分析,不满足原因如下 * 1. notifier->parent == NULL * 2. notifier->v4l2_dev == NULL */ ret = v4l2_async_notifier_try_all_subdevs(notifier); if (ret < 0) goto err_unbind; /* * 条件不满足,暂时不进入分析,不满足原因如下 * 1. notifier->parent == NULL * 2. notifier->v4l2_dev == NULL */ ret = v4l2_async_notifier_try_complete(notifier); if (ret < 0) goto err_unbind; /* * 以上2个函数可以看出来,v4l2_dev为空时都不会执行 * 将这个notifer挂载到链表notifier_list上 */ /* Keep also completed notifiers on the list */ list_add(¬ifier->list, ¬ifier_list); mutex_unlock(&list_lock); return 0; imx291_probe -> v4l2_async_register_subdev_sensor_common -> v4l2_async_subdev_notifier_register -> v4l2_async_register_subdev int v4l2_async_register_subdev(struct v4l2_subdev *sd) { struct v4l2_async_notifier *subdev_notifier; struct v4l2_async_notifier *notifier; int ret; /* * No reference taken. The reference is held by the device * (struct v4l2_subdev.dev), and async sub-device does not * exist independently of the device at any point of time. */ if (!sd->fwnode && sd->dev) sd->fwnode = dev_fwnode(sd->dev); mutex_lock(&list_lock); INIT_LIST_HEAD(&sd->async_list); /* * 目前为止notifier_list上只有一个notifer * v4l2_dev上面说过为NULL * 所以这个循环可以退出了,没有实质性的动作 */ list_for_each_entry(notifier, ¬ifier_list, list) { struct v4l2_device *v4l2_dev = v4l2_async_notifier_find_v4l2_dev(notifier); struct v4l2_async_subdev *asd; if (!v4l2_dev) continue; ... } /* None matched, wait for hot-plugging */ /* * 没有匹配到相关的信息 * 将subdev挂载到subdev_list上 */ list_add(&sd->async_list, &subdev_list); } 以上就是imx291的注册过程,注意这里的分析认为是按照一定的顺序注册的,就是imx291--> mipi csi phy --> mipi csi --> rkcif_mipi这种注册顺序 总结一下imx291的注册都做了什么
这里并没有想象中的直接去注册v4l-subdev的节点,看来是需要一定的契机才会注册 请看后面分析。。。 |
|
|
|
imx291的dts配置如下
imx291: imx291@1a { compatible = "sony,imx291"; status = "okay"; reg = <0x1a>; ... port { ucam_out2: endpoint { remote-endpoint = <&mipi_in_ucam0>; data-lanes = <1 2 3 4>; }; }; }; 对于endpoint这里先忽略 下面分析驱动 imx291_probe struct imx291 { struct i2c_client *client; ... struct v4l2_subdev subdev; struct media_pad pad; ... bool streaming; bool power_on; ... }; static int imx291_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct device_node *node = dev->of_node; struct imx291 *imx291; struct v4l2_subdev *sd; int ret; imx291 = devm_kzalloc(dev, sizeof(*imx291), GFP_KERNEL); if (!imx291) return -ENOMEM; ... imx291->client = client; ... sd = &imx291->subdev; /* * v4l2_i2c_subdev_init这里不展开分析 * 主要记录一下几点 * sd->ops = &imx291_subdev_ops; * sd->v4l2_dev = NULL; * sd->flags = V4L2_SUBDEV_FL_IS_I2C */ v4l2_i2c_subdev_init(sd, client, &imx291_subdev_ops); /* * 对于controls这里先不分析 * 后面有专题进行分析 */ ret = imx291_initialize_controls(imx291); if (ret) goto err_probe; /* * 这个配置开启了 * 下面这个成员值都先记住就好 */ #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API sd->internal_ops = &imx291_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; #endif /* * media这里也先不分析 * 后面专题 */ #if defined(CONFIG_MEDIA_CONTROLLER) imx291->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &imx291->pad); if (ret < 0) goto err_power_off; #endif ... ret = v4l2_async_register_subdev_sensor_common(sd); if (ret) { dev_err(dev, "v4l2 async register subdev failedn"); goto err_clean_entity; } return 0; ... } imx291_probe -> v4l2_async_register_subdev_sensor_common int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd) { /* * 这里都是使用的异步的方式 * 都是A完成了再通知B */ struct v4l2_async_notifier *notifier; int ret; if (WARN_ON(!sd->dev)) return -ENODEV; notifier = kzalloc(sizeof(*notifier), GFP_KERNEL); if (!notifier) return -ENOMEM; /* * 这里主要解析dts中有没有指定以下3种设备 * 1. flash-leds 闪光灯 * 2. lens-focus 聚焦设备 * 3. ir-cut 红外滤镜 * 这些imx291都没有,忽略 */ ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev, notifier); if (ret < 0) goto out_cleanup; /* 主要就是将notifier挂载到链表notifier_list上 */ ret = v4l2_async_subdev_notifier_register(sd, notifier); if (ret < 0) goto out_cleanup; ret = v4l2_async_register_subdev(sd); if (ret < 0) goto out_unregister; /* subdev和notifier你中有我,我中有你 */ sd->subdev_notifier = notifier; return 0; } imx291_probe -> v4l2_async_register_subdev_sensor_common -> v4l2_async_subdev_notifier_register int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd, struct v4l2_async_notifier *notifier) { int ret; if (WARN_ON(!sd || notifier->v4l2_dev)) return -EINVAL; /* * 记录subdev */ notifier->sd = sd; /* 异步通知注册 主要就是操作notifier */ 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; INIT_LIST_HEAD(¬ifier->waiting); INIT_LIST_HEAD(¬ifier->done); ... /* * num_subdevs值为0,所以这里的for语句分析 */ for (i = 0; i < notifier->num_subdevs; i++) { ... } /* * 条件不满足,暂时不进入分析,不满足原因如下 * 1. notifier->parent == NULL * 2. notifier->v4l2_dev == NULL */ ret = v4l2_async_notifier_try_all_subdevs(notifier); if (ret < 0) goto err_unbind; /* * 条件不满足,暂时不进入分析,不满足原因如下 * 1. notifier->parent == NULL * 2. notifier->v4l2_dev == NULL */ ret = v4l2_async_notifier_try_complete(notifier); if (ret < 0) goto err_unbind; /* * 以上2个函数可以看出来,v4l2_dev为空时都不会执行 * 将这个notifer挂载到链表notifier_list上 */ /* Keep also completed notifiers on the list */ list_add(¬ifier->list, ¬ifier_list); mutex_unlock(&list_lock); return 0; imx291_probe -> v4l2_async_register_subdev_sensor_common -> v4l2_async_subdev_notifier_register -> v4l2_async_register_subdev int v4l2_async_register_subdev(struct v4l2_subdev *sd) { struct v4l2_async_notifier *subdev_notifier; struct v4l2_async_notifier *notifier; int ret; /* * No reference taken. The reference is held by the device * (struct v4l2_subdev.dev), and async sub-device does not * exist independently of the device at any point of time. */ if (!sd->fwnode && sd->dev) sd->fwnode = dev_fwnode(sd->dev); mutex_lock(&list_lock); INIT_LIST_HEAD(&sd->async_list); /* * 目前为止notifier_list上只有一个notifer * v4l2_dev上面说过为NULL * 所以这个循环可以退出了,没有实质性的动作 */ list_for_each_entry(notifier, ¬ifier_list, list) { struct v4l2_device *v4l2_dev = v4l2_async_notifier_find_v4l2_dev(notifier); struct v4l2_async_subdev *asd; if (!v4l2_dev) continue; ... } /* None matched, wait for hot-plugging */ /* * 没有匹配到相关的信息 * 将subdev挂载到subdev_list上 */ list_add(&sd->async_list, &subdev_list); } 以上就是imx291的注册过程,注意这里的分析认为是按照一定的顺序注册的,就是imx291--> mipi csi phy --> mipi csi --> rkcif_mipi这种注册顺序 总结一下imx291的注册都做了什么 填充了subdev的相关成员信息 sd->ops = &imx291_subdev_ops; sd->v4l2_dev = NULL; sd->flags = V4L2_SUBDEV_FL_IS_I2C 创建了notifier关联subdev,并将notifier挂载到链表notifier_list上 subdev挂载到subdev_list上 这里并没有想象中的直接去注册v4l-subdev的节点,看来是需要一定的契机才会注册 请看后面分析。。。 |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
基于米尔瑞芯微RK3576核心板/开发板的人脸疲劳检测应用方案
1309 浏览 0 评论
1457 浏览 1 评论
1139 浏览 1 评论
2467 浏览 1 评论
3737 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-2 03:33 , Processed in 0.525271 second(s), Total 76, Slave 58 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号