初识v4l2(五)-------v4l2_ioctl浅析
阅读原文时间:2023年07月10日阅读:2

上一篇文章中,已经介绍了v4l2_open、v4l2_read、v4l2_write的调用过程,相对于v4l2_ioctl,它们是比较简单的。下面来分析v4l2_ioctl。注意在这里还是分析以vivi.c为例,进行分析。

app:          ioctl

---------------------------------------------------------------------------

drv:           v4L2_fops.unlocked_ioctl

      .v4L2_ioctl

        vdev = video_devdata(filp);

        vdev->fops->unlocked_ioctl(filp, cmd, arg);//调用具体设备提供的unlocked_ioctl,因为本篇文章是以vivi.c为例进行分析,.unlocked_ioctl = video_ioctl2

          video_ioctl2

            video_usercopy(file, cmd, arg, __video_do_ioctl)

              __video_do_ioctl

video_ioctl2 

  long video_ioctl2(struct file *file,unsigned int cmd, unsigned long arg)
  {
    //根据命令cmd的不同,调用__video_do_ioctl,将数据拷贝到内核空间

    return video_usercopy(file, cmd, arg, __video_do_ioctl);
  }

__video_do_ioctl

  //以次设备号为下标,从video_device[]中取出对应的video_device,此处就是vivi_template

  struct video_device *vfd = video_devdata(file);

  //获取vivi_template的ioctl_ops

  const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;

  ---------- 

  switch (cmd) {

    /* --- capabilities ------------------------------------------ */

    case VIDIOC_QUERYCAP://cmd命令
    {
      //v4l2设备的能力结构体

      struct v4l2_capability *cap = (struct v4l2_capability *)arg;

      if (!ops->vidioc_querycap)
        break;

      cap->version = LINUX_VERSION_CODE;

      //根据不同的cmd,调用到了ioctl_ops中的vidioc_querycap
      ret = ops->vidioc_querycap(file, fh, cap);

      ----

      break

    }

现总结一下这个过程:

1、video_device被设置成了vivi_template  //在函数vivi_create_instance中被设置

2、vdev->cdev->ops = &v4l2_fops; //在函数__video_register_device中被设置

3、video_device[vdev->minor] = vdev;//在函数__video_register_device中被设置

当用户空间调用ioctl的时候,v4l2_fops的v4l2_ioctl将被调用;

在v4l2_ioctl中,vivi_template->fops->unlocked_ioctl(filp, cmd, arg) 即video_ioctl2函数会被调用;

在video_ioctl2中,__video_do_ioctl函数会被调用;

在__video_do_ioctl中,根据cmd来调用vivi_template中的vivi_ioctl_ops结构体中对应的函数。