v4l2 video设备注册和调用过程

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

  1. static struct v4l2_file_operations omap24xxcam_fops = {  
  2.  .ioctl  = video_ioctl2,  
  3.  .poll  = omap24xxcam_poll,  
  4.  .mmap  = omap24xxcam_mmap,  
  5.  .open  = omap24xxcam_open,  
  6.  .release = omap24xxcam_release,  
  7. };  



2、Video device控制操作函数集

  1. static const struct v4l2_ioctl_ops omap24xxcam_ioctl_fops = {  
  2.  .vidioc_querycap = vidioc_querycap,  
  3.  .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,  
  4.  .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,  
  5.  .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,  
  6.  .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,  
  7.  .vidioc_reqbufs  = vidioc_reqbufs,  
  8.  .vidioc_querybuf = vidioc_querybuf,  
  9.  .vidioc_qbuf  = vidioc_qbuf,  
  10.  .vidioc_dqbuf  = vidioc_dqbuf,  
  11.  .vidioc_streamon = vidioc_streamon,  
  12.  .vidioc_streamoff = vidioc_streamoff,  
  13.  .vidioc_enum_input = vidioc_enum_input,  
  14.  .vidioc_g_input  = vidioc_g_input,  
  15.  .vidioc_s_input  = vidioc_s_input,  
  16.  .vidioc_queryctrl = vidioc_queryctrl,  
  17.  .vidioc_g_ctrl  = vidioc_g_ctrl,  
  18.  .vidioc_s_ctrl  = vidioc_s_ctrl,  
  19.  .vidioc_g_parm  = vidioc_g_parm,  
  20.  .vidioc_s_parm  = vidioc_s_parm,  
  21. };  


 

3、注册函数:omap24xxcam_device_register

  1. static int omap24xxcam_device_register(struct v4l2_int_device *s)  
  2. {  
  3.  struct omap24xxcam_device *cam = s->u.slave->master->priv;  
  4.  struct video_device *vfd;//定义struct video_device结构体  
  5.  int rval;  
  6.   
  7. 。。。。。。  
  8.   
  9.  /* initialize the video_device struct */  
  10.  vfd = cam->vfd = video_device_alloc();  
  11.  if (!vfd) {  
  12.   dev_err(cam->dev, "could not allocate video device struct\n");  
  13.   rval = -ENOMEM;  
  14.   goto err;  
  15.  }  
  16.  vfd->release = video_device_release;  
  17.   
  18.  vfd->parent = cam->dev;  
  19.   
  20.  strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));  
  21. //该video device设备V4L2操作函数集,在下边定义,这个通过最顶级字符设备的响应操作函数调用  
  22.  vfd->fops   = &omap24xxcam_fops;   
  23.  vfd->minor   = -1;  
  24. //该video device设备控制操作,和vfd->fops中的ioctl可能重复,下边进一步分析。  
  25.  vfd->ioctl_ops   = &omap24xxcam_ioctl_fops;   
  26.  omap24xxcam_hwinit(cam);  
  27.   
  28.  rval = omap24xxcam_sensor_init(cam);  
  29.  if (rval)  
  30.   goto err;  
  31.   
  32. //注册video device,VFL_TYPE_GRABBER表示注册的是视频处理设备,video_nr=-1表示自动分配从设备号  
  33.  if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {  
  34.   dev_err(cam->dev, "could not register V4L device\n");  
  35.   vfd->minor = -1;  
  36.   rval = -EBUSY;  
  37.   goto err;  
  38.  }  
  39.   
  40. 。。。。。。。  
  41.   
  42. err:  
  43.  omap24xxcam_device_unregister(s);  
  44.   
  45.  return rval;  
  46. }  


 

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

  1. static int v4l2_ioctl(struct inode *inode, struct file *filp,  
  2.   unsigned int cmd, unsigned long arg)  
  3. {  
  4.  //根据次设备号从video_device[VIDEO_NUM_DEVICES]数组中得到当前操作的video device  
  5.  struct video_device *vdev = video_devdata(filp);  
  6.   
  7.  if (!vdev->fops->ioctl)  
  8.   return -ENOTTY;  
  9.  /* Allow ioctl to continue even if the device was unregistered. 
  10.     Things like dequeueing buffers might still be useful. */  
  11.  return vdev->fops->ioctl(filp, cmd, arg);  
  12. }  


 

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

  1. static struct v4l2_file_operations omap24xxcam_fops = {  
  2.  .ioctl  = video_ioctl2,  
  3.  。。。。。  
  4. }  


 

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

  1. long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg)  
  2. {  
  3.  char sbuf[128];  
  4.  void    *mbuf = NULL;  
  5.  void *parg = NULL;  
  6.  long err  = -EINVAL;  
  7.  int     is_ext_ctrl;  
  8.  size_t  ctrls_size = 0;  
  9.  void __user *user_ptr = NULL;  
  10.   
  11. 控制命令处理。。。。。。。。。。  
  12.   
  13.  /* Handles IOCTL */  
  14.  err = __video_do_ioctl(file, cmd, parg);  
  15.  if (err == -ENOIOCTLCMD)  
  16.   err = -EINVAL;  
  17.  if (is_ext_ctrl) {  
  18.   struct v4l2_ext_controls *p = parg;  
  19.   
  20.   p->controls = (void *)user_ptr;  
  21.   if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))  
  22.    err = -EFAULT;  
  23.   goto out_ext_ctrl;  
  24.  }  
  25.  if (err < 0)  
  26.   goto out;  
  27.   
  28. 错误处理。。。。。。。。。  
  29.   
  30. }  


 

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

  1. static long __video_do_ioctl(struct file *file, unsigned int cmd, void *arg)  
  2. {  
  3. //得到当前操作的video device  
  4.  struct video_device *vfd = video_devdata(file);  
  5. //v4l2 控制操作函数集,在video device注册时赋值。  
  6.  const struct v4l2_ioctl_ops *ops = vfd->omap24xxcam_ioctl_fops;  
  7.  void *fh = file->private_data;  
  8.  long ret = -EINVAL;  
  9.   
  10. 参数错误处理。。。。。  


 

  1. #ifdef CONFIG_VIDEO_V4L1_COMPAT  
  2.  /*********************************************************** 
  3.   Handles calls to the obsoleted V4L1 API 
  4.   Due to the nature of VIDIOCGMBUF, each driver that supports 
  5.   V4L1 should implement its own handler for this ioctl. 
  6.   ***********************************************************/  
  7.   
  8.  /* --- streaming capture ------------------------------------- */  
  9.  if (cmd == VIDIOCGMBUF) {  
  10.   struct video_mbuf *p = arg;  
  11.   
  12.   if (!ops->vidiocgmbuf)  
  13.    return ret;  
  14.   ret = ops->vidiocgmbuf(file, fh, p);  
  15.   if (!ret)  
  16.    dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n",  
  17.       p->size, p->frames,  
  18.       (unsigned long)p->offsets);  
  19.   return ret;  
  20.  }  
  21.   
  22.  /******************************************************** 
  23.   All other V4L1 calls are handled by v4l1_compat module. 
  24.   Those calls will be translated into V4L2 calls, and 
  25.   __video_do_ioctl will be called again, with one or more 
  26.   V4L2 ioctls. 
  27.   ********************************************************/  
  28.  if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE)  
  29.   return v4l_compat_translate_ioctl(file, cmd, arg,  
  30.       __video_do_ioctl);  
  31. #endif  
  32.   
  33.  switch (cmd) {  
  34.  /* --- capabilities ------------------------------------------ */  
  35.  case VIDIOC_QUERYCAP:  
  36.  {  
  37.   struct v4l2_capability *cap = (struct v4l2_capability *)arg;  
  38.   
  39.   if (!ops->vidioc_querycap)  
  40.    break;  
  41.   
  42.   ret = ops->vidioc_querycap(file, fh, cap);  
  43.   if (!ret)  
  44.    dbgarg(cmd, "driver=%s, card=%s, bus=%s, "  
  45.      "version=0x%08x, "  
  46.      "capabilities=0x%08x\n",  
  47.      cap->driver, cap->card, cap->bus_info,  
  48.      cap->version,  
  49.      cap->capabilities);  
  50.   break;  
  51.  }  
  52.   
  53.   
  54. }  


 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值