Linux Media子系统:Media Controller设备
关键词:Media、Device、Entity、Pad、Link、Interface、Graph、Pipeline等等。
Media Framework一个目的是发现设备内部拓扑结构,并对其进行运行时配置。
为此硬件被被抽象为通过Pad连接的Entity,Pad之间的连接称为Link。
1 Media子系统初始化
Media子系统初始化:
- 分配Media字符设备号区间。
- 注册Media总线。
static int __init media_devnode_init(void) { ... ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES, MEDIA_NAME); ... ret = bus_register(&media_bus_type); ... return 0; }
2 Media Device及其抽象模型
2.1 media_device数据结构以及API
struct media_device是一个Media设备的抽象
struct media_device { /* dev->driver_data points to this struct. */ struct device *dev; struct media_devnode *devnode;--此media_device对应的device节点相关信息。 char model[32]; char driver_name[32]; char serial[40]; char bus_info[32]; u32 hw_revision; u64 topology_version; u32 id; struct ida entity_internal_idx; int entity_internal_idx_max; struct list_head entities;--此media_device注册的Entity列表。 struct list_head interfaces;--media_device注册的Interface列表。 struct list_head pads;--此media_device注册的Pad列表。 struct list_head links;--此media_device注册的Link列表。 ... struct media_graph pm_count_walk; void *source_priv; int (*enable_source)(struct media_entity *entity, struct media_pipeline *pipe); void (*disable_source)(struct media_entity *entity); const struct media_device_ops *ops; struct mutex req_queue_mutex; atomic_t request_id; };
struct media_devnode包含media_device相关的device设备、字符设备等,其中media_file_operations是file_operations的部分实现:
struct media_devnode { struct media_device *media_dev;--关联的media_device结构。 /* device ops */ const struct media_file_operations *fops; /* sysfs */ struct device dev; /* media device */ struct cdev cdev; /* character device */ struct device *parent; /* device parent */ /* device info */ int minor; unsigned long flags; /* Use bitops to access flags */ /* callbacks */ void (*release)(struct media_devnode *devnode); };
struct media_file_operations { struct module *owner; ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); __poll_t (*poll) (struct file *, struct poll_table_struct *); long (*ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*open) (struct file *); int (*release) (struct file *); };
对media_device的初始化和注册API如下:
void media_device_init(struct media_device *mdev); void media_device_cleanup(struct media_device *mdev); int __must_check __media_device_register(struct media_device *mdev, struct module *owner); void media_device_unregister(struct media_device *mdev);
__media_device_register:
- 分配一个struce media_devnode并进行初始化,操作函数集为media_device_fops。
- 创建mediaX设备。
__media_device_register
->分配struct media_devnode,并初始化操作函数集为media_device_fops,释放函数为media_device_release。
->media_devnode_register
->找到空闲minor号。
->初始化mediaX设备节点,位于media_bus_type总线上。
->初始化mediaX字符设备,操作函数集为media_devnode_fops。
->注册字符设备。
->标志位置位MEDIA_FLAG_REGISTERED。
->device_create_file--创建设备节点,并创建model属性节点。
对/dev/mediaX设备的系统调用,落到对media_devnode_fops成员调用,进而部分落到对media_device_fops调用。
static const struct media_file_operations media_device_fops = {--仅支持open/release/ioctl调用。 .owner = THIS_MODULE, .open = media_device_open, .ioctl = media_device_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = media_device_compat_ioctl, #endif /* CONFIG_COMPAT */ .release = media_device_close, }; static const struct file_operations media_devnode_fops = { .owner = THIS_MODULE, .read = media_read, .write = media_write, .open = media_open, .unlocked_ioctl = media_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = media_compat_ioctl, #endif /* CONFIG_COMPAT */ .release = media_release, .poll = media_poll, .llseek = no_llseek, };
2.2 Media Graph模型成员
Media子系统将系统抽象成如下几个成员:
- Entity:struct media_entity是对硬件抽象。
- Pad:struct media_pad是对端口抽象,有Sink Pad和Source Pad两种。
- Link:struct media_link是对两个Pad之间的连接的抽象。
- Interface:struct media_interface是对Entity和其对应的Device Node之间的关联的抽象。
如下为一个Media Graph实例图:
- rkcif-mipi-lvds2是Entity,/dev/v4l-subdev4是Device node,rkcif-mipi-lvds2跟/dev/v4l-subdev4之间的接口为Interface。
- Entity输入口为Sink Pad;输出口为Source Pad;Source Pad到Sink Pad之间的连接为Link。
struct media_gobj表示表示Media Graph上的一个对象:
struct media_gobj { struct media_device *mdev; u32 id; struct list_head list; };
Graph Object的API:
void media_gobj_create(struct media_device *mdev, enum media_gobj_type type, struct media_gobj *gobj); void media_gobj_destroy(struct media_gobj *gobj);
2.2.1 Entity
struct media_entity表示Media Graph上的Entity对象:
struct media_entity { struct media_gobj graph_obj; /* must be first field in struct */ const char *name; enum media_entity_type obj_type; u32 function; unsigned long flags; u16 num_pads;--Pad数量。 u16 num_links;--总Link数量。 u16 num_backlinks; int internal_idx; struct media_pad *pads;--属下的Pad列表。 struct list_head links; const struct media_entity_operations *ops; int stream_count; int use_count; struct media_pipeline *pipe;--Pipeline实例。 union { struct { u32 major; u32 minor; } dev; } info; };
2.2.2 Pad
struct media_pad表示Media Graph上的Pad对象,其隶属于某一个Entity:
struct media_pad { struct media_gobj graph_obj; /* must be first field in struct */ struct media_entity *entity;--此Pad所属的Entity。 u16 index;--在Entity的Pad列表中序号。 enum media_pad_signal_type sig_type; unsigned long flags; };
Pad相关API:
int media_entity_pads_init(struct media_entity *entity, u16 num_pads, struct media_pad *pads); int media_get_pad_index(struct media_entity *entity, bool is_sink, enum media_pad_signal_type sig_type); struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
2.2.3 Link
struct media_link表示Media Graph上的Link对象:
- 如果Link是Entity的Pad之间,Link连接两个Pad。称为Data Link。
- 如果Link是Entity和Interface之间,Link一端是Interface另一端是Entity。称为Interface Link。
struct media_link { struct media_gobj graph_obj; struct list_head list;--指向拥有此Link的Entity或者Interface。 union { struct media_gobj *gobj0; struct media_pad *source;--表示当前Link对应的Source Pad。 struct media_interface *intf;--表示当前Link对应的Interface。 }; union { struct media_gobj *gobj1; struct media_pad *sink;--表示当前Link的Sink Pad。 struct media_entity *entity;--表示当前Link对应的Entity。 }; struct media_link *reverse; unsigned long flags; bool is_backlink; ANDROID_VENDOR_DATA(1); };
Link相关API:
__must_check int media_create_pad_link(struct media_entity *source, u16 source_pad, struct media_entity *sink, u16 sink_pad, u32 flags); int media_create_pad_links(const struct media_device *mdev, const u32 source_function, struct media_entity *source, const u16 source_pad, const u32 sink_function, struct media_entity *sink, const u16 sink_pad, u32 flags, const bool allow_both_undefined); void media_entity_remove_links(struct media_entity *entity); int media_entity_setup_link(struct media_link *link, u32 flags); struct media_link *media_entity_find_link(struct media_pad *source, struct media_pad *sink);
2.2.4 Interface
struct media_interface表示Media Graph上的Interface对象,其将Entity和Device node连接起来:
struct media_interface { struct media_gobj graph_obj; struct list_head links; u32 type; u32 flags; };
struct media_intf_devnode表示一个Media Interface和Device node的连接:
struct media_intf_devnode { struct media_interface intf; /* Should match the fields at media_v2_intf_devnode */ u32 major; u32 minor; };
Interface相关API:
__must_check media_create_intf_link(struct media_entity *entity, struct media_interface *intf, u32 flags); void media_remove_intf_link(struct media_link *link); void media_remove_intf_links(struct media_interface *intf);
3 Media Graph遍历
struct media_graph表示一个Media Graph中Entity的连接关系:
struct media_graph {
struct {
struct media_entity *entity;--指向当前Media Graph的Entity。
struct list_head *link;--指向到达此Entity的Link。
} stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
struct media_entity_enum ent_enum;
int top;
};
对Media Device进行Graph遍历的API包括:
__must_check int media_graph_walk_init( struct media_graph *graph, struct media_device *mdev); void media_graph_walk_cleanup(struct media_graph *graph); void media_graph_walk_start(struct media_graph *graph, struct media_entity *entity); struct media_entity *media_graph_walk_next(struct media_graph *graph);
进行Media Graph遍历的流程如下:
- media_graph_walk_init():分配Graph遍历相关资源。
- media_graph_walk_start():选择一个Entity,开始进行Graph遍历。
- media_graph_walk_next():查找下一个Entity,知道返回NULL表示结束。
- 通过media_entity_find_link()找到当前Link,通过media_entity_remote_pad()找对Link远端Pad。
- media_graph_walk_cleanup():释放media_graph资源。
4 Pipeline
struct media_pipeline表示一个Media Graph中的数据流:
struct media_pipeline { int streaming_count; struct media_graph graph; };
在Media Graph中可能存在多种Link可能性,
__must_check int media_pipeline_start(struct media_entity *entity, struct media_pipeline *pipe); void media_pipeline_stop(struct media_entity *entity);