V4L2驱动程序架构-1

come from http://blog.csdn.net/shui1025701856/article/details/7459868


1 V4L2简介


video4linux2(V4L2)是Linux内核中关于视频设备的内核驱动,它为Linux中视频设备访问提供了通用接口,在Linux系统中,V4L2驱动的Video设备节点路径通常/dev/video/中的videoX
V4L2驱动对用户空间提供字符设备,主设备号为81,对于视频设备,其次设备号为0-63。除此之外,次设备号为64-127的Radio设备,次设备号为192-223的是Teletext设备,次设备号为224-255的是VBI设备
V4L2驱动的Video设备在用户空间通过各种ioctl调用进行控制,并且可以使用mmap进行内存映射

1.1 V4L2驱动主要使用的ioctl

命令值如下所示:

[csharp] view plaincopy

  1. ---------------------------------------------------------------------  

[csharp] view plaincopy

  1. #define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability)  /*查询能力*/  

  2. #define VIDIO_G_FMT _IOWR('V', 4, struct v4l2_format) /*获得格式*/  

  3. #define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) /*设置格式*/  

  4. #define VIDIOC_REQBUFS _IOWR('V', 8, strut v4l2_requestbuffers) /*申请内存*/  

  5. #define VIDIOC_G_FBUF _IOW('V', 10, struct v4l2_framebuffer) /*获得Framebuffer*/  

  6. #define VIDIOC_S_BUF _IOW('V', 11, struct v4l2_framebuffer) /*设置Framebuffer*/  

  7. #define VIDIOC_OVERLAY _IOW('V', 14, int) /*设置Overlay*/  

  8. #define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer) /*将内存加入队列*/  

  9. #define VIDIOC_DQBUF _IOWR('V', 17, strut v4l2_buffer) /*从队列取出内存*/  

  10. #define VIDIOC_STREAMON _IOW('V', 18, int) /*开始流*/  

  11. #define VIDIOC_STREAMOFF _IOW('V', 19, int) /*停止流*/  

  12. #define VIDIOC_G_CTRL _IOWR('V', 27, struct v4l2_control) /*得到控制*/  

  13. #define VIDIOC_S_CTRL _IOWR('V', 28, struct v4l2_control) /*设置控制*/  

  14. ---------------------------------------------------------------------  



1.2 重要结构


头文件 include/linux/videodev2.h

include/media/v4l2-dev.h

V4L2驱动核心实现文件:driver/media/video/v4l2-dev.c

v4l2-dev.h中定义的video_deviceV4L2驱动程序的核心数据结构

[csharp] view plaincopy

  1. struct video_device  

  2. {  

  3.     const struct v4l2_file_operations *fops;  

  4.     struct cdev *cdev;//字符设备  

  5.     struct device *parent;//父设备  

  6.     struct v4l2_device *v4l2_dev;//父v4l2_device  

  7.     char name[32];//名称  

  8.     int vfl_type;//类型  

  9.     int minor;//次设备号  

  10.     /*释放回调*/  

  11.     void (*release)(struct video_device *vdev);  

  12.     /*ioctl回调*/  

  13.     const struct v4l2_ioctl_ops *ioctl_ops;  

  14. }  

  15. 常用的结构  

  16. 参见/include/linux/videodev2.h  

  17. 1)设备能力结构  

  18. struct v4l2_capability  

  19. {  

  20.     __u8 driver[16];//驱动名  

  21.     __u8 card[32];//例如Hauppauge winTV  

  22.     __u8 bus_info[32];//PCI总线信息  

  23.     __u32 version;//内核版本  

  24.     __u32 capabilities;//设备能力  

  25.     __u32 reserved[4];  

  26. };  

  27. 2)数据格式结构  

  28. struct v4l2_format  

  29. {  

  30.     enum v4l2_buf_type type;//本结构的数据类型  

  31. };  

  32. 3)像素格式结构  

  33. struct v4l2_pix_format  

  34. {  

  35.     __u32   width;//宽度  

  36.     __u32   height;//高度  

  37. }  

  38. 4)请求缓冲  

  39. struct v4l2_requestbuffers  

  40. {  

  41.     __u32   count;//缓存数量  

  42.     enum v4l2_buf_type type;//数据流类型  

  43. }  

  44. 5)数据流类型包括V4L2_MEMORY_MMAP和V4L2_MEMORY_USERPTR  

  45. enum v4l2_memory{  

  46.   

  47. };  


2 V4L2驱动注册

2.1 video_register_device

video4linux2驱动程序的注册drivers/media/video

video_register_device函数用来注册一个v4l驱动程序

[csharp] view plaincopy

  1. int video_register_device(struct video_device *vdev, int type, int nr)  

  2. {  

  3.     return __video_register_device(vdev, type, nr, 1);  

  4. }  

  5. 其中参数type支持的类型如下  

  6. #define VFL_TYPE_GRABBER 0//视频  

  7. #define VFL_TYPE_VBI    1//从视频消隐的时间取得信息的设备  

  8. #define VFL_TYPE_RADIO  2 //广播  

  9. #define VFL_TYPE_VTX    3//视传设备  

  10. #define VFL_TYPE_MAX    4//最大值  

  11. ----------------->返回调用 __video_register_device()  

  12. __video_register_device 函数先检查设备类型,接下来  

  13. 寻找一个可用的子设备号,最后注册相应的字符设备  

  14. static int __video_register_device(struct video_device *vdev, int type, int nr, int warn_if_nr_in_use)  

  15. {  

  16.       

  17. switch (type) {  

  18.         case VFL_TYPE_GRABBER:  

  19.             minor_offset = 0;  

  20.             minor_cnt = 64;  

  21.             break;  

  22.         case VFL_TYPE_RADIO:  

  23.             minor_offset = 64;  

  24.             minor_cnt = 64;  

  25.             break;  

  26.         case VFL_TYPE_VTX:  

  27.             minor_offset = 192;  

  28.             minor_cnt = 32;  

  29.             break;  

  30.         case VFL_TYPE_VBI:  

  31.             minor_offset = 224;  

  32.             minor_cnt = 32;  

  33.             break;  

  34.         nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);  

  35.     }     

  36.     nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);  

  37.     vdev->cdev->ops = &v4l2_fops;  

  38. //注册字符设备  

  39. ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);  

  40.     ret = device_register(&vdev->dev);  

  41. //注册完毕设备信息存储在video_device数组中  

  42.     mutex_lock(&videodev_lock);  

  43.     video_device[vdev->minor] = vdev;  

  44.     mutex_unlock(&videodev_lock);  

  45. }  


2.2 v4l2_fops接口

v4l2_fopsvideo4linux2设备提供了统一的应用层接口,v4l2_fops定义如下

[csharp] view plaincopy

  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.         .release = v4l2_release,  

  10.         .poll = v4l2_poll,  

  11.         .llseek = no_llseek,  

  12.   

  13. };  

  14. v4l2_fops中的成员函数最终要调用struct video_device->fops中相应的成员  

  15. struct video_device->fops是具体video4linux2摄像头驱动程序必须实现的接口  

  16. static ssize_t v4l2_read(struct file *filp, char __user *buf, size_t sz, loff_t *off)  

  17. {  

  18.     return vdev->fops->read(filp, buf, sz, off);  

  19. }  


2.3 /drivers/media/video/samsung/fimc/s3c_fimc_core.c

驱动探测函数s3c_fimc_probe定义

[csharp] view plaincopy

  1. static int s3c_fimc_probe(struct platform_device *dev)  

  2. {  

  3.     ctrl = s3c_fimc_register_controller(pdev);  

  4.       

  5.     clk_enable(ctrl->clock);//使能时钟  

  6.     //注册V4L2驱动  

  7.     ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id);  

  8. }  

  9. s3c_fimc_register_contoller函数主要用来分配资源与申请中断  

  10. static struct s3c_fimc_control *s3c_fimc_register_controller(struct platform_device *pdev)  

  11. {  

  12.     ctrl->vd = &s3c_fimc_video_device[id];  

  13.     //申请中断  

  14.     ctrl->irq = platform_get_irq(pdev, 0);  

  15.     if(request_irq(ctrl->irq, s3c_fimc_irq, IRQF_DISABLED, ctrl->name, ctrl))  

  16. };  

  17. struct video_device s3c_fimc_video_device[S3C_FIMC_MAX_CTRLS] = {  

  18.     [0] = {  

  19.         .vfl_type = VID_TYPE_OVERLAY | VID_TYPE_CAPTURE | VID_TYPE_CLIPPING | VID_TYPE_SCALES,  

  20.         .fops = &s3c_fimc_fops,  

  21.         .ioctl_ops = &s3c_fimc_v4l2_ops,  

  22.         .release  = s3c_fimc_vdev_release,  

  23.           

  24.         .name = "sc3_video0",  

  25.     },  

  26. }  

  27. s3c_fimc_v4l2_ops,是在drivers/media/video/samsung/fimc中实现的v4l2_ioctl_ops,在用户空间进行ioctl等调用时,要调用到具体实现的各个函数指针  


3 V4L2 操作

3.1 s3c_fimc_open

[csharp] view plaincopy

  1. static int s3c_fimc_open(struct file *filp)  

  2. {  

  3.     struct s3c_fimc_control *ctrl;  

  4.     int id, ret;  

  5.   

  6.     id =0;  

  7.     ctrl = &s3c_fimc.ctrl[id];  

  8.     mutex_lock(&ctrl->lock);  

  9.     if (atomic_read(&ctrl->in_use)) {  

  10.         ret = -EBUSY;  

  11.         goto resource_busy;  

  12.     } else {  

  13.         atomic_inc(&ctrl->in_use);  

  14.         s3c_fimc_reset(ctrl);  

  15.         filp->private_data = ctrl;  

  16.     }  

  17.     mutex_unlock(&ctrl->lock);  

  18.     return 0;  

  19. resource_busy:  

  20.     mutex_unlock(&ctrl->lock);  

  21.     return ret;  

  22. }  

  23. 用户空间  

  24. 打开设备文件  

  25. fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);  


3.2 获取设备的capability,查看设备有什么功能

1)结构体

[csharp] view plaincopy

  1. struct v4l2_capability cap;  

  2. ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);  

  3. /include/linux/videodev2.h  

  4. struct v4l2_capability {  

  5.     __u8    driver[16]; /* i.e. "bttv" */  

  6.     __u8    card[32];   /* i.e. "Hauppauge WinTV" */  

  7.     __u8    bus_info[32];   /* "PCI:" + pci_name(pci_dev) */  

  8.     __u32   version;        /* should use KERNEL_VERSION() */  

  9.     __u32   capabilities;   /* Device capabilities */  

  10.     __u32   reserved[4];  

  11. };  

  12. 驱动实现  

  13.   

  14. static int s3c_fimc_v4l2_querycap(struct file *filp, void *fh,  

  15.                     struct v4l2_capability *cap)  

  16. {  

  17.     struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;  

  18.     strcpy(cap->driver, "Samsung FIMC Driver");  

  19.     strlcpy(cap->card, ctrl->vd->name, sizeof(cap->card));  

  20.     sprintf(cap->bus_info, "FIMC AHB-bus");  

  21.     cap->version = 0;  

  22.     cap->capabilities = (V4L2_CAP_VIDEO_OVERLAY | \  

  23.                 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING);  

  24.     return 0;  

  25. }  

  26. 应用层调用  

  27. static int video_capability(int fd)  

  28. {  

  29.     int ret = 0;  

  30.     /***********get the device capability********/  

  31.     struct v4l2_capability cap;  

  32.     ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);  

  33.     if (ret < 0) {  

  34.         perror("VIDIOC_QUERYCAP failed ");  

  35.         return ret;  

  36.     }  

  37.       

  38.     printf("\n****Capability informations****\n");  

  39.     printf("driver:   %s\n", cap.driver);  

  40.       

  41.     if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)  

  42.         printf("Capture capability is supported\n");  

  43.   

  44.     if (cap.capabilities & V4L2_CAP_STREAMING)   

  45.         printf("Streaming capability is supported\n");  

  46.           

  47.     if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)   

  48.         printf("Overlay capability is supported\n");  

  49.       

  50.     return 0;  

  51. }  


3.3 选择视频输入,一个视频设备可以有多个视频输入

[csharp] view plaincopy

  1. 结构体  

  2. struct v4l2_input input;  

  3. int index;  

  4. 得到INPUT  

  5. ret = ioctl(fd, VIDIOC_G_INPUT, &index);      

  6. input.index = index;  

  7. 列举INPUT  

  8. ret = ioctl(fd, VIDIOC_ENUMINPUT, &input);  

  9. 设置INPUT  

  10. ret = ioctl(fd, VIDIOC_S_INPUT, &index);  

  11.   

  12. struct v4l2_input {  

  13.     __u32        index;     /*  Which input */  

  14.     __u8         name[32];      /*  Label */  

  15.     __u32        type;      /*  Type of input */  

  16.     __u32        audioset;      /*  Associated audios (bitfield) */  

  17.     __u32        tuner;             /*  Associated tuner */  

  18.     v4l2_std_id  std;  

  19.     __u32        status;  

  20.     __u32        capabilities;  

  21.     __u32        reserved[3];  

  22. };  

  23.   

  24. Ioctl: VIDIOC_S_INPUT This IOCTL takes pointer to integer containing index of the input which has to be set. Application will provide the index number as an argument.   

  25.     0 - Composite input,  

  26.     1 - S-Video input.  

  27. 驱动  

  28. static int s3c_fimc_v4l2_s_input(struct file *filp, void *fh,  

  29.                     unsigned int i)  

  30. {  

  31.     struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;  

  32.   

  33.     if (i >= S3C_FIMC_MAX_INPUT_TYPES)  

  34.         return -EINVAL;  

  35.   

  36.     ctrl->v4l2.input = &s3c_fimc_input_types[i];  

  37.   

  38.     if (s3c_fimc_input_types[i].type == V4L2_INPUT_TYPE_CAMERA)  

  39.         ctrl->in_type = PATH_IN_ITU_CAMERA;  

  40.     else  

  41.         ctrl->in_type = PATH_IN_DMA;  

  42.   

  43.     return 0;  

  44. }  

  45. static struct v4l2_input s3c_fimc_input_types[] = {  

  46.     {  

  47.         .index      = 0,  

  48.         .name       = "External Camera Input",  

  49.         .type       = V4L2_INPUT_TYPE_CAMERA,  

  50.         .audioset   = 1,  

  51.         .tuner      = 0,  

  52.         .std        = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,  

  53.         .status     = 0,  

  54.     },   

  55.     {  

  56.         .index      = 1,  

  57.         .name       = "Memory Input",  

  58.         .type       = V4L2_INPUT_TYPE_MEMORY,  

  59.         .audioset   = 2,  

  60.         .tuner      = 0,  

  61.         .std        = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,  

  62.         .status     = 0,  

  63.     }  

  64. };  

  65. static int s3c_fimc_v4l2_enum_input(struct file *filp, void *fh,  

  66.                     struct v4l2_input *i)  

  67. {  

  68.     if (i->index >= S3C_FIMC_MAX_INPUT_TYPES)  

  69.         return -EINVAL;  

  70.   

  71.     memcpy(i, &s3c_fimc_input_types[i->index], sizeof(struct v4l2_input));  

  72.   

  73.     return 0;  

  74. }  

  75. 应用  

  76. static int video_input(int fd)  

  77. {  

  78.     /***********get and set the VIDIO INPUT********/  

  79.     int ret = 0;  

  80.     struct v4l2_input input;//视频输入信息,对应命令VIDIOC_ENUMINPUT   

  81.     int index;  

  82.     index = 0;    //0 - Composite input, 1 - S-Video input.  

  83.      

  84.     ret = ioctl (fd, VIDIOC_S_INPUT, &index);  

  85.     if (ret < 0) {  

  86.         perror ("VIDIOC_S_INPUT");  

  87.         return ret;  

  88.     }  

  89.   

  90.     input.index = index;  

  91.     ret = ioctl (fd, VIDIOC_ENUMINPUT, &input);  

  92.     if (ret < 0){  

  93.         perror ("VIDIOC_ENUMINPUT");  

  94.         return ret;  

  95.     }  

  96.     printf("\n****input informations****\n");  

  97.     printf("name of the input = %s\n", input.name);  

  98.     return 0;  

  99. }  

你可能感兴趣的:(V4L)