Chinaunix首页 | 论坛 | 博客
  • 博客访问: 311260
  • 博文数量: 101
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 774
  • 用 户 组: 普通用户
  • 注册时间: 2018-10-15 14:13
个人简介

搭建一个和linux开发者知识共享和学习的平台

文章分类

全部博文(101)

文章存档

2024年(15)

2023年(24)

2022年(27)

2019年(8)

2018年(27)

分类: 嵌入式

2024-10-22 11:31:47

V4l2 async框架介绍
v4l2 async框架是Linux V4L2框架中的一个子框架,用于实现v4l2 device的异步注册。Linux V4L2框架中对设备定义分为:v4l2_device和v4l2_subdev, 设备是有从属概念的,v4l2 device之间是可以存在依赖关系的。v4l2 async框架主要就是为了解决这种乱序异步注册问题,保证一个v4l2 device的上一层的被依赖设备注册后注册这个v4l2 device。按依赖链自上而下完成注册。


v4l2 async框架定义两个角色,3个概念:

v4l2_async_subdev  //async的桥。是异步通知到对端的桥。notifier通过这个桥知道异步操作的对端是谁。notifier持有桥(其实是怎么match)。
v4l2_async_notifier  //v4l2 async框架中的重要角色,是绑定动作的发起者(该角色需要实现v4l2_async框架定义接口:bound, complete, unbind)。
v4l2_subdev  //async通知给谁。是通知桥连接的对端。


v4l2 async框架是围绕两个链表来实现异步处理的:

static LIST_HEAD(notifier_list)  //注册到v4l2 async框架的没有完成bind操作的v4l2_async_notifier.
static LIST_HEAD(subdev_list)  //注册到v4l2 async框架的没有bind的对端。


对端向v4l2 async框架注册的两种情况:

情况1:桥连接的对端先注册,notifier还没注册到v4l2 async框架。这时找不到匹配的桥,不能触发notifier bind流程,这个对端(v4l2_subdev)会被记录到subdev_list。
情况2:桥连接的对端注册之前notifier已经注册到v4l2 async框架。这时能找到匹配的桥,将触发notifier bind流程。如果异步处理完成,这个对端其实是不会进入subdev_list。


如何使用v4l2 async框架实现一个camera系统(基于Linux V4L2框架实现)异步处理:

首先,确定camera系统中哪些模块充当v4l2_async_notifier, 哪些模块充当v4l2_subdev,即确定模块的主从关系。
其次,对于充当v4l2_async_notifier角色的模块需要实现相应的异步处理回调接口(struct v4l2_async_notifier_operations数据结构定义框架接口,自己根据实际情况实现需要的接口就可以)
然后,根据实际情况定义n个notifier match桥。(桥有x种,调用v4l2_async_notifier_add_xx_remote_subdev接口将一个桥添加到notifier)
{BANNED}{BANNED}最佳佳后,调用将async notifier和v4l2_subdev向v4l2_async框架注册。此时v4l2_async框架会根据v4l2 device设备的注册情况完成异步bind。


v4l2 async框架定义接口

主要是3个数据结构:v4l2_async_notifier, v4l2_async_subdev和v4l2_async_notifier_operations
/**
  * struct v4l2_async_notifier - v4l2_device notifier data
  *
  * @ops:    notifier operations
  * @v4l2_dev:   v4l2_device of the root notifier, NULL otherwise
  * @sd:     sub-device that registered the notifier, NULL otherwise
  * @parent: parent notifier
  * @asd_list:   master list of struct v4l2_async_subdev
  * @waiting:    list of struct v4l2_async_subdev, waiting for their drivers
  * @done:   list of struct v4l2_subdev, already probed
  * @list:   member in a global list of notifiers
  */
struct v4l2_async_notifier {
    const struct v4l2_async_notifir_operations *ops;
    struct v4l2_device *v4l2_dev; //root notifier的v4l2_device
    struct v4l2_subdev *sd;    //这个notifier注册到sub-device
    struct v4l2_async_notifier *parent;
    struct list_head asd_list;//
    struct list_head waiting;//等待他们的drivers的v4l2_async_subdev链表
    struct list_head done;   //已经probed的v4l2_subdev链表
    struct list_head list;   //用于将这个notifier串到v4l2_async框架的全局链表notifier中。
};
 
/**
  * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
  *
  * @match_type: type of match that will be used
  * @match:  union of per-bus type matching data sets
  * @match.fwnode:
  *      pointer to &struct fwnode_handle to be matched.
  *      Used if @match_type is %V4L2_ASYNC_MATCH_FWNODE.
  * @match.device_name:
  *      string containing the device name to be matched.
  *      Used if @match_type is %V4L2_ASYNC_MATCH_DEVNAME.
  * @match.i2c:  embedded struct with I2C parameters to be matched.
  *      Both @match.i2c.adapter_id and @match.i2c.address
  *      should be matched.
  *      Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
  * @match.i2c.adapter_id:
  *      I2C adapter ID to be matched.
  *      Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
  * @match.i2c.address:
  *      I2C address to be matched.
  *      Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
  * @match.custom:
  *      Driver-specific match criteria.
  *      Used if @match_type is %V4L2_ASYNC_MATCH_CUSTOM.
  * @match.custom.match:
  *      Driver-specific match function to be used if
  *      %V4L2_ASYNC_MATCH_CUSTOM.
  * @match.custom.priv:
  *      Driver-specific private struct with match parameters
  *      to be used if %V4L2_ASYNC_MATCH_CUSTOM.
  * @asd_list:   used to add struct v4l2_async_subdev objects to the
  *      master notifier @asd_list
  * @list:   used to link struct v4l2_async_subdev objects, waiting to be
  *      probed, to a notifier->waiting list
  *
  * When this struct is used as a member in a driver specific struct,
  * the driver specific struct shall contain the &struct
  * v4l2_async_subdev as its first member.
  */
struct v4l2_async_subdev {
    enum v4l2_async_match_type match_type;
    union {
        struct fwnode_handle *fwnode;
        const char *device_name;
        struct {
            int adapter_id;
            unsigned short address;
        }i2c;
        struct {
            bool (*match)(struct device *dev,
                    struct v4l2_async_subdev *sd);
            void *priv;
        }custom;
    }match;
    
    /* v4l2-async core private: not to be used by drivers */
    struct list_head list;
    struct list_head asd_list;
};
 
/**
 * @bound: a subdevice driver has successfully probed one of the subdevices
 * @complete: All subdevices have been probed successfully. The complete callback is only executed for the root notifier.
 * @unbind: a subdevice is leaving
 */
struct v4l2_async_notifier_operations {
    int (*bound)(struct v4l2_async_notifier *notifier, 
            struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd);
    int (*complete)(struct v4l2_async_notifier *notifier);
    int (*unbind)(struct v4l2_async_notifier *notifier,
            struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd)
}

v4l2_async_notifier_register和v4l2_async_subdev_notifier_register都是向v4l2 async框架注册一个异步通知器,不同的是后边这个接口注册的notifier是子设备(v4l2_subdev),{BANNED}中国{BANNED}中国第一个接口时v4l2_device作通知器。v4l2 async框架中notifier是有root的概念,root notifier是v4l2_device。

示例
notifier_list链表上有3个notifier,分别是imx291的, mipi csi phy的及 mipi csi 的

subdev_list链表上有3个subdev,分别是imx291的, mipi csi phy的及 mipi csi 的

mipi csi phy的notifier->waitng上有个asd,asd指向imx291 dts的节点

mipi csi 的notifier->waiting上有个asd,asd指向mipi csi phy dts的节点

rkcif_mipi 的notifier->waiting上有个asd,asd指向mipi csi dts的节点

异步通知机制允许驱动程序在子设备可用时通知V4L2核心进行注册,而不需要在驱动程序初始化阶段进行静态注册。这种机制非常适用于需要动态添加或移除子设备的情况,例如热插拔设备或根据特定条件动态注册设备的应用场景。

需要补充下:v4l2_async_notifier_register()和v4l2_async_register_subdev实际上并真正注册设备,只有在它们两个注册的设备信息匹配后,才会调用v4l2_device_register_subdev()函数向系统真正注册子设备。


小结:
视频异步子设备注册可以分为两个部分,一部分为notifier管理的v4l2_async_subdev,另外一部分为子设备驱动的v4l2_subdev。notifier中的异步子设备都是根据设备树信息注册的。然后子设备驱动再注册自己对应的子设备。上面所涉及到的主要区别在于v4l2_async_notifier_register()和v4l2_async_register_subdev()函数。这两个函数需要仔细去分析下,原理和linux驱动中的其它总线和设备匹配非常相似。一般来说视频驱动会先解析设备树获取子设备信息后,再通过v4l2_async_notifier_register()来注册到notifier,将还没有匹配的子设备添加到waiting链表上。然后调用notifier->match()函数来进行匹配,如果匹配成功,将调用v4l2_device_register_subdev()将subdev添加到V4L2的子设备链表上。{BANNED}最佳后调用notifier->complete()回调函数。如果匹配不成功,则将添加到v4l2自己维护的通知链表notifier_list。另一方面,在驱动中会调用v4l2_async_register_subdev()来注册子设备,将调用notifier->match()函数来进行匹配,如果匹配成功,将调用v4l2_device_register_subdev()将subdev添加到V4L2的子设备链表上。{BANNED}最佳后调用notifier->complete()回调函数。如果匹配不成功,会将设备添加到v4l2自己维护的子设备链表subdev_list是上。

阅读(55) | 评论(0) | 转发(0) |
0

上一篇:CMA and DMA_BUF

下一篇:Linux显示系统框架

给主人留下些什么吧!~~