V4L2 driver -整体架构

我的uvc开源地址:gitee-uvc

  • 字符设备驱动程序核心:V4L2本身就是一个字符设备,具有字符设备所有的特性,暴露接口给用户空间。
  • V4L2 驱动核心:主要是构建一个内核中标准视频设备驱动的框架,为视频操作提供统一的接口函数。
  • 平台V4L2设备驱动:在V4L2框架下,根据平台自身的特性实现与平台相关的V4L2驱动部分,包括注册video_device和v4l2_dev。
  • 具体的sensor驱动:主要上电、提供工作时钟、视频图像裁剪、流IO开启等,实现各种设备控制方法供上层调用并注册v4l2_subdev。

1 从字符设备开始:

熟悉v4l2用户空间编程的都知道, v4l2编程主要是调用一系列的ioctl函数去对v4l2设备进行打开, 关闭, 查询, 设置等操作. v4l2设备是一个字符设备, 而且其驱动的主要工作就是实现各种各样的ioctl.

v4l2的整体框架如下图所示:

V4L2 :video for linux version 2 ,是 linux 里一套标准的视频驱动。本文来分析一下它的核心框架。

在v4l2的核心中对这个file_operations的实现如下:

static const struct file_operations v4l2_fops = {
    .owner = THIS_MODULE,
    .read = v4l2_read,
    .write = v4l2_write,
    .open = v4l2_open,
    .get_unmapped_area = v4l2_get_unmapped_area,
    .mmap = v4l2_mmap,
    .unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl = v4l2_compat_ioctl32,
#endif
    .release = v4l2_release,
    .poll = v4l2_poll,
    .llseek = no_llseek,
};

这个v4l2_fops函数最终绑定在一个cdev上, 并注册到系统中。

v4l2_open为例(代码在kernel\drivers\media\v4l2-core中):

/* Override for the open function */
static int v4l2_open(struct inode *inode, struct file *filp)
{
    struct video_device *vdev;
    int ret = 0;

    /* Check if the video device is available */
    mutex_lock(&videodev_lock);
    vdev = video_devdata(filp);
    /* return ENODEV if the video device has already been removed. */
    if (vdev == NULL || !video_is_registered(vdev)) {
        mutex_unlock(&videodev_lock);
        return -ENODEV;
    }
    /* and increase the device refcount */
    video_get(vdev);
    mutex_unlock(&videodev_lock);
    if (vdev->fops->open) {
        if (video_is_registered(vdev))
            //这里就是调用了file_operations的open函数
            ret = vdev->fops->open(filp);
        else
            ret = -ENODEV;
    }

    if (vdev->debug)
        printk(KERN_DEBUG "%s: open (%d)\n",
            video_device_node_name(vdev), ret);
    /* decrease the refcount in case of an error */
    if (ret)
        video_put(vdev);
    return ret;
}

2. video_device结构体:

video_device结构体用于在/dev目录下生成设备节点文件,把操作设备的接口暴露给用户空间。

我们是使用video_device来操作的,看看video_device这个结构体:

struct video_device
{
#if defined(CONFIG_MEDIA_CONTROLLER)
    struct media_entity entity;
#endif
    /* device ops */
    const struct v4l2_file_operations *fops;

    /* sysfs */
    struct device dev;      /* v4l device */
    struct cdev *cdev;      /* character device */

    /* Set either parent or v4l2_dev if your driver uses v4l2_device */
    struct device *parent;      /* device parent */
    struct v4l2_device *v4l2_dev;   /* v4l2_device parent */

    /* Control handler associated with this device node. May be NULL. */
    struct v4l2_ctrl_handler *ctrl_handler;

    /* vb2_queue associated with this device node. May be NULL. */
    struct vb2_queue *queue;

    /* Priority state. If NULL, then v4l2_dev->prio will be used. */
    struct v4l2_prio_state *prio;

    /* device info */
    char name[32];
    int vfl_type;   /* device type */
    int vfl_dir;    /* receiver, transmitter or m2m */
    /* 'minor' is set to -1 if the registration failed */
    int minor;
    u16 num;
    /* use bitops to set/clear/test flags */
    unsigned long flags;
    /* attribute to differentiate multiple indices on one physical device */
    int index;

    /* V4L2 file handles */
    spinlock_t      fh_lock; /* Lock for all 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 */

    /* callbacks */
    void (*release)(struct video_device *vdev);

    /* ioctl callbacks */
    const struct v4l2_ioctl_ops *ioctl_ops;
    DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);

    /* serialization lock */
    DECLARE_BITMAP(disable_locking, BASE_VIDIOC_PRIVATE);
    struct mutex *lock;
};

3. V4L2_device结构体:

这个结构体中包含了一个非常重要的结构体v4l2_device

struct v4l2_device {
    /* dev->driver_data points to this struct.
       Note: dev might be NULL if there is no parent device
       as is the case with e.g. ISA devices. */
    struct device *dev;
#if defined(CONFIG_MEDIA_CONTROLLER)
    struct media_device *mdev;
#endif
    /* used to keep track of the registered subdevs */
    struct list_head subdevs;
    /* lock this struct; can be used by the driver as well if this
       struct is embedded into a larger struct. */
    spinlock_t lock;
    /* unique device name, by default the driver name + bus ID */
    char name[V4L2_DEVICE_NAME_SIZE];
    /* notify callback called by some sub-devices. */
    void (*notify)(struct v4l2_subdev *sd,
            unsigned int notification, void *arg);
    /* The control handler. May be NULL. */
    struct v4l2_ctrl_handler *ctrl_handler;
    /* Device's priority state */
    struct v4l2_prio_state prio;
    /* BKL replacement mutex. Temporary solution only. */
    struct mutex ioctl_lock;
    /* Keep track of the references to this struct. */
    struct kref ref;
    /* Release function that is called when the ref count goes to 0. */
    void (*release)(struct v4l2_device *v4l2_dev);
};

3.1 v4l2_device的注册和注销:

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

static void v4l2_device_release(struct kref *ref)

4. v4l2_subdev结构体

V4l2_subdev代表子设备,包含了子设备的相关属性和操作。先来看下结构体原型:

struct v4l2_subdev {
 
         struct v4l2_device *v4l2_dev;  //指向父设备
 
         //提供一些控制v4l2设备的接口
 
         const struct v4l2_subdev_ops *ops;
 
         //向V4L2框架提供的接口函数
 
         const struct v4l2_subdev_internal_ops *internal_ops;
 
         //subdev控制接口
 
         struct v4l2_ctrl_handler *ctrl_handler;
 
         /* name must be unique */
 
         charname[V4L2_SUBDEV_NAME_SIZE];
 
         /*subdev device node */
 
         struct video_device *devnode;  
 
};

4.1 subdev的注册和注销

当我们把v4l2_subdev需要实现的成员都已经实现,就可以调用以下函数把子设备注册到V4L2核心层:

int v4l2_device_register_subdev(struct v4l2_device*v4l2_dev, struct v4l2_subdev *sd)

当卸载子设备时,可以调用以下函数进行注销:

void v4l2_device_unregister_subdev(struct v4l2_subdev*sd)

5. 应用层具体流程框架:

我们使用一张图来体现吧:

猜你喜欢

转载自www.cnblogs.com/linhaostudy/p/9486511.html