热门关键字:  ubuntu  分区  linux系统进程  函数  Fedora

当前位置 :| 主页>Linux教程>编程开发>C++>

摄像头驱动实现源码分析

来源: 作者: 时间:2007-12-04 Tag: 点击:

Spac5xx的实现是按照标准的USB VIDEO设备的驱动框架编写(其具体的驱动框架可参照/usr/src/linux/drivers/usb/usbvideo.c文件),整个源程序由四个主体部分组成:设备模块的初始化模块和卸载模块,上层软件接口模块,数据传输模块。具体的模块分析如下:

一.           初始化设备模块:

该驱动采用了显式的模块初始化和消除函数,即调用module_init来初始化一个模块,并在卸载时调用moduel-exit函数(此二函数在2.3.13内核开始支持)。其具体实现如下:

1.模块初始化:

module_init (usb_spca5xx_init);

static int __init

usb_spca5xx_init (void)

{

#ifdef CONFIG_PROC_FS                 

  proc_spca50x_create ();                     //建立PROC设备文件

#endif /* CONFIG_PROC_FS */

  if (usb_register (&spca5xx_driver) < 0)         //注册USB设备驱动

    return -1;

  info ("spca5xx driver %s registered", version);

  return 0;

}

2.模块卸载:

module_exit (usb_spca5xx_exit);

tatic void __exit

usb_spca5xx_exit (void)

{

  usb_deregister (&spca5xx_driver);                //注销USB设备驱动

  info ("driver spca5xx deregistered");

#ifdef CONFIG_PROC_FS

  proc_spca50x_destroy ();                         //撤消PROC设备文件

#endif /* CONFIG_PROC_FS */

}

关键数据结构:                             //USB驱动结构,即插即用功能的实现

static struct usb_driver spca5xx_driver = {

       "spca5xx",

       spca5xx_probe,                   //注册设备自我侦测功能

       spca5xx_disconnect,               //注册设备自我断开功能

       {NULL,NULL}

};

  用两个函数调用spca5xx_probe 和spca5xx_disconnect来支持USB设备的即插即用功能:

spca5xx_probe具体实现如下:

static void *

spca5xx_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)

{

  struct usb_interface_descriptor *interface;          //USB设备接口描述符

  struct usb_spca50x *spca50x;                    //物理设备数据结构

  int err_probe;

  int i;

  if (dev->descriptor.bNumConfigurations != 1)        //探测设备是不是可配置

    goto nodevice;

  if (ifnum > 0)

    goto nodevice;

  interface = &dev->actconfig->interface[ifnum].altsetting[0];

  MOD_INC_USE_COUNT;

  interface = &intf->altsetting[0].desc;

  if (interface->bInterfaceNumber > 0)

    goto nodevice;

  if ((spca50x = kmalloc (sizeof (struct usb_spca50x), GFP_KERNEL)) == NULL)

//分配物理地址空间

    {

      err ("couldn't kmalloc spca50x struct");

      goto error;

    }

  memset (spca50x, 0, sizeof (struct usb_spca50x));

  spca50x->dev = dev;

  spca50x->iface = interface->bInterfaceNumber;

  if ((err_probe = spcaDetectCamera (spca50x)) < 0)     

//具体物理设备查找,匹配厂商号,设备号(在子程序中)

    {

      err (" Devices not found !! ");

      goto error;

    }

  PDEBUG (0, "Camera type %s ", Plist[spca50x->cameratype].name

  for (i = 0; i < SPCA50X_NUMFRAMES; i++)

    init_waitqueue_head (&spca50x->frame[i].wq);     //初始化帧等待队列

    init_waitqueue_head (&spca50x->wq);            //初始化驱动等待队列

  if (!spca50x_configure (spca50x))                

//物理设备配置(主要完成传感器侦测和图形参数配置),主要思想是给控制寄存器写值,读回其返回值,以此判断具体的传感器型号

    {

      spca50x->user = 0;

      init_MUTEX (&spca50x->lock);                  //信号量初始化

      init_MUTEX (&spca50x->buf_lock);

      spca50x->v4l_lock = SPIN_LOCK_UNLOCKED;

      spca50x->buf_state = BUF_NOT_ALLOCATED;

    }                                

  else

    {

      err ("Failed to configure camera");

      goto error;

    }

  /* Init video stuff */

  spca50x->vdev = video_device_alloc ();           //设备控制块内存分配

  if (!spca50x->vdev)

    goto error;

  memcpy (spca50x->vdev, &spca50x_template, sizeof (spca50x_template));

//系统调用的挂接,在此将驱动实现的系统调用,挂到内核中

  video_set_drvdata (spca50x->vdev, spca50x);

  if (video_register_device (spca50x->vdev, VFL_TYPE_GRABBER, video_nr) < 0)

    {                                            //video设备注册

      err ("video_register_device failed");

      goto error;

    }

  spca50x->present = 1;

  if (spca50x->force_rgb)

    info ("data format set to RGB");

  spca50x->task.sync = 0;

  spca50x->task.routine = auto_bh;

  spca50x->task.data = spca50x;

  spca50x->bh_requested = 0;

  MOD_DEC_USE_COUNT;                            //增加模块使用数

  return spca50x;                                       //返回数据结构

error:                                                  //错误处理

  if (spca50x->vdev)

    {

      if (spca50x->vdev->minor == -1)

       video_device_release (spca50x->vdev);

      else

       video_unregister_device (spca50x->vdev);

      spca50x->vdev = NULL;

    }

  if (spca50x)

    {

      kfree (spca50x);

      spca50x = NULL;

    }

  MOD_DEC_USE_COUNT;

  return NULL;

nodevice:

  return NULL;

}

Spca5xx_disconnect的具体实现如下:

static void

spca5xx_disconnect (struct usb_device *dev, void *ptr)

{

  struct usb_spca50x *spca50x = (struct usb_spca50x *) ptr;

  int n;

  MOD_INC_USE_COUNT;                             //增加模块使用数

  if (!spca50x)

    return;

  down (&spca50x->lock);                                //减少信号量

  spca50x->present = 0;                                   //驱动卸载置0

  for (n = 0; n < SPCA50X_NUMFRAMES; n++)       //标示所有帧ABORTING状态

    spca50x->frame[n].grabstate = FRAME_ABORTING;

    spca50x->curframe = -1;

  for (n = 0; n < SPCA50X_NUMFRAMES; n++)       //唤醒所有等待进程

    if (waitqueue_active (&spca50x->frame[n].wq))

      wake_up_interruptible (&spca50x->frame[n].wq);

  if (waitqueue_active (&spca50x->wq))

      wake_up_interruptible (&spca50x->wq);

  spca5xx_kill_isoc(spca50x);                      //子函数终止URB包的传输

  PDEBUG (3,"Disconnect Kill isoc done");

  up (&spca50x->lock);                            //增加信号量

  while(spca50x->user)                            //如果还有进程在使用,进程切换

      schedule();

    down (&spca50x->lock);

    if (spca50x->vdev)

       video_unregister_device (spca50x->vdev);          //注销video设备

      usb_driver_release_interface (&spca5xx_driver,     //端口释放

                                &spca50x->dev->actconfig->

                                interface[spca50x->iface]);

      spca50x->dev = NULL;

      up (&spca50x->lock);

#ifdef CONFIG_PROC_FS

      destroy_proc_spca50x_cam (spca50x);               //注销PROC文件

#endif /* CONFIG_PROC_FS */

      if (spca50x && !spca50x->user)                      //释放内存空间

       {

         spca5xx_dealloc (spca50x);

         kfree (spca50x);

         spca50x = NULL;

       }

  MOD_DEC_USE_COUNT;                              //减少模块记数

  PDEBUG (3, "Disconnect complete");

}

最新评论共有 4 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册
栏目列表