加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

摄像头驱动——V4L2框架分析

发布时间:2020-12-14 02:10:17 所属栏目:Linux 来源:网络整理
导读:一、概述 Video for Linux 2,简称V4l2,是Linux内核中关于视频设备的内核驱动框架,为上层的访问底层的视频设备提供了统一的接口。 摄像头驱动是属于字符设备驱动程序。(分析linux3.4.2内核) 二、如何写字符设备驱动 1、对于简单的驱动: 1).构造一个fil

一、概述

Video for Linux 2,简称V4l2,是Linux内核中关于视频设备的内核驱动框架,为上层的访问底层的视频设备提供了统一的接口。

摄像头驱动是属于字符设备驱动程序。(分析linux3.4.2内核)

二、如何写字符设备驱动

1、对于简单的驱动:

  1).构造一个file_operations:.open=drv_open .read=drv_read
  2).告诉内核:register_chrdev(主设备号,名字,&file_operations)
  3).入口函数:调用register_chrdev
  4).出口函数:卸载
  一般采用register_chrdev的代替方法:分配、设置cdev,cdev_add

2、对于稍复杂的驱动程序采用分层思想

例如LCD驱动中分为两层:上层通用的核心层内核已经帮我们做好,即在fbmem.c
  1.构造file_operations(open/ read /write ...)
  2.注册?

?  3.入口、出口

我们做的是硬件相关层,供上层file_operations调用
  1.分配一个fb_info 结构体
  2.设置
  3.注册
  4.硬件相关的操作

三、分析V4L2框架

把usb设备接到系统前台,会有打印信息,根据打印信息在内核里找出驱动,用dmsg命令查看;
grep "Found UVC" * -nR 搜索 在uvc_driver.c里,这是个硬件相关的驱动。

分析代码,猜测V4L2 ?框架 肯定也是分为至少两层? 。

?

应用层:

/*调用 open read write -->调用 v4l2_fops 里的 open read write->调用硬件相关层的video_device 里提供的函数*/
----------------------------------------------------------------------------------------------------------
核心层:v4l2-dev.c ? __video_register_device ?
? ?   构造:v4l2_fops(

        .read = v4l2_read,
? ?       ???.write = v4l2_write,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.open = v4l2_open,...)
? ?   注册:
? ?     vdev->cdev = cdev_alloc(); ? ? //1.字符设备cdev_alloc
?     ? vdev->cdev->ops = &v4l2_fops; ? //2.设置fops
? ?     cdev_add(vdev->cdev,MKDEV(VIDEO_MAJOR,vdev->minor),1); ?//3.cdev_add


----------------------------------------------------------------------------------------------------------
硬件相关层:如uvc_driver.c ? Found UVC

  ? ? ?->v4l2_device_register(这个不重要)
? ?   ->video_device_alloc->video_register_device(向核心层注册)?
? ? ? ? ? ?->v4l2-dev.h->__video_register_device(v4l2-dev.c) ? ??
---------------------------------------------------------------------------------------------------------? ??
? ? 即分配结构体 ?video_device (里面的函数供上层v4l2_fops调用) ??
? ? 设置 ?注册video_register_device ? ? ? ? ? ?

?

四、通过vivi.c分析v4l2核心驱动框架

(virtual video driver )虚拟视频驱动

?分析如下:

vivi_init (入口函数)
     vivi_create_instance(i);
        v4l2_device_register  //非主要,仅初始化一些锁等,实际未注册啥
            spin_lock_init(&v4l2_dev->lock);
                ...
            get_device(dev);
            v4l2_dev->dev = dev;
        vfd = video_device_alloc(); //分配video_device
        //设置
        1.*vfd = vivi_template;        //内容设置为vivi_template
              /*最底层的vivi 操作函数*/
              static struct video_device vivi_template = {
                  .name             = "vivi",.fops ? ? ? ? ? = &vivi_fops,.ioctl_ops        = &vivi_ioctl_ops,...
                  };
          
        2.vfd->v4l2_dev = &dev->v4l2_dev; 
        
        3.设置“Ctrl属性”(用于APP的ioctl),音量、亮度、增益等
            dev->volume = v4l2_ctrl_new_std(hdl,&vivi_ctrl_ops,V4L2_CID_AUDIO_VOLUME,0,255,1,200);
            dev->brightness = v4l2_ctrl_new_std(hdl,V4L2_CID_BRIGHTNESS,127);
            dev->contrast = v4l2_ctrl_new_std(hdl,V4L2_CID_CONTRAST,16);
                ...
                              //    结构体vfd      类型     number
        video_register_device(video_device,VFL_TYPE_GRABBER,nr); //向上注册
            __video_register_device    
            /* Part 1: check device type */  检验设备类型
                ...
            /* Part 2: find a free minor,device node number and device index. */
                ...                           互斥锁相关
            /* Part 3: Initialize the character device */ 初始化字符设备
            vdev->cdev = cdev_alloc();
            vdev->cdev->ops = &v4l2_fops;
            cdev_add
                ...
            /* Part 6: Activate this minor. The char device can now be used. */
            video_device[vdev->minor] = vdev; //以次设备号为下标,将vdev存入数组

************************************************************************************
分析vivi.c的open、read、write、ioctl过程
1. open app: open ("/dev/video0",...) ---------------------------------------------- drv: v4l2_open vdev = video_devdata(filp); //根据次设备号从数组中得到video_device ret = vdev->fops->open(filp);//调用open函数 调用vivi.c 里的v4l2_fh_open 2. read app: read... ---------------------------------------------- drv: v412_read struct video_device *vdev = video_devdata(filp); ret = vdev->fops->read(filp,buf,sz,off); 3. ioctl app: ioctl ---------------------------------------------- drv: v4l2_fops.unlocked_ioctl v4l2_ioctl struct video_device *vdev = video_devdata(filp); ret = vdev->fops->unlocked_ioctl(filp,cmd,arg); 调用vivi.c 里的video_ioctl2 /*把用户空间的参数复制进来,然后调用__video_do_ioctl*/ video_usercopy(file,arg,__video_do_ioctl); __video_do_ioctl *vdev = video_devdata(filp) 根据APP传入的cmd来获得、设置某些属性
                 /*在vivi.c 里一开始的vivi_create_instance里设置*/

?由上分析可知vivi.c主要完成了以下工作:

1 、初始化 v4l2_device结构体(代表一个 v4l2设备)?

   v4l2_device_register、?v4l2_device

2、分配video_device结构体

   vfd = video_device_alloc()

3、设置video_device结构

   a、 .vfd->v4l2_dev

   b、vfd:

      .fops? ? 设置vfd的fops 里的open、read、write 被上层调用

      .ioctl_ops? ?最终会调用到ioctl(设置属性被上层调用??)

4、 注册video_device结构体

  (video_device 是内核对 v4l2_device的官方封装,用于管理v4l2_device数据),向上层用户提供访问接口
  ? video_register_device

?

:APP可以通过ioctl来设置(获得)亮度等信息,在驱动程序里,谁来接收、存储、设置到硬件(提供这些信息)?

答:在驱动程序中抽象出来一个结构体v4l2_ctrl,每个Ctrl对应其中的一项(音量、亮度等等);
? ? ? ?由v4l2_ctrl_handler来管理他们

  1.初始化
?    ? v4l2_ctrl_handler_init?
? ???2.设置
? ?   ?v4l2_ctrl_new_std
? ?    v4l2_ctrl_new_custom
?    ? 这些函数就是创建各个属性,并且放入v4l2_ctrl_handler的链表
? ? ?3.跟vdev关联
? ?    dev->v4l2_dev.ctrl_handler = hdl;

小结:

v4l2框架并未脱离字符设备驱动框架,只是ioctl的实现较为复杂。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读