Linux v4l2架构学习总链接
imx291源码
imx291的dts配置如下
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14imx291: 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
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91struct 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
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49int 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
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81int 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
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46int 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分析内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复