视频驱动V4L2子系统驱动架构-框架

V4L2驱动框架

v4l2驱动架构如图所示,v4l2也就是video for linux two,那么也就是说还有One了,v4l2前面还有v4l

图中芯片模块对应Soc的各个子模块,video_device结构体主要用来控制Soc的video模块,v4l2_device会包含多个v4l2_subdev ,每个v4l2_subdev 用来控制各自的子模块,某些驱动不需要v4l2_subdev ,依靠video模块就能实现功能

这里写图片描述

v4l2驱动代码在drivers\media\v4l2-core文件夹下,文件看起来很多,但是根据字面意思来理解基本的功能都了解差不多了。videobuf是实现视频的内存分配的,对于v4l2和v4l分别对应不同的文件,如videobuf-core和videobuf2-core;v4l2-dev,v4l2-device,v4l2-subdev分别对应video_device,v4l2_device ,v4l2_subdev 的实现;v4l2-ioctl是实现ioctl等等。

video驱动代码在driver/media/目录下,下面分好多子目录,platform目录存放的是不同SoC的驱动代码,对应video_device,其他大多子目录如i2c、mmc、usb、tuners、radio等对应subdev的实现

v4l2驱动框架最重要的是理解ioctl,另外v4l2驱动框架最主要的是各个ioctl实现的功能,这些实现方式需要在实际操作中多加理解,不是难点。

用一个比较粗糙的图来表现他们之间的关系,大致为:

设备实例(v4l2_device)

           |______子设备实例(v4l2_subdev)

           |______视频设备节点(video_device)

           |______文件访问控制(v4l2_fh)

           |______视频缓冲的处理(videobuf/videobuf2)

struct v4l2_device; 
用来描述一个v4l2设备实例

struct v4l2_subdev, 
用来描述一个v4l2的子设备实例

struct video_device; 
用来创建设备节点/dev/videoX

struct v4l2_fh; 
用来跟踪文件句柄实例

v4l2-dev.c                  //linux版本2视频捕捉接口,主要结构体 video_device 的注册
v4l2-common.c               //在Linux操作系统体系采用低级别的操作一套设备structures/vectors的通用视频设备接口。
                            //此文件将替换videodev.c的文件配备常规的内核分配。
v4l2-device.c               //V4L2的设备支持。注册v4l2_device
v4l22-ioctl.c               //处理V4L2的ioctl命令的一个通用的框架。
v4l2-subdev.c               //v4l2子设备
v4l2-mem2mem.c              //内存到内存为Linux和videobuf视频设备的框架。设备的辅助函数,使用其源和目的地videobuf缓冲区。

头文件linux/videodev2.h、media/v4l2-common.h、media/v4l2-device.h、media/v4l2-ioctl.h、media/v4l2-dev.h、media/v4l2-ioctl.h等。

-----------------------------------------------------------------------------------------------------------------------------------------------------------

 V4L2支持三类设备:视频输入输出设备、VBI设备和radio设备(其实还支持更多类型的设备,暂不讨论),分别会在/dev目录下产生videoX、radioX和vbiX设备节点。我们常见的视频输入设备主要是摄像头,也是本文主要分析对象。下图V4L2在Linux系统中的结构图:

 

Linux系统中视频输入设备主要包括以下四个部分:

字符设备驱动程序核心:V4L2本身就是一个字符设备,具有字符设备所有的特性,暴露接口给用户空间;

V4L2驱动核心:主要是构建一个内核中标准视频设备驱动的框架,为视频操作提供统一的接口函数;

平台V4L2设备驱动:在V4L2框架下,根据平台自身的特性实现与平台相关的V4L2驱动部分,包括注册video_device和v4l2_dev。

具体的sensor驱动:主要上电、提供工作时钟、视频图像裁剪、流IO开启等,实现各种设备控制方法供上层调用并注册v4l2_subdev。

V4L2的核心源码位于drivers/media/v4l2-core,源码以实现的功能可以划分为四类:

核心模块实现:由v4l2-dev.c实现,主要作用申请字符主设备号、注册class和提供video device注册注销等相关函数;

V4L2框架:由v4l2-device.c、v4l2-subdev.c、v4l2-fh.c、v4l2-ctrls.c等文件实现,构建V4L2框架;

Videobuf管理:由videobuf2-core.c、videobuf2-dma-contig.c、videobuf2-dma-sg.c、videobuf2-memops.c、videobuf2-vmalloc.c、v4l2-mem2mem.c等文件实现,完成videobuffer的分配、管理和注销。

Ioctl框架:由v4l2-ioctl.c文件实现,构建V4L2ioctl的框架。

----------------------------------------------------------------------------------------------------------------------------------------------------------

V4L2框架(2)

         结构体v4l2_device、video_device、v4l2_subdev和v4l2_fh是搭建框架的主要元素。下图是V4L2框架的结构图:

从上图V4L2框架是一个标准的树形结构,v4l2_device充当了父设备,通过链表把所有注册到其下的子设备管理起来,这些设备可以是GRABBER、VBI或RADIO。V4l2_subdev是子设备,v4l2_subdev结构体包含了对设备操作的ops和ctrls,这部分代码和硬件相关,需要驱动工程师根据硬件实现,像摄像头设备需要实现控制上下电、读取ID、饱和度、对比度和视频数据流打开关闭的接口函数。Video_device用于创建子设备节点,把操作设备的接口暴露给用户空间。V4l2_fh是每个子设备的文件句柄,在打开设备节点文件时设置,方便上层索引到v4l2_ctrl_handler,v4l2_ctrl_handler管理设备的ctrls,这些ctrls(摄像头设备)包括调节饱和度、对比度和白平衡等。

------------------------------------------------------------------------------------------------------------------------------------------------------

V4L2 core介绍

video_device

用于实现SoC的video模块


 
 
  1. struct video_device
  2. {
  3. #if defined(CONFIG_MEDIA_CONTROLLER)
  4. struct media_entity entity;
  5. struct media_intf_devnode *intf_devnode;
  6. struct media_pipeline pipe;
  7. #endif
  8. /* device ops */
  9. const struct v4l2_file_operations *fops;--------------------------具体video模块实现函数
  10. /* sysfs */
  11. struct device dev; /* v4l device */
  12. struct cdev *cdev; /* character device */--------------------上层接口
  13. struct v4l2_device *v4l2_dev; /* v4l2_device parent */----------v4l2_device
  14. /* Only set parent if that can't be deduced from v4l2_dev */
  15. struct device *dev_parent; /* device parent */
  16. /* Control handler associated with this device node. May be NULL. */
  17. struct v4l2_ctrl_handler *ctrl_handler;
  18. /* vb2_queue associated with this device node. May be NULL. */
  19. struct vb2_queue *queue;
  20. /* Priority state. If NULL, then v4l2_dev->prio will be used. */
  21. struct v4l2_prio_state *prio;
  22. /* device info */
  23. char name[ 32];
  24. int vfl_type; /* device type */
  25. int vfl_dir; /* receiver, transmitter or m2m */
  26. /* 'minor' is set to -1 if the registration failed */
  27. int minor;--------------------------------------------------------video-x的次设备号
  28. u16 num;
  29. /* use bitops to set/clear/test flags */
  30. unsigned long flags;
  31. /* attribute to differentiate multiple indices on one physical device */
  32. int index;
  33. /* V4L2 file handles */
  34. spinlock_t fh_lock; /* Lock for all v4l2_fhs */
  35. struct list_head fh_list; /* List of struct v4l2_fh */
  36. /* Internal device debug flags, not for use by drivers */
  37. int dev_debug;
  38. /* Video standard vars */
  39. v4l2_std_id tvnorms; /* Supported tv norms */
  40. /* callbacks */
  41. void (*release)(struct video_device *vdev);
  42. /* ioctl callbacks */
  43. const struct v4l2_ioctl_ops *ioctl_ops;-------------------------具体功能的实现函数
  44. DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
  45. /* serialization lock */
  46. DECLARE_BITMAP(disable_locking, BASE_VIDIOC_PRIVATE);
  47. struct mutex *lock;
  48. };

struct video_device
     {
         /*设备操作函数 */
         const struct v4l2_file_operations *fops;

         /* 虚拟文件系统 */
         struct device dev;        /* v4l 设备 */
         struct cdev *cdev;        /* 字符设备 */

        struct device *parent;        /*父设备 */
        struct v4l2_device *v4l2_dev;    /* v4l2_device parent */

        /* 设备信息 */
         char name[32];
         int vfl_type;
         /* 'minor' is set to -1 if the registration failed */
        int minor;
        u16 num;
         /* use bitops to set/clear/test flags */
         unsigned long flags;
         /*属性来区分一个物理设备上的多个索引 */
        int index;

         /* V4L2 文件句柄 */
         spinlock_t        fh_lock; /*锁定所有的 v4l2_fhs */
         struct list_head    fh_list; /* List of struct v4l2_fh */

         int debug;            /* Activates debug level*/

         /* Video standard vars */
         v4l2_std_id tvnorms;        /* Supported tv norms */
         v4l2_std_id current_norm;    /* Current tvnorm */

         /* 释放的回调函数 */
        void (*release)(struct video_device *vdev);

         /* 控制的回调函数 */
         const struct v4l2_ioctl_ops *ioctl_ops;
     }

函数介绍:


 
 
  1. //注册函数
  2. static inline int __must_check video_register_device( struct video_device *vdev,
  3. int type, int nr)
  4. //卸载函数
  5. void video_unregister_device( struct video_device *vdev);

v4l2_device

对应子模块的实现,包含多个子模块


 
 
  1. struct v4l2_device {
  2. /* dev->driver_data points to this struct.
  3. Note: dev might be NULL if there is no parent device
  4. as is the case with e.g. ISA devices. */
  5. struct device *dev;
  6. #if defined(CONFIG_MEDIA_CONTROLLER)
  7. struct media_device *mdev;
  8. #endif
  9. /* used to keep track of the registered subdevs */
  10. struct list_head subdevs;
  11. /* lock this struct; can be used by the driver as well if this
  12. struct is embedded into a larger struct. */
  13. spinlock_t lock;
  14. /* unique device name, by default the driver name + bus ID */
  15. char name[V4L2_DEVICE_NAME_SIZE];
  16. /* notify callback called by some sub-devices. */
  17. void (*notify)(struct v4l2_subdev *sd,
  18. unsigned int notification, void *arg);
  19. /* The control handler. May be NULL. */
  20. struct v4l2_ctrl_handler *ctrl_handler;
  21. /* Device's priority state */
  22. struct v4l2_prio_state prio;
  23. /* Keep track of the references to this struct. */
  24. struct kref ref;
  25. /* Release function that is called when the ref count goes to 0. */
  26. void (*release)(struct v4l2_device *v4l2_dev);
  27. };

struct v4l2_device {
//指向设备模型的指针
struct device *dev;
#if defined(CONFIG_MEDIA_CONTROLLER)
//指向一个媒体控制器的指针
struct media_device *mdev;
#endif
//管理子设备的双向链表,所有注册到的子设备都需要加入到这个链表当中
struct list_head subdevs;
//全局锁
spinlock_t lock;
//设备名称
char name[V4L2_DEVICE_NAME_SIZE];
//通知回调函数,通常用于子设备传递事件,这些事件可以是自定义事件
void (*notify)(struct v4l2_subdev*sd, uint notification, void *arg);
//控制句柄
struct v4l2_ctrl_handler*ctrl_handler;
//设备的优先级状态,一般有后台,交互,记录三种优先级,依次变高
struct v4l2_prio_state prio;
//ioctl操作的互斥量
struct mutex ioctl_lock;
//本结构体的引用追踪
struct kref ref;
//设备释放函数
void (*release)(struct v4l2_device*v4l2_dev);
};

 

函数介绍:


 
 
  1. //注册函数
  2. int __ must_check v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
  3. int __ must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
  4. struct v4l2_subdev *sd);
  5. //卸载函数
  6. void v4l2_device_unregister(struct v4l2_device *v4l2_dev);
  7. int __ must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
  8. struct v4l2_subdev *sd);

v4l2_subdev

具体子模块的实现


 
 
  1. struct v4l2_subdev {
  2. #if defined(CONFIG_MEDIA_CONTROLLER)
  3. struct media_entity entity;
  4. #endif
  5. struct list_head list;
  6. struct module *owner;
  7. bool owner_v4l2_dev;
  8. u32 flags;
  9. struct v4l2_device *v4l2_dev;
  10. const struct v4l2_subdev_ops *ops;--------------------------功能实现函数
  11. /* Never call these internal ops from within a driver! */
  12. const struct v4l2_subdev_internal_ops *internal_ops;
  13. /* The control handler of this subdev. May be NULL. */
  14. struct v4l2_ctrl_handler *ctrl_handler;
  15. /* name must be unique */
  16. char name[V4L2_SUBDEV_NAME_SIZE];
  17. /* can be used to group similar subdevs, value is driver-specific */
  18. u32 grp_id;
  19. /* pointer to private data */
  20. void *dev_priv;
  21. void *host_priv;
  22. /* subdev device node */
  23. struct video_device *devnode;
  24. /* pointer to the physical device, if any */
  25. struct device *dev;
  26. /* The device_node of the subdev, usually the same as dev->of_node. */
  27. struct device_node *of_node;
  28. /* Links this subdev to a global subdev_list or @notifier->done list. */
  29. struct list_head async_list;
  30. /* Pointer to respective struct v4l2_async_subdev. */
  31. struct v4l2_async_subdev *asd;
  32. /* Pointer to the managing notifier. */
  33. struct v4l2_async_notifier *notifier;
  34. /* common part of subdevice platform data */
  35. struct v4l2_subdev_platform_data *pdata;
  36. };

 
 
  1. 每个模块对应的实现函数
  2. struct v4l2_subdev_ops {
  3. const struct v4l2_subdev_core_ops *core;
  4. const struct v4l2_subdev_tuner_ops *tuner;
  5. const struct v4l2_subdev_audio_ops *audio;
  6. const struct v4l2_subdev_video_ops *video;
  7. const struct v4l2_subdev_vbi_ops *vbi;
  8. const struct v4l2_subdev_ir_ops *ir;
  9. const struct v4l2_subdev_sensor_ops *sensor;
  10. const struct v4l2_subdev_pad_ops *pad;
  11. };

struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER)
//媒体控制器的实体,和v4l2_device
struct media_entity entity;
#endif
struct list_head list;
struct module *owner;
u32 flags;
//指向一个v4l2设备
struct v4l2_device *v4l2_dev;
//子设备的操作函数集
const struct v4l2_subdev_ops *ops;
//子设备的内部操作函数集
const struct v4l2_subdev_internal_ops*internal_ops;
//控制函数处理器
struct v4l2_ctrl_handler*ctrl_handler;
//子设备的名称
char name[V4L2_SUBDEV_NAME_SIZE];
//子设备所在的组标识
u32 grp_id;
//子设备私有数据指针,一般指向总线接口的客户端
void *dev_priv;
//子设备私有的数据指针,一般指向总线接口的host端
void *host_priv;
//设备节点
struct video_device devnode;
//子设备的事件
unsigned int nevents;
};

函数介绍:


 
 
  1. //注册函数
  2. struct v4l2_subdev *v4l2_i2c_new_subdev( struct v4l2_device *v4l2_dev,
  3. struct i2c_adapter *adapter, const char *client_type,
  4. u8 addr, const unsigned short *probe_addrs);
  5. struct v4l2_subdev *v4l2_spi_new_subdev( struct v4l2_device *v4l2_dev,
  6. struct spi_master *master, struct spi_board_info *info);

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值