系列文章:
Linux V4L2驱动框架分析之(一):架构介绍
Linux V4L2驱动框架分析之(二):平台v4l2设备驱动
Linux V4L2驱动框架分析之(三):v4l2设备的缓存管理
Linux V4L2驱动框架分析之(四):sensor驱动
为了实现代码的重用,sensor驱动只需实现各种设备控制方法供上层调用并注册v4l2_subdev,而无需关心video_device和v4l2_dev。
struct v4l2_subdev结构体定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23struct v4l2_subdev { ...... struct list_head list; //用于挂入v4l2_dev的subdevs链表 struct module *owner; bool owner_v4l2_dev; u32 flags; struct v4l2_device *v4l2_dev; const struct v4l2_subdev_ops *ops; //操作集 ...... char name[V4L2_SUBDEV_NAME_SIZE]; ...... struct video_device *devnode; struct device *dev; struct device_node *of_node; struct list_head async_list; struct v4l2_async_subdev *asd; struct v4l2_async_notifier *notifier; struct v4l2_subdev_platform_data *pdata; };
如果说v4l2_subdev是个i2c设备,可调用v4l2_i2c_subdev_init函数初始化v4l2_subdev:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, const struct v4l2_subdev_ops *ops) { //初始化v4l2_subdev里的ops等 v4l2_subdev_init(sd, ops); sd->flags |= V4L2_SUBDEV_FL_IS_I2C; sd->owner = client->dev.driver->owner; sd->dev = &client->dev; v4l2_set_subdevdata(sd, client); i2c_set_clientdata(client, sd); /* initialize name */ snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", client->dev.driver->name, i2c_adapter_id(client->adapter), client->addr); }
struct v4l2_subdev_ops结构体定义如下:
1
2
3
4
5
6
7struct v4l2_subdev_ops { const struct v4l2_subdev_core_ops *core; const struct v4l2_subdev_video_ops *video; const struct v4l2_subdev_pad_ops *pad; ...... };
对于sensor,一般要实现struct v4l2_subdev_ops的core、video和pad成员。
struct v4l2_subdev_video_ops结构体定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19struct v4l2_subdev_video_ops { ...... //获取当前正在使用的标准 int (*g_std)(struct v4l2_subdev *sd, v4l2_std_id *norm); //设置视频标准 int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm); int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std); int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); int (*g_frame_interval)(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval); int (*s_frame_interval)(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval); ...... };
如应用层要获取v4l2设备当前正在使用的视频标准,会"ioctl /dev/video0",ioctl传入到平台驱动层,那么平台驱动可以调用v4l2_subdev->ops->video->g_std回调函数获取sensor的视频标准。
设置好v4l2_subdev后,调用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
30int v4l2_async_register_subdev(struct v4l2_subdev *sd) { struct v4l2_async_notifier *notifier; if (!sd->of_node && sd->dev) sd->of_node = sd->dev->of_node; mutex_lock(&list_lock); INIT_LIST_HEAD(&sd->async_list); //匹配v4l2_device,具体怎么匹配后面在分析 list_for_each_entry(notifier, ¬ifier_list, list) { struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd); if (asd) { int ret = v4l2_async_test_notify(notifier, sd, asd); mutex_unlock(&list_lock); return ret; } } /* 未匹配则挂入全局链表subdev_list */ list_add(&sd->async_list, &subdev_list); mutex_unlock(&list_lock); return 0; }
对于未匹配的v4l2_subdev会挂入全局链表subdev_list:
为了能让平台v4l2设备驱动能匹配到sensor驱动注册的v4l2_subdev,平台驱动需要注册一个struct v4l2_async_notifier:
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
53struct v4l2_async_notifier { unsigned int num_subdevs; //需要匹配v4l2_subdev的数目 struct v4l2_async_subdev **subdevs; //v4l2_async_subdev数组 struct v4l2_device *v4l2_dev; struct list_head waiting; struct list_head done; struct list_head list; //与v4l2_subdev匹配后,调用bound回调 int (*bound)(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd); int (*complete)(struct v4l2_async_notifier *notifier); void (*unbind)(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd); }; struct v4l2_async_subdev { //匹配类型 enum v4l2_async_match_type match_type; union { struct { const struct device_node *node; //设备节点匹配 } of; struct { const char *name; //名称匹配 } device_name; struct { int adapter_id; unsigned short address; //i2c设备地址匹配 } i2c; struct { bool (*match)(struct device *, struct v4l2_async_subdev *); void *priv; } custom; } match; /* v4l2-async core private: not to be used by drivers */ struct list_head list; }; //匹配类型 enum v4l2_async_match_type { V4L2_ASYNC_MATCH_CUSTOM, V4L2_ASYNC_MATCH_DEVNAME, V4L2_ASYNC_MATCH_I2C, V4L2_ASYNC_MATCH_OF, };
平台v4l2设备驱动设置好struct v4l2_async_notifier后,调用v4l2_async_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
57int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, struct v4l2_async_notifier *notifier) { struct v4l2_subdev *sd, *tmp; struct v4l2_async_subdev *asd; int i; ...... notifier->v4l2_dev = v4l2_dev; INIT_LIST_HEAD(¬ifier->waiting); INIT_LIST_HEAD(¬ifier->done); for (i = 0; i < notifier->num_subdevs; i++) { asd = notifier->subdevs[i]; switch (asd->match_type) { case V4L2_ASYNC_MATCH_CUSTOM: case V4L2_ASYNC_MATCH_DEVNAME: case V4L2_ASYNC_MATCH_I2C: case V4L2_ASYNC_MATCH_OF: break; default: ...... return -EINVAL; } //把v4l2_async_subdev都挂入v4l2_async_notifier的waiting链表 list_add_tail(&asd->list, ¬ifier->waiting); } mutex_lock(&list_lock); /* 把v4l2_async_notifier挂入全局链表notifier_list */ list_add(¬ifier->list, ¬ifier_list); //遍历subdev_list链表 list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) { int ret; //进行匹配 asd = v4l2_async_belongs(notifier, sd); if (!asd) continue; ret = v4l2_async_test_notify(notifier, sd, asd); if (ret < 0) { mutex_unlock(&list_lock); return ret; } } mutex_unlock(&list_lock); return 0; }
调用v4l2_async_belongs函数进行匹配:
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
45static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd) { bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *); struct v4l2_async_subdev *asd; //从v4l2_async_notifier的waiting链表取出每项v4l2_async_subdev list_for_each_entry(asd, ¬ifier->waiting, list) { /* bus_type has been verified valid before */ switch (asd->match_type) { case V4L2_ASYNC_MATCH_CUSTOM: match = match_custom; break; case V4L2_ASYNC_MATCH_DEVNAME: match = match_devname; break; case V4L2_ASYNC_MATCH_I2C: match = match_i2c; break; case V4L2_ASYNC_MATCH_OF: match = match_of; break; default: /* Cannot happen, unless someone breaks us */ WARN_ON(true); return NULL; } /* 调用match进行v4l2_async_subdev与v4l2_subdev的匹配,不同的匹配类型 match回调函数不一样 */ if (match(sd, asd)) return asd; } return NULL; } //对于V4L2_ASYNC_MATCH_OF类型,match为match_of static bool match_of(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { return sd->of_node == asd->match.of.node; //判断设备节点是否一致 }
匹配成功后调用v4l2_async_test_notify:
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
37static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { int ret; /* Remove from the waiting list */ list_del(&asd->list); //设置v4l2_subdev的asd、notifier sd->asd = asd; sd->notifier = notifier; if (notifier->bound) { ret = notifier->bound(notifier, sd, asd); //回调v4l2_async_notifier的bound if (ret < 0) return ret; } /* Move from the global subdevice list to notifier's done */ list_move(&sd->async_list, ¬ifier->done); //把v4l2_subdev挂入v4l2_device的subdevs链表 ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd); if (ret < 0) { if (notifier->unbind) notifier->unbind(notifier, sd, asd); return ret; } if (list_empty(¬ifier->waiting) && notifier->complete) return notifier->complete(notifier); return 0; }
匹配前:
匹配后:
最后
以上就是寂寞篮球最近收集整理的关于Linux V4L2驱动框架分析之(四):sensor驱动的全部内容,更多相关Linux内容请搜索靠谱客的其他文章。
发表评论 取消回复