介绍
日期 | 作者 | 说明 |
---|---|---|
2024/04/04 | Manfredxxc | 初版 |
内核版本:kernel-4.1.15
参考源码:drivers/media/platform/omap3isp/isp.c
在v4l2框架里struct v4l2_device
代表了一个video设备;相应的,struct v4l2_subdev
代表video设备下的子设备,如csi、isp、sensor等
下图是v4l2_device
与v4l2_subdev
之间的拓扑结构示例,所有的子设备都链接在链表上(v4l2_device->subdevs
)
输入设备
数据类型简要说明
struct v4l2_device
一般嵌入一个更大的私有结构体,构成一个video输入设备
struct isp_device {
struct v4l2_device v4l2_dev; // 该结构体的嵌入,构成一个omap3isp设备
struct v4l2_async_notifier notifier; // 用于异步注册v4l2_device
struct media_device media_dev; // 用于media framework
struct device *dev;
}
struct v4l2_device {
struct device *dev; // 赋值为isp->dev
struct list_head *subdevs; // 由子设备组成的链表
}
API简要说明
v4l2_device_register
- 描述:注册一个v4l2输入设备,让
@dev->driver_data 指向 @v4l2_dev
- 原型:
int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
子设备
数据结构简要说明
struct v4l2_subdev
一般嵌入到一个更大的私有结构体,构成一个子设备
struct isp_csi2_device {
struct v4l2_subdev subdev; // 该结构体的嵌入,构成一个csi2子设备
}
struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
#endif
struct list_head list; // 子设备链表
u32 flags; // I2C|SPI|DEVNODE|EVENTS 标记子设备类型(i2c/spi)| 需要创建子设备节点/dev/v4l-subdev<X> | 子设备可创建事件
struct v4l2_device *v4l2_dev; // 指向绑定的v4l2_device
const struct v4l2_subdev_ops *ops; // 子设备支持的操作
const struct v4l2_subdev_internal_ops *internal_ops; // 内部操作 registered | unregistered | open | close | release 时触发
char name[V4L2_SUBDEV_NAME_SIZE]; // 唯一的子设备名
u32 grp_id; // 归类子设备
void *dev_priv; // 指向私有数据 v4l2_set_subdevdata()/v4l2_get_subdevdata()
void *host_priv; // 指向子设备连接的设备使用的私有数据 v4l2_set_subdev_hostdata()/v4l2_get_subdev_hostdata()
}
API简要说明
v4l2_subdev_init
- 描述:初始化一个
struct v4l2_subdev
- 原型:
void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
v4l2_device_register_subdev
- 描述:向v4l2输入设备注册一个子设备
- 原型:
int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd)
- 参数:NA
-
将sd->ctrl_hander
纳入v4l2_dev
统一管理注册一个media_entity
- 调用
sd->internal_ops->registered(sd)
(如果存在) - 将
sd
链接到v4l2_dev->subdevs
层次结构
访问
video输入设备(struct isp)、子设备(struct isp_csi2_device)、v4l2_dev(struct v4l2_device)、sd(struct v4l2_subdev)
- v4l2_dev => sd
按子设备名遍历链表即可 - v4l2_dev => 输入设备
container_of(v4l2_dev, struct isp, v4l2_dev)
- sd => v4l2_dev
sd->v4l2_dev
- sd => 子设备
v4l2_get_subdevdata(sd)
信息交流
- 访问子设备并执行相应操作
v4l2_device_call_all
- 描述:对符合条件(
@group_id == sd->grpid
)的子设备调用o->f(args)
- 原型:
v4l2_device_call_all(v4l2_dev, grpid, o, f, args...)
- 描述:对符合条件(
- 子设备通知v4l2_dev
需要实现v4l2_dev->notify()
,子设备在需要时调用v4l2_subdev_notify()
通知v4l2_dev
v4l2_subdev_notify
- 描述:通知
v4l2_device
- 原型:
static inline void v4l2_subdev_notify(struct v4l2_subdev *sd, unsigned int notification, void *arg)
- 参数:
- @sd:指向
&struct v4l2_subdev
- @notification:驱动自定义的通知类型
- @arg:配合@notification使用的参数
- @sd:指向
- 使用:在
v4l2_dev->notify()
中,根据notification
执行不同的操作
- 描述:通知
节点注册
节点注册最终都是通过调用__video_register_device()
,需要一个struct video_device
,会根据vfl_devnode_type
创建不同类型的节点
存在如下类型:
- video
- vbi
- ratio
- v4l-subdev
- swradio
- v4l-touch
本文主要分析v4l2_device/subdev,这里提下v4l-subdev类型节点的注册:
v4l2_device_register_subdev_nodes
- 描述:为该v4l2_dev上的所有标记为
V4L2_SUBDEV_FL_HAD_DEVNODE
的子设备创建节点/dev/v4l-subdev - 原型:
int __must_check v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
- 不需要用户提供fops:
open/close
使用sd->internal_ops->open/close
,其余由v4l2核心层支持