初识V4L2(一)

V4L2驱动框架概述

V4L2(video for linux two)是linux为视频设备提供的一套标准接口。它也属于字符设备驱动程序。

首先回顾普通字符设备驱动程序的写法:

app :       open                    read                            write

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

内核:    drv_open            drv_read                     drv_write

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

相关的硬件设备

1、如何写简单的字符设备驱动程序

(1)构造file_operations结构

    .open =drv_open

    .read =drv_read

    .write =drv_write

(2)告诉内核

(3)入口函数

(4)出口函数

2、如何写复杂的字符设备驱动程序

     以LCD驱动程序为例,进行简要说明。在LCD驱动程序里面引入了分层的概念,分为上下两层

(1)fbmem.c。注意这里面的内容内核已经帮我们做好了

  构造file_operations结构体

    .open/.read/.write

  告诉内核

  入口函数

  出口函数

(2)硬件相关的内容,这部分内容需要我们自己来做

  分配fb_info结构体

  设置fb_info结构体

  硬件相关的操作

  注册

  所谓注册,就是把fb_info结构体告诉fbmem.c。这样当应用程序调用open、read、write等函数来操作LCD时,首先会调用fbmem.c的file_operations结构体中的open、read、write等函数,进而调用fb_info结构体提供的open、read、write等函数。分层的好处在于:在写驱动程序的时候专注于硬件相关的那部分就可以了。其他通用的比如说fbmem.c中的内容,内核已经帮我们做好了。

前面已经说过,摄像头驱动程序也是一种字符设备驱动程序,它的结构框图如下:

当我们插入一个usb摄像头的时候,过程是怎样的?接下来简要分析一下:

在uvc_driver.c中

 

首先看一下入口函数:
static int __init uvc_init(void)
{
  int ret;
  ret = usb_register(&uvc_driver.driver);
}
struct uvc_driver uvc_driver = {
  .driver = {
  .name    = "uvcvideo",
  .probe    = uvc_probe,//当它发现所能支持的设备时,就会调用该函数
  .disconnect    = uvc_disconnect,
  .suspend    = uvc_suspend,
  .resume    = uvc_resume,
  .reset_resume    = uvc_reset_resume,
  /*假设我们接上了一个usb摄像头,这个摄像头在 uvc_ids里面,那么内核就会调用uvc_probe函数*/
  .id_table    = uvc_ids,
  .supports_autosuspend = 1,
  },
};
接下来再看一下uvc_probe这个函数:
/* -------------------------------------------------------------
* USB probe, disconnect, suspend and resume
*/

static int uvc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{

 /*v4l2_device_register这个函数不重要,只是做了某些初始化的工作*/

  if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
  goto error;
 /* Register video device nodes. */
  if (uvc_register_chains(dev) < 0)
  goto error;
}
接下来看一下函数uvc_register_chains做了什么事情?
static int uvc_register_chains(struct uvc_device *dev)
{
  struct uvc_video_chain *chain;
  int ret;  
list_for_each_entry(chain, &dev->chains, list)
{
ret = uvc_register_terms(dev, chain);   if (ret < 0)   return ret; } 接下来分析uvc_register_terms: /* * Register all video devices in all chains. */ static int uvc_register_terms(struct uvc_device *dev, struct uvc_video_chain *chain) {   ret = uvc_register_video(dev, stream);   if (ret < 0)   return ret; } static int uvc_register_video(struct uvc_device *uvc) {   struct usb_composite_dev *cdev = uvc->func.config->cdev;   struct video_device *video;   /* TODO reference counting. */   video = video_device_alloc();   if (video == NULL)   return -ENOMEM;   video->parent = &cdev->gadget->dev;   video->minor = -1;   video->fops = &uvc_v4l2_fops;   video->release = video_device_release;   strncpy(video->name, cdev->gadget->name, sizeof(video->name));   uvc->vdev = video;   video_set_drvdata(video, uvc);   return video_register_device(video, VFL_TYPE_GRABBER, -1); }

 

通过简单的分析函数的调用过程,与上图我们猜测的过程刚好对应起来,本篇文章先让我们感性的来认识一下,摄像头驱动程序的框架。

 

posted @ 2019-01-19 16:40  一代枭雄  阅读(940)  评论(0编辑  收藏  举报