摄像头驱动(一)————V4L2框架浅析
来源:互联网 发布:python 绝技 源码 编辑:程序博客网 时间:2024/06/18 11:56
V4L2 :video for linux version 2 ,是 linux 里一套标准的视频驱动,它支持 uvc 标准的摄像头。本文来分析一下它的核心框架。
整个v4l2的框架分为三层:
在应用层,我们可以在 /dev 目录发现 video0 类似的设备节点,上层的摄像头程序打开设备节点进行数据捕获,显示视频画面。设备节点的名字很统一,video0 video1 video2...这些设备节点在是核心层注册。
核心层 v4l2-dev.c,承上启下,对于每一个硬件相关层注册进来的设备,设置一个统一的接口 v4l2_fops ,既然是统一的接口必然不是具体的视频设备的操作函数,应用层调用 v4l2_fops 中的函数最终将调用到硬件相关层的 video_device 的 fops 。
硬件相关层,与具体的视频硬件打交道,分配、设置、注册 video_device 结构体。
- static int __init videodev_init(void)
- {
-
- dev_t dev = MKDEV(VIDEO_MAJOR, 0);
- ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
-
- ret = class_register(&video_class);
- return 0;
- }
- struct video_device
- {
-
- const struct v4l2_file_operations *fops;
-
-
- struct device dev;
- struct cdev *cdev;
-
-
- struct device *parent;
- struct v4l2_device *v4l2_dev;
-
-
- struct v4l2_ctrl_handler *ctrl_handler;
-
-
- struct v4l2_prio_state *prio;
-
-
- char name[32];
- int vfl_type;
-
- int minor;
- u16 num;
-
- unsigned long flags;
-
- int index;
-
-
- spinlock_t fh_lock;
- struct list_head fh_list;
-
- int debug;
-
-
- v4l2_std_id tvnorms;
- v4l2_std_id current_norm;
-
-
- void (*release)(struct video_device *vdev);
-
-
- const struct v4l2_ioctl_ops *ioctl_ops;
- DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
-
-
- DECLARE_BITMAP(disable_locking, BASE_VIDIOC_PRIVATE);
- struct mutex *lock;
- };
- struct v4l2_device {
- struct device *dev;
-
- struct list_head subdevs;
- spinlock_t lock;
- char name[V4L2_DEVICE_NAME_SIZE];
- void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg);
- struct v4l2_ctrl_handler *ctrl_handler;
- struct v4l2_prio_state prio;
- struct mutex ioctl_lock;
- struct kref ref;
- void (*release)(struct v4l2_device *v4l2_dev);
- };
- static inline int __must_check video_register_device(struct video_device *vdev,
- int type, int nr)
- {
- return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);
- }
-
- int __video_register_device(struct video_device *vdev, int type, int nr,
- int warn_if_nr_in_use, struct module *owner)
- {
- int i = 0;
- int ret;
- int minor_offset = 0;
- int minor_cnt = VIDEO_NUM_DEVICES;
- const char *name_base;
-
-
- vdev->minor = -1;
-
-
- switch (type) {
- case VFL_TYPE_GRABBER:
- name_base = "video";
- break;
- case VFL_TYPE_VBI:
- name_base = "vbi";
- break;
- ...
- }
-
- vdev->vfl_type = type;
- vdev->cdev = NULL;
-
-
- #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
- switch (type) {
- case VFL_TYPE_GRABBER:
- minor_offset = 0;
- minor_cnt = 64;
- break;
- ...
- #endif
-
-
- mutex_lock(&videodev_lock);
- nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
- if (nr == minor_cnt)
- nr = devnode_find(vdev, 0, minor_cnt);
- if (nr == minor_cnt) {
- printk(KERN_ERR "could not get a free device node number\n");
- mutex_unlock(&videodev_lock);
- return -ENFILE;
- }
- #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
-
- i = nr;
- #else
-
- for (i = 0; i < VIDEO_NUM_DEVICES; i++)
- if (video_device[i] == NULL)
- break;
- if (i == VIDEO_NUM_DEVICES) {
- mutex_unlock(&videodev_lock);
- printk(KERN_ERR "could not get a free minor\n");
- return -ENFILE;
- }
- #endif
- vdev->minor = i + minor_offset;
- vdev->num = nr;
- devnode_set(vdev);
-
- if (vdev->ioctl_ops)
- determine_valid_ioctls(vdev);
-
-
- vdev->cdev = cdev_alloc();
- vdev->cdev->ops = &v4l2_fops;
- vdev->cdev->owner = owner;
- ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
-
-
- vdev->dev.class = &video_class;
- vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
- if (vdev->parent)
- vdev->dev.parent = vdev->parent;
- dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
- ret = device_register(&vdev->dev);
-
- vdev->dev.release = v4l2_device_release;
-
-
- set_bit(V4L2_FL_REGISTERED, &vdev->flags);
- mutex_lock(&videodev_lock);
- video_device[vdev->minor] = vdev;
- mutex_unlock(&videodev_lock);
-
- return 0;
-
- }
- EXPORT_SYMBOL(__video_register_device);
- 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,
- };
- static int v4l2_open(struct inode *inode, struct file *filp)
- {
- struct video_device *vdev = video_devdata(filp);
- if (vdev->fops->open) {
-
- if (video_is_registered(vdev))
- ret = vdev->fops->open(filp);
- }
- }
- static ssize_t v4l2_read(struct file *filp, char __user *buf,
- size_t sz, loff_t *off)
- {
- struct video_device *vdev = video_devdata(filp);
- if (!vdev->fops->read)
- return -EINVAL;
- if (video_is_registered(vdev))
- ret = vdev->fops->read(filp, buf, sz, off);
- }
- static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
- {
- struct video_device *vdev = video_devdata(filp);
- if (!vdev->fops->mmap)
- return ret;
- ret = vdev->fops->mmap(filp, vm);
- }
-
- static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
- {
- struct video_device *vdev = video_devdata(filp);
- if (vdev->fops->unlocked_ioctl) {
- if (video_is_registered(vdev))
- ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
- } else if (vdev->fops->ioctl) {
- if (video_is_registered(vdev))
- ret = vdev->fops->ioctl(filp, cmd, arg);
- }
- }