摄像头驱动(一)————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 结构体。

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static int __init videodev_init(void)  
  2. {  
  3.     /* 申请设备号,留给 video 设备使用 */  
  4.     dev_t dev = MKDEV(VIDEO_MAJOR, 0);  
  5.     ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);  
  6.     /* 创建 video 类 */  
  7.     ret = class_register(&video_class);  
  8.     return 0;  
  9. }  
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. struct video_device  
  2. {  
  3.     /* device ops */  
  4.     const struct v4l2_file_operations *fops;  
  5.   
  6.     /* sysfs */  
  7.     struct device dev;      /* v4l device */  
  8.     struct cdev *cdev;      /* character device */  
  9.   
  10.     /* Set either parent or v4l2_dev if your driver uses v4l2_device */  
  11.     struct device *parent;          /* device parent */  
  12.     struct v4l2_device *v4l2_dev;   /* v4l2_device parent */  
  13.   
  14.     /* Control handler associated with this device node. May be NULL. */  
  15.     struct v4l2_ctrl_handler *ctrl_handler;  
  16.   
  17.     /* Priority state. If NULL, then v4l2_dev->prio will be used. */  
  18.     struct v4l2_prio_state *prio;  
  19.   
  20.     /* device info */  
  21.     char name[32];  
  22.     int vfl_type;  
  23.     /* 'minor' is set to -1 if the registration failed */  
  24.     int minor;  
  25.     u16 num;  
  26.     /* use bitops to set/clear/test flags */  
  27.     unsigned long flags;  
  28.     /* attribute to differentiate multiple indices on one physical device */  
  29.     int index;  
  30.   
  31.     /* V4L2 file handles */  
  32.     spinlock_t      fh_lock; /* Lock for all v4l2_fhs */  
  33.     struct list_head    fh_list; /* List of struct v4l2_fh */  
  34.   
  35.     int debug;          /* Activates debug level*/  
  36.   
  37.     /* Video standard vars */  
  38.     v4l2_std_id tvnorms;        /* Supported tv norms */  
  39.     v4l2_std_id current_norm;   /* Current tvnorm */  
  40.   
  41.     /* callbacks */  
  42.     void (*release)(struct video_device *vdev);  
  43.   
  44.     /* ioctl callbacks */  
  45.     const struct v4l2_ioctl_ops *ioctl_ops;  
  46.     DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);  
  47.   
  48.     /* serialization lock */  
  49.     DECLARE_BITMAP(disable_locking, BASE_VIDIOC_PRIVATE);  
  50.     struct mutex *lock;  
  51. };  
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. struct v4l2_device {  
  2.     struct device *dev;  
  3.     /* used to keep track of the registered subdevs */  
  4.     struct list_head subdevs;  
  5.     spinlock_t lock;  
  6.     char name[V4L2_DEVICE_NAME_SIZE];  
  7.     void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg);  
  8.     struct v4l2_ctrl_handler *ctrl_handler;  
  9.     struct v4l2_prio_state prio;  
  10.     struct mutex ioctl_lock;  
  11.     struct kref ref;  
  12.     void (*release)(struct v4l2_device *v4l2_dev);  
  13. };  
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static inline int __must_check video_register_device(struct video_device *vdev,  
  2.         int type, int nr)  
  3. {  
  4.     return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);  
  5. }  
  6.   
  7. int __video_register_device(struct video_device *vdev, int type, int nr,  
  8.         int warn_if_nr_in_use, struct module *owner)  
  9. {  
  10.     int i = 0;  
  11.     int ret;  
  12.     int minor_offset = 0;  
  13.     int minor_cnt = VIDEO_NUM_DEVICES;  
  14.     const char *name_base;  
  15.   
  16.     /* A minor value of -1 marks this video device as never having been registered */  
  17.     vdev->minor = -1;  
  18.   
  19.     /* 视频设备的设备节点一般为 video0 ..video 就是由此而来 */  
  20.     switch (type) {  
  21.     case VFL_TYPE_GRABBER:  
  22.         name_base = "video";  
  23.         break;  
  24.     case VFL_TYPE_VBI:  
  25.         name_base = "vbi";  
  26.         break;  
  27.     ...  
  28.     }  
  29.   
  30.     vdev->vfl_type = type;  
  31.     vdev->cdev = NULL;  
  32.   
  33.     /* Part 2: find a free minor, device node number and device index. */  
  34. #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES  
  35.     switch (type) {  
  36.     case VFL_TYPE_GRABBER:  
  37.         minor_offset = 0;  
  38.         minor_cnt = 64;  
  39.         break;  
  40.     ...  
  41. #endif  
  42.   
  43.     /* 寻找一个空的项,这个好像并不重要 */  
  44.     mutex_lock(&videodev_lock);  
  45.     nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);  
  46.     if (nr == minor_cnt)  
  47.         nr = devnode_find(vdev, 0, minor_cnt);  
  48.     if (nr == minor_cnt) {  
  49.         printk(KERN_ERR "could not get a free device node number\n");  
  50.         mutex_unlock(&videodev_lock);  
  51.         return -ENFILE;  
  52.     }  
  53. #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES  
  54.     /* 1-on-1 mapping of device node number to minor number */  
  55.     i = nr;  
  56. #else  
  57.     /* 在全局 video_deivce 数组中寻找一个空的项,下标+minor_offset作为设备的次设备号 */  
  58.     for (i = 0; i < VIDEO_NUM_DEVICES; i++)  
  59.         if (video_device[i] == NULL)  
  60.             break;  
  61.     if (i == VIDEO_NUM_DEVICES) {  
  62.         mutex_unlock(&videodev_lock);  
  63.         printk(KERN_ERR "could not get a free minor\n");  
  64.         return -ENFILE;  
  65.     }  
  66. #endif  
  67.     vdev->minor = i + minor_offset;  
  68.     vdev->num = nr;  
  69.     devnode_set(vdev);  
  70.   
  71.     if (vdev->ioctl_ops)  
  72.         determine_valid_ioctls(vdev);  
  73.   
  74.     /* 注册字符设备 */  
  75.     vdev->cdev = cdev_alloc();  
  76.     vdev->cdev->ops = &v4l2_fops;  
  77.     vdev->cdev->owner = owner;  
  78.     ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);  
  79.       
  80.     /* 得把device注册进内核,mdev才能自动创建设备节点,/dev 目录下的video0 等就是来自这里 */  
  81.     vdev->dev.class = &video_class;  
  82.     vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);  
  83.     if (vdev->parent)  
  84.         vdev->dev.parent = vdev->parent;  
  85.     dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);  
  86.     ret = device_register(&vdev->dev);  
  87.   
  88.     vdev->dev.release = v4l2_device_release;  
  89.   
  90.     /* Part 6: Activate this minor. The char device can now be used. */  
  91.     set_bit(V4L2_FL_REGISTERED, &vdev->flags);  
  92.     mutex_lock(&videodev_lock);  
  93.     video_device[vdev->minor] = vdev;  
  94.     mutex_unlock(&videodev_lock);  
  95.   
  96.     return 0;  
  97.   
  98. }  
  99. EXPORT_SYMBOL(__video_register_device);  
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static const struct file_operations v4l2_fops = {  
  2.     .owner = THIS_MODULE,  
  3.     .read = v4l2_read,  
  4.     .write = v4l2_write,  
  5.     .open = v4l2_open,  
  6.     .get_unmapped_area = v4l2_get_unmapped_area,  
  7.     .mmap = v4l2_mmap,  
  8.     .unlocked_ioctl = v4l2_ioctl,  
  9. #ifdef CONFIG_COMPAT  
  10.     .compat_ioctl = v4l2_compat_ioctl32,  
  11. #endif  
  12.     .release = v4l2_release,  
  13.     .poll = v4l2_poll,  
  14.     .llseek = no_llseek,  
  15. };  
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static int v4l2_open(struct inode *inode, struct file *filp)  
  2. {  
  3.     struct video_device *vdev = video_devdata(filp);  
  4.     if (vdev->fops->open) {  
  5.   
  6.         if (video_is_registered(vdev))  
  7.             ret = vdev->fops->open(filp);  
  8.     }  
  9. }  
  10. static ssize_t v4l2_read(struct file *filp, char __user *buf,  
  11.         size_t sz, loff_t *off)  
  12. {  
  13.     struct video_device *vdev = video_devdata(filp);  
  14.     if (!vdev->fops->read)  
  15.         return -EINVAL;  
  16.     if (video_is_registered(vdev))  
  17.         ret = vdev->fops->read(filp, buf, sz, off);  
  18. }  
  19. static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)  
  20. {  
  21.     struct video_device *vdev = video_devdata(filp);  
  22.     if (!vdev->fops->mmap)  
  23.         return ret;  
  24.     ret = vdev->fops->mmap(filp, vm);  
  25. }  
  26.   
  27. static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
  28. {  
  29.     struct video_device *vdev = video_devdata(filp);  
  30.     if (vdev->fops->unlocked_ioctl) {  
  31.         if (video_is_registered(vdev))  
  32.             ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);  
  33.     } else if (vdev->fops->ioctl) {  
  34.         if (video_is_registered(vdev))  
  35.             ret = vdev->fops->ioctl(filp, cmd, arg);  
  36.     }   
  37. }  
阅读全文
1 0