• 13、虚拟驱动vivi.c注册过程分析及怎么写V4L2驱动及启动过程


    UVC设备也是一个usb设备,在uvc_driver.c中的init函数会调用usb_register注册,根据id_table发送可支持的设备后调用probe函数,其会去uvc_register_chains注册所有uvc_device,前面说的根据id_table匹配的过程是usb_bus总线,uvc是另一个东西了

    vivi.c是一个摄像头驱动模板或者实例,安装vivi模块后会产生一个虚拟的摄像头,使用应用程序可以获得其提供的虚拟数据并显示。

    vivi_init
      vivi_create_instance
        v4l2_device_register // 不是主要, 只是用于初始化一些东西,比如自旋锁、引用计数

        hdl = &dev->ctrl_handler;//hdl 是用于保存子设备控制方法集的结构体,对于视频设备这些ctrls包括设置亮度、饱和度、对比度和 清晰度                                                                                      等,用链表的方式来保存ctrls,可以通过v4l2_ctrl_new_std函数向链表添加ctrls。在下面的代码中用到了这个函数。
        video_device_alloc 
        // 设置
          1. vfd:
            .fops = &vivi_fops,
            .ioctl_ops = &vivi_ioctl_ops,
            .release = video_device_release,
          2.
            vfd->v4l2_dev = &dev->v4l2_dev;
          3. 设置"ctrl属性",并挂接到hdl的链表上(用于应用的ioctl)://后续会根据这里设置的属性调用真正的ioctl,用户空间可以通过ioctl的VIDIOC_S_CTRL指令调用到hdl(v4l2_ctrl_handler结构体)
            v4l2_ctrl_handler_init(hdl, 11);
            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, &vivi_ctrl_ops,
              V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
            dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
              V4L2_CID_CONTRAST, 0, 255, 1, 16);

        video_register_device(video_device, type:VFL_TYPE_GRABBER, nr)
          __video_register_device
            vdev->cdev = cdev_alloc();
            vdev->cdev->ops = &v4l2_fops;//真正的fops是vivi_fops
            cdev_add

            video_device[vdev->minor] = vdev;//把包含真正fops结构体的变量放入video_device数组,以次设备号为下标

              if (vdev->ctrl_handler == NULL)
                vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;

    分析vivi.c的open,read,write,ioctl过程
    1. open
    app: open("/dev/video0",....)
    ---------------------------------------------------
    drv: v4l2_fops.v4l2_open
        vdev = video_devdata(filp); // 根据次设备号从数组中得到video_device
        ret = vdev->fops->open(filp);
          vivi_ioctl_ops.open
            v4l2_fh_open

    2. read
    app: read ....
    ---------------------------------------------------
    drv: v4l2_fops.v4l2_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);
          video_ioctl2
            video_usercopy(file, cmd, arg, __video_do_ioctl);
              __video_do_ioctl
                struct video_device *vfd = video_devdata(file);
                根据应用传入的cmd来获得、设置"某些属性"

    v4l2_ctrl_handler的使用过程:(v4l2_ctrl_handler是属性链表,在video_device_alloc被设置)
      __video_do_ioctl//往上面数5行,video_usercopy里面调用__video_do_ioctl这个函数,最终ioctrl会表用vivi_ioctl_ops结构体里面的ioctrl函数
        struct video_device *vfd = video_devdata(file);

        case VIDIOC_QUERYCTRL:
        {
          struct v4l2_queryctrl *p = arg;

          if (vfh && vfh->ctrl_handler)
            ret = v4l2_queryctrl(vfh->ctrl_handler, p);
          else if (vfd->ctrl_handler) // 在哪设置?在video_register_device中vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler,vdev->v4l2_dev在video_register_device前通过vfd->v4l2_dev = &dev->v4l2_dev复制,这里的dev是vivi_device,dev->v4l2_dev.ctrl_handler = hdl,这里的hdl就是vivi_init过程中在v4l2_ctrl_new_std里面被设置,vfd就是video_device结构体类型;ctrl_handler是v4l2_ctrl_handler

            ret = v4l2_queryctrl(vfd->ctrl_handler, p);
              // 根据ID在ctrl_handler里找到v4l2_ctrl,返回它的值,ID在v4l2_ctrl_new_std里面被设置

     怎么写V4L2驱动?

    1、分配、设置、注册V4L2_device  (v4l2_device_register,v4l2_device)(仅初始化,并提供一些属性参数供ioctl设置,辅助作用,属性在这个v4l2_ctrl_handler里面被管理,v4l2_ctrl来表示属性,v4l2_ctrl_new_std来创建v4l2_ctrl,放入v4l2_ctrl_handler链表)

    2、分配video_device(video_device_alloc)

    3、设置 video_device()

      vfd->v4l2_dev = &dev->v4l2_dev;//把video_device和第一部里面设置的属性关联起来,后面会用来ioctl设置属性,比如亮度、饱和度等参数

      fops=真真的v4l2_file_operations,v4l2_fops中的read等会指向这里设置的fops;

      ioctl_ops=真真的ioctl函数,v4l2_fops->unlocked_ioctl调用v4l2_file_operations->unlocked_ioctl,调用ioctl_ops

  • 相关阅读:
    scratch少儿编程第一季——04、想要做到有的放矢,瞄准方向很重要
    scratch少儿编程第一季——02、scratch界面介绍
    scratch少儿编程第一季——01、初识图形化界面编程的神器
    Scratch—点亮生日蜡烛
    scratch少儿编程——03、动作:运动的开始,游戏的基础。
    画一个秘密花园 | Scratch 3.0 艺术项目
    scratch少儿编程第一季——01、初识图形化界面编程的神器
    scratch少儿编程第一季——02、scratch界面介绍
    mysql优化一之查询优化
    mysql优化二之锁机制
  • 原文地址:https://www.cnblogs.com/liusiluandzhangkun/p/8689126.html
Copyright © 2020-2023  润新知