我是靠谱客的博主 受伤大炮,最近开发中收集的这篇文章主要介绍基于RV1126平台imx291分析 --- imx291注册Linux v4l2架构学习总链接,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
Linux v4l2架构学习总链接
imx291源码
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的节点,看来是需要一定的契机才会注册
请看后面分析。。。
最后
以上就是受伤大炮为你收集整理的基于RV1126平台imx291分析 --- imx291注册Linux v4l2架构学习总链接的全部内容,希望文章能够帮你解决基于RV1126平台imx291分析 --- imx291注册Linux v4l2架构学习总链接所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复