v4l2 video设备注册和调用过程

 

一、 注册一个video_device设备
它代表系统/dev/videox设备节点的实际的物理设备。
下边一内核版本2.6.32种成熟的omap2432处理器摄像头控制器模块驱动为例分析:
下边的代码在driver/media/video/omap24xxcam.c中
1、Video device的操作函数集

static struct v4l2_file_operations omap24xxcam_fops = {
 .ioctl  = video_ioctl2,
 .poll  = omap24xxcam_poll,
 .mmap  = omap24xxcam_mmap,
 .open  = omap24xxcam_open,
 .release = omap24xxcam_release,
};



2、Video device控制操作函数集

static const struct v4l2_ioctl_ops omap24xxcam_ioctl_fops = {
 .vidioc_querycap = vidioc_querycap,
 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
 .vidioc_reqbufs  = vidioc_reqbufs,
 .vidioc_querybuf = vidioc_querybuf,
 .vidioc_qbuf  = vidioc_qbuf,
 .vidioc_dqbuf  = vidioc_dqbuf,
 .vidioc_streamon = vidioc_streamon,
 .vidioc_streamoff = vidioc_streamoff,
 .vidioc_enum_input = vidioc_enum_input,
 .vidioc_g_input  = vidioc_g_input,
 .vidioc_s_input  = vidioc_s_input,
 .vidioc_queryctrl = vidioc_queryctrl,
 .vidioc_g_ctrl  = vidioc_g_ctrl,
 .vidioc_s_ctrl  = vidioc_s_ctrl,
 .vidioc_g_parm  = vidioc_g_parm,
 .vidioc_s_parm  = vidioc_s_parm,
};


 

3、注册函数:omap24xxcam_device_register

static int omap24xxcam_device_register(struct v4l2_int_device *s)
{
 struct omap24xxcam_device *cam = s->u.slave->master->priv;
 struct video_device *vfd;//定义struct video_device结构体
 int rval;

。。。。。。

 /* initialize the video_device struct */
 vfd = cam->vfd = video_device_alloc();
 if (!vfd) {
  dev_err(cam->dev, "could not allocate video device struct\n");
  rval = -ENOMEM;
  goto err;
 }
 vfd->release = video_device_release;

 vfd->parent = cam->dev;

 strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
//该video device设备V4L2操作函数集,在下边定义,这个通过最顶级字符设备的响应操作函数调用
 vfd->fops   = &omap24xxcam_fops; 
 vfd->minor   = -1;
//该video device设备控制操作,和vfd->fops中的ioctl可能重复,下边进一步分析。
 vfd->ioctl_ops   = &omap24xxcam_ioctl_fops; 
 omap24xxcam_hwinit(cam);

 rval = omap24xxcam_sensor_init(cam);
 if (rval)
  goto err;

//注册video device,VFL_TYPE_GRABBER表示注册的是视频处理设备,video_nr=-1表示自动分配从设备号
 if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
  dev_err(cam->dev, "could not register V4L device\n");
  vfd->minor = -1;
  rval = -EBUSY;
  goto err;
 }

。。。。。。。

err:
 omap24xxcam_device_unregister(s);

 return rval;
}


 

二、 调用过程
应用程序的read、write、ioctl等操作函数传到内核层
以ioctl为例作说明:
1、最顶层的调用
在driver/media/video/v4l2-dev.c中:

static int v4l2_ioctl(struct inode *inode, struct file *filp,
  unsigned int cmd, unsigned long arg)
{
 //根据次设备号从video_device[VIDEO_NUM_DEVICES]数组中得到当前操作的video device
 struct video_device *vdev = video_devdata(filp);

 if (!vdev->fops->ioctl)
  return -ENOTTY;
 /* Allow ioctl to continue even if the device was unregistered.
    Things like dequeueing buffers might still be useful. */
 return vdev->fops->ioctl(filp, cmd, arg);
}


 

2、自己实现的操作函数集
根据上边注册时填充的fops,vdev->fops->ioctl(filp, cmd, arg)调用下边函数:
(在driver/media/video/omap24xxcam.c)

static struct v4l2_file_operations omap24xxcam_fops = {
 .ioctl  = video_ioctl2,
 。。。。。
}


 

3、中间层处理调用
Video_ioctl2是定义在driver/media/video/v4l2-ioctl.c中的函数:

long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg)
{
 char sbuf[128];
 void    *mbuf = NULL;
 void *parg = NULL;
 long err  = -EINVAL;
 int     is_ext_ctrl;
 size_t  ctrls_size = 0;
 void __user *user_ptr = NULL;

控制命令处理。。。。。。。。。。

 /* Handles IOCTL */
 err = __video_do_ioctl(file, cmd, parg);
 if (err == -ENOIOCTLCMD)
  err = -EINVAL;
 if (is_ext_ctrl) {
  struct v4l2_ext_controls *p = parg;

  p->controls = (void *)user_ptr;
  if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
   err = -EFAULT;
  goto out_ext_ctrl;
 }
 if (err < 0)
  goto out;

错误处理。。。。。。。。。

}


 

4、根据命令调用相应的处理函数
下边就是根据传入的控制参数,调用相应的已经注册的v4l2_ioctl_ops操作处理

static long __video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
//得到当前操作的video device
 struct video_device *vfd = video_devdata(file);
//v4l2 控制操作函数集,在video device注册时赋值。
 const struct v4l2_ioctl_ops *ops = vfd->omap24xxcam_ioctl_fops;
 void *fh = file->private_data;
 long ret = -EINVAL;

参数错误处理。。。。。


 

#ifdef CONFIG_VIDEO_V4L1_COMPAT
 /***********************************************************
  Handles calls to the obsoleted V4L1 API
  Due to the nature of VIDIOCGMBUF, each driver that supports
  V4L1 should implement its own handler for this ioctl.
  ***********************************************************/

 /* --- streaming capture ------------------------------------- */
 if (cmd == VIDIOCGMBUF) {
  struct video_mbuf *p = arg;

  if (!ops->vidiocgmbuf)
   return ret;
  ret = ops->vidiocgmbuf(file, fh, p);
  if (!ret)
   dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
      p->size, p->frames,
      (unsigned long)p->offsets);
  return ret;
 }

 /********************************************************
  All other V4L1 calls are handled by v4l1_compat module.
  Those calls will be translated into V4L2 calls, and
  __video_do_ioctl will be called again, with one or more
  V4L2 ioctls.
  ********************************************************/
 if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE)
  return v4l_compat_translate_ioctl(file, cmd, arg,
      __video_do_ioctl);
#endif

 switch (cmd) {
 /* --- capabilities ------------------------------------------ */
 case VIDIOC_QUERYCAP:
 {
  struct v4l2_capability *cap = (struct v4l2_capability *)arg;

  if (!ops->vidioc_querycap)
   break;

  ret = ops->vidioc_querycap(file, fh, cap);
  if (!ret)
   dbgarg(cmd, "driver=%s, card=%s, bus=%s, "
     "version=0x%08x, "
     "capabilities=0x%08x\n",
     cap->driver, cap->card, cap->bus_info,
     cap->version,
     cap->capabilities);
  break;
 }


}


 

你可能感兴趣的:(v4l2)