LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

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);

posted on 2024-04-17 23:59  ArnoldLu  阅读(720)  评论(0编辑  收藏  举报

导航