[完结]Linux内核中的V4L2核心框架分析(V4L2 framework,video for linux 2,linux视频子系统)

本文详细介绍了Linux内核中的V4L2框架,包括设备驱动结构、框架结构、子设备管理和设备节点创建。内容涵盖v4l2_device、v4l2_subdev结构体的使用,以及注册、反注册、通知回调等机制。此外,还讨论了如何处理视频缓冲区和事件订阅。
摘要由CSDN通过智能技术生成


标题: V4L2核心框架分析   

 

驱动的结构
------------------------------------------------------
1)一个为设备实例定义的,并且包含设备状态信息的结构;
2)一种初始化和命令子设备(sub-devices)的方式;
3)创建V4L2设备节点(/dev/videoX, /dev/vbiX, /dev/radioX and /dev/vtxX)
   并且 keeping track of device-node specific data.
4)Filehandle-specific structs containing per-filehandle data;
5)视频buffer处理;

下面有个大略的关系描述图:

    device instances
      |
      +-sub-device instances
      |
      \-V4L2 device nodes
      |
      \-filehandle instances

 


框架的结构
------------------------------------------------------------
框架结构与驱动结构类似:
它有:
    一个用于device实例数据的结构体: v4l2_device
    一个用于sub-device实例的结构体:v4l2_subdev
    一个存储设备节点数据的结构体:video_device
    将来会用于保持对文件操作实例的追踪的结构体:v4l2_fh

 


v4l2_device结构体(struct v4l2_device)
-----------------------------------------------------------------------
每个设备实例是由一个struct v4l2_device结构(v4l2-device.h)来描述的。
很简单的设备可以只分配这个结构,但是,大部分时候,你将嵌入这个结构到一个更大的与描述特定设备的结构。
你必须注册设备实例(在drivers/media/video/v4l2-device.c中):
 

  v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);

 

注册将初始化v4l2_device结构,和连接(link) dev->driver_data 到v4l2_dev。
如果v4l2_dev->name 是空的,那么它将被设置成一个值,这个值是由dev参数得到的(严格来说,驱动名跟随bus_id)。
如果你在调用v4l2_device_register()之前设置了v4l2_dev->name,那么v4l2_dev->name将不被改变(即使用你之前设置的值)。
如果dev是NULL,那么你必须在调用v4l2_device_register()之前填充v4l2_dev->name。

你可以使用 v4l2_device_set_name()来设置这个名称为驱动的名字 和 一个  driver-global atomic_t instance。
这将产生一些名字如: ivtv0, ivtv1 等。如果这些名字(ivtv0中的ivtv就是一个名字)以一个数字结束,那么它将插入一个“-”,然后跟上一个顺序的编号。
v4l2_device_set_name()这个函数返回这个实例号。

 

 

    int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
                            atomic_t *instance)
    {
        int num = atomic_inc_return(instance) - 1;
        int len = strlen(basename);

        if (basename[len - 1] >= '0' && basename[len - 1] <= '9')//如果名字的最后是数字;
            snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
                    "%s-%d", basename, num);//那么名字后面加“-”
        else
            snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
                    "%s%d", basename, num);
        return num;
    }
    EXPORT_SYMBOL_GPL(v4l2_device_set_name);


 

现在回头说v4l2_device_register函数。它的第一个参数dev通常都是一个pci_dev
、usb_interface 或者 platform_device 的“struct device”类型的指针。
dev基本上不会是NULL,但是在ISA devices或者当一个设备创建了多个PCI设备的时候,这是可能发生的。
这时候它与v4l2_dev产生了关系,v4l2_dev下可能有个dev成员(即v4l2_dev是父,dev是子)。

你也可以提供一个 notify()的回调函数,子设备(sub-devices)可以调用这个回调函数通知你一些事件(events);
你是否需要设置这个回调函数,取决于这个子设备。一个子设备支持的任何通知(notifications)必须被定义在头文件“include/media/<subdevice>.h”当中。
比如include/media/ 下有如下文件:
    v4l2-chip-ident.h  v4l2-fh.h          v4l2-mem2mem.h         videobuf-dvb.h
    v4l2-common.h      v4l2-i2c-drv.h     v4l2-subdev.h          videobuf-vmalloc.h
    v4l2-dev.h         v4l2-int-device.h  videobuf-core.h            tvp5150.h(这个就是subdevice的头文件)
    v4l2-device.h      v4l2-ioctl.h       videobuf-dma-contig.h
    v4l2-event.h       v4l2-mediabus.h    videobuf-dma-sg.h     …………

有注册,就有反注册。那对应的反注册的函数是:

    v4l2_device_unregister(struct v4l2_device *v4l2_dev);

 

反注册,也将会自动从设备反注册掉所有的子设备(subdevs)。

如果你有一个可热插拔的(hotpluggable)的设备(例如USB设备),那么的那个一个disconnect(断开)发生时,父设备变成无效的(invalid)。
因为v4l2_device中有一个指针指向父设备,所以他可以同时被清除掉,并且标记父设备is gone(这里应该是在父设备的结构里标记子设备已经无效了)。
    v4l2_device_disconnect(struct v4l2_device *v4l2_dev); //热插拔使用的断开函数

 

    void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
    {
        if (v4l2_dev->dev) {//这个函数制式标记了父设备那边告诉子设备已经无效。
            dev_set_drvdata(v4l2_dev->dev, NULL);
            v4l2_dev->dev = NULL;
        }
    }
    EXPORT_SYMBOL_GPL(v4l2_device_disconnect);



v4l2_device_disconnect不会反注册掉子设备,所以你依然需要为子设备调用v4l2_device_unregister这个函数。
事实上,v4l2_device_unregister函数中还是会调用v4l2_device_disconnect的。

    void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
    {
        struct v4l2_subdev *sd, *next;

        if (v4l2_dev == NULL)
            return;
        v4l2_device_disconnect(v4l2_dev);
            …………
    }

 

如果你的设备不支持热插拔,那么就不需要调用v4l2_device_disconnect()了。

有时候,你需要迭代把所有的设备通过一个特定的驱动注册。这种情况通常发生在,多个设备驱动使用同一个硬件(hardware)的时候。
例如(E.g.),ivtvfb 驱动是一个 帧缓冲(framebuffer)设备驱动,这个驱动使用ivtv这个硬件。类似的 alsa驱动也是一样。

你可以像如下这样迭代所有已注册的设备:

 

    static int callback(struct devic
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值