精华内容
下载资源
问答
  • USB摄像头以其良好的性能和低廉的价格得到广泛应用。同时因其灵活、方便的特性,易于集成到嵌入式系统中。...本文首先介绍在Linux系统下USB摄像头驱动编制的一般方法,然后说明在此基础上如何提高帧速。
  • 基于Linux的USB摄像头驱动程序设计.pdf
  • 天兴阳光168摄像头驱动安装文件为USBPCCAM-168_v.exe,在安装时首先必须确实摄像头usb接口已插到电脑上,安装方法也是相当的简单容易,需要的用户快下载体验吧!软件介绍天兴阳光摄像头驱动168系列是一款专门为天兴...
  • 楼主耗尽千心万苦终于写出来驱动USB网络摄像头驱动程序了,特别注意:需要下载NI的VAS_September_2011,直接百度搜就可以了!
  • 嵌入式Linux下USB摄像头驱动程序开发.pdf
  • 基于Linux的USB摄像头驱动程序的实现.pdf
  • 基于嵌入式平台的USB摄像头驱动程序的实现.pdf
  • WinCE系统下USB摄像头驱动程序开发的研究
  • 万能摄像头驱动程序自动检测摄像头芯片,集成了301、303、168、268、325、211、308、380等市面基本所有方案。不用再担心不知道自己摄像头是什么芯片,不用再担心丢失了驱动程序就无法再使用了!
  • 这篇论文是用台湾凌越tp6800视频主控芯片来讲述linux下USB摄像头驱动基本架构……
  • 华硕ASUS K42JZ摄像头驱动程序,官方最新驱动,解决摄像头使用异常的问题。驱动是从官方下载来的,大家可放心下载使用。参数摄像头芯片:USB2.0 0.3M UVC WebCamWINXP驱动版本:10/06/2010,061.005.200.440WIN7驱动...
  • ancusb2.0全系列摄像头驱动目前支持winxp/2000/98se/me系统,不支持win7系统。只要你的摄像头是ANCUSB2.0系列,就可以安装本驱动。有需要的朋友,快下载吧!anc摄像头介绍ANC摄像头是奥尼国际旗下摄像头头品牌之一。...
  • 688USB摄像头驱动程序

    2009-05-20 15:29:46
    688USB摄像头驱动程序688USB摄像头驱动程序
  • 帖子大意:讨论的前提是你的USB摄像头是UVC兼容的(如今大部分摄像头兼容)默认Android不提供访问外部摄像头的API,所以你要考虑写一个内核到Android应用层通信的中间件。当你给设备接入了USB摄像头,首先要检查一下几...

    多亏了stackoverflow看到的一篇帖子,其中有几句关键的话,然后顺藤摸瓜解决了问题。

    帖子大意:

    讨论的前提是你的USB摄像头是UVC兼容的(如今大部分摄像头兼容)

    默认Android不提供访问外部摄像头的API,所以你要考虑写一个内核到Android应用层通信的中间件。

    当你给设备接入了USB摄像头,首先要检查一下几点:

    1)你的设备是否支持USB-OTG?

    2)是否在/dev目录创建了设备?如果创建了就那么一切就很简单了。shell 执行 ls -l /dev/v*,你将会看到video0或者video1。

    3)如果/dev没有创建设备,你需要写一个固件(UVC)跟硬件通信!

    (帖子地址:http://stackoverflow.com/questio ... android-application)

    读到这里,再次给我的MK802接上USB摄像头,然后打开adb shell,执行ls -l /dev/v*,看到了 /dev/video0设备!

    拔掉摄像头,再执行,video0消失,再连接,video0出现,这说明mk802支持我的摄像头!

    到此,已经明确,下一步我需要写一个android应用层到内核通信的中间件,我对这个也不了解,于是在google狂搜“android usb camera”

    终于功夫不负有心,找到了一个android usb摄像头的应用例子

    http://brain.cc.kogakuin.ac.jp/research/usb-e.html

    从中找了一个SimpleWebCamra.apk,下载了赶紧装上,发现不能运行,logcat报一个错,提示没有权限访问video0设备。

    这是为什么?我的系统已经root了呀!难道我的apk也要获得root权限?又在网上查资料,试了半天,还是不行。

    后来忽然灵机一动,android也是linux呀,我能不能把video0设备设置成没权限?问了问朋友,执行了一个命令:

    chmod 777 /dev/video0

    再次运行apk终于跑起来了!(后来经测试,设置成 chmod 0666 /dev/vidoe0 也可以,但是我也不懂0666的含义。。)

    但是问题又来了,程序进去以后,报错

    VIDIOC_DQBUF error 22, Invalid argument

    于是想,必须要活的SimpleWebCamea的源码了!经过苦苦搜索,很幸运的找到一个simplewebcam的源码:

    https://bitbucket.org/neuralassembly/simplewebcam/src 下载一看,里边包含ndk的c源码和android源码,于是按照ndk教程,安装了cygwin 苦于c代码看不太懂,错误提示VIDIOC_DQBUF 调用参数错误,却无从下手。 于是看了n篇教程,偶然发现说打开摄像头设备的open方法的一些参数,然后试着把c代码中的一些参数去掉: fd = open (dev_name, O_RDWR | O_NONBLOCK, 0); 改为 fd = open (dev_name, O_RDWR); 再次build,运行,天啊终于出来了,高兴死了!

    展开全文
  • USB摄像头驱动实现源码分析

    千次阅读 2018-03-24 18:31:03
    转自:http://blog.csdn.net/zqixiao_09/article/details/50984412 Spac5xx的实现是按照标准的USB VIDEO设备的驱动框架编写(其具体的驱动框架可参照/usr/src/linux/drivers/usb/usbvideo.c文件),整个源程序由四...

    转自:http://blog.csdn.net/zqixiao_09/article/details/50984412

     Spac5xx的实现是按照标准的USB VIDEO设备的驱动框架编写(其具体的驱动框架可参照/usr/src/linux/drivers/usb/usbvideo.c文件),整个源程序由四个主体部分组成:

    设备模块的初始化模块和卸载模块,上层软件接口模块,数据传输模块


    具体的模块分析如下:

     一、初始化设备模块

            该驱动采用了显式的模块初始化和消除函数,即调用module_init来初始化一个模块,并在卸载时调用moduel-exit函数

            其具体实现如下: 

    1、模块初始化:

    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. module_init (usb_spca5xx_init);   
    2.   
    3. static int __init  usb_spca5xx_init (void)   
    4. {    
    5. #ifdef CONFIG_PROC_FS                       
    6.     proc_spca50x_create ();//建立PROC设备文件   
    7. #endif /* CONFIG_PROC_FS */      
    8.     if (usb_register (&spca5xx_driver) < 0) //注册USB设备驱动      
    9.         return -1;      
    10.     info ("spca5xx driver %s registered", version);     
    11.     return 0;   
    12. }  
    [cpp]  view plain  copy
    1. module_init (usb_spca5xx_init);   
    2.   
    3. static int __init  usb_spca5xx_init (void)   
    4. {    
    5. #ifdef CONFIG_PROC_FS                       
    6.     proc_spca50x_create ();//建立PROC设备文件   
    7. #endif /* CONFIG_PROC_FS */      
    8.     if (usb_register (&spca5xx_driver) < 0) //注册USB设备驱动      
    9.         return -1;      
    10.     info ("spca5xx driver %s registered", version);     
    11.     return 0;   
    12. }  

    2、模块卸载:

    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. module_exit (usb_spca5xx_exit);   
    2.   
    3. static void __exit  usb_spca5xx_exit (void)   
    4. {      
    5.     usb_deregister (&spca5xx_driver); //注销USB设备驱动     
    6.     info ("driver spca5xx deregistered");   
    7. #ifdef CONFIG_PROC_FS      
    8.     proc_spca50x_destroy ();//撤消PROC设备文件   
    9. #endif /* CONFIG_PROC_FS */   
    10. }   
    [cpp]  view plain  copy
    1. module_exit (usb_spca5xx_exit);   
    2.   
    3. static void __exit  usb_spca5xx_exit (void)   
    4. {      
    5.     usb_deregister (&spca5xx_driver); //注销USB设备驱动     
    6.     info ("driver spca5xx deregistered");   
    7. #ifdef CONFIG_PROC_FS      
    8.     proc_spca50x_destroy ();//撤消PROC设备文件   
    9. #endif /* CONFIG_PROC_FS */   
    10. }   


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

    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. static struct usb_driver spca5xx_driver = {          
    2.     "spca5xx",           
    3.     spca5xx_probe, //注册设备自我侦测功能          
    4.     spca5xx_disconnect,//注册设备自我断开功能          
    5.     {NULL,NULL}   
    6. };  
    [cpp]  view plain  copy
    1. static struct usb_driver spca5xx_driver = {          
    2.     "spca5xx",           
    3.     spca5xx_probe, //注册设备自我侦测功能          
    4.     spca5xx_disconnect,//注册设备自我断开功能          
    5.     {NULL,NULL}   
    6. };  

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

    a -- spca5xx_probe 具体实现如下:
    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. static void * spca5xx_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)   
    2. {      
    3.     struct usb_interface_descriptor *interface;          //USB设备接口描述符   
    4.     struct usb_spca50x *spca50x;                    //物理设备数据结构     
    5.     int err_probe;     
    6.     int i;      
    7.     if (dev->descriptor.bNumConfigurations != 1)        //探测设备是不是可配置       
    8.         goto nodevice;     
    9.     if (ifnum > 0)       
    10.         goto nodevice;      
    11.     interface = &dev->actconfig->interface[ifnum].altsetting[0];    
    12.     MOD_INC_USE_COUNT;      
    13.     interface = &intf->altsetting[0].desc;     
    14.     if (interface->bInterfaceNumber > 0)       
    15.         goto nodevice;      
    16.     if ((spca50x = kmalloc (sizeof (struct usb_spca50x), GFP_KERNEL)) == NULL) //分配物理地址空间       
    17.     {          
    18.         err ("couldn't kmalloc spca50x struct");         
    19.         goto error;       
    20.     }      
    21.   
    22.     memset (spca50x, 0, sizeof (struct usb_spca50x));     
    23.     spca50x->dev = dev;      
    24.     spca50x->iface = interface->bInterfaceNumber;      
    25.     if ((err_probe = spcaDetectCamera (spca50x)) < 0)       //具体物理设备查找,匹配厂商号,设备号(在子程序中)         
    26.     {          
    27.         err (" Devices not found !! ");         
    28.         goto error;       
    29.     }      
    30.     PDEBUG (0, "Camera type %s ", Plist[spca50x->cameratype].name)  
    31.     for (i = 0; i < SPCA50X_NUMFRAMES; i++)        
    32.         init_waitqueue_head (&spca50x->frame[i].wq);     //初始化帧等待队列       
    33.         init_waitqueue_head (&spca50x->wq);            //初始化驱动等待队列     
    34.   
    35.     if (!spca50x_configure (spca50x))                  //物理设备配置(主要完成传感器侦测和图形参数配置),主要思想是给控制寄存器写值,读回其返回值,以此判断具体的传感器型号       
    36.     {          
    37.         spca50x->user = 0;          
    38.         init_MUTEX (&spca50x->lock);                  //信号量初始化         
    39.         init_MUTEX (&spca50x->buf_lock);          
    40.         spca50x->v4l_lock = SPIN_LOCK_UNLOCKED;         
    41.         spca50x->buf_state = BUF_NOT_ALLOCATED;       
    42.     }                                      
    43.     else       
    44.     {  
    45.         err ("Failed to configure camera");         
    46.             goto error;       
    47.     }   
    48.     
    49.   
    50.     /* Init video stuff */   
    51.     
    52.     spca50x->vdev = video_device_alloc ();           //设备控制块内存分配     
    53.     if (!spca50x->vdev)       
    54.         goto error;  
    55.     memcpy (spca50x->vdev, &spca50x_template, sizeof (spca50x_template));    
    56.     //系统调用的挂接,在此将驱动实现的系统调用,挂到内核中     
    57.     video_set_drvdata (spca50x->vdev, spca50x);   
    58.     
    59.         if (video_register_device (spca50x->vdev, VFL_TYPE_GRABBER, video_nr) < 0)       
    60.     {                                              
    61.     //video设备注册         
    62.         err ("video_register_device failed");         
    63.         goto error;       
    64.     }   
    65.     
    66.     spca50x->present = 1;     
    67.     if (spca50x->force_rgb)   
    68.       
    69.         info ("data format set to RGB");     
    70.     spca50x->task.sync = 0;   
    71.     
    72.     spca50x->task.routine = auto_bh;     
    73.     spca50x->task.data = spca50x;     
    74.     spca50x->bh_requested = 0;   
    75.               
    76.     MOD_DEC_USE_COUNT; //增加模块使用数     
    77.     return spca50x; //返回数剧结构   
    78. error://错误处理     
    79.     if (spca50x->vdev)       
    80.     {   
    81.         
    82.         if (spca50x->vdev->minor == -1)   
    83.          
    84.             video_device_release (spca50x->vdev);         
    85.         else   
    86.          
    87.             video_unregister_device (spca50x->vdev);         
    88.         spca50x->vdev = NULL;       
    89.     }   
    90.     
    91.     if (spca50x)       
    92.     {   
    93.         
    94.         kfree (spca50x);         
    95.         spca50x = NULL;       
    96.     }   
    97.     
    98.     MOD_DEC_USE_COUNT;     
    99.     return NULL;   
    100. nodevice:   
    101.     
    102.     return NULL;   
    103. }  
    [cpp]  view plain  copy
    1. static void * spca5xx_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)   
    2. {      
    3.     struct usb_interface_descriptor *interface;          //USB设备接口描述符   
    4.     struct usb_spca50x *spca50x;                    //物理设备数据结构     
    5.     int err_probe;     
    6.     int i;      
    7.     if (dev->descriptor.bNumConfigurations != 1)        //探测设备是不是可配置       
    8.         goto nodevice;     
    9.     if (ifnum > 0)       
    10.         goto nodevice;      
    11.     interface = &dev->actconfig->interface[ifnum].altsetting[0];    
    12.     MOD_INC_USE_COUNT;      
    13.     interface = &intf->altsetting[0].desc;     
    14.     if (interface->bInterfaceNumber > 0)       
    15.         goto nodevice;      
    16.     if ((spca50x = kmalloc (sizeof (struct usb_spca50x), GFP_KERNEL)) == NULL) //分配物理地址空间       
    17.     {          
    18.         err ("couldn't kmalloc spca50x struct");         
    19.         goto error;       
    20.     }      
    21.   
    22.     memset (spca50x, 0, sizeof (struct usb_spca50x));     
    23.     spca50x->dev = dev;      
    24.     spca50x->iface = interface->bInterfaceNumber;      
    25.     if ((err_probe = spcaDetectCamera (spca50x)) < 0)       //具体物理设备查找,匹配厂商号,设备号(在子程序中)         
    26.     {          
    27.         err (" Devices not found !! ");         
    28.         goto error;       
    29.     }      
    30.     PDEBUG (0, "Camera type %s ", Plist[spca50x->cameratype].name)  
    31.     for (i = 0; i < SPCA50X_NUMFRAMES; i++)        
    32.         init_waitqueue_head (&spca50x->frame[i].wq);     //初始化帧等待队列       
    33.         init_waitqueue_head (&spca50x->wq);            //初始化驱动等待队列     
    34.   
    35.     if (!spca50x_configure (spca50x))                  //物理设备配置(主要完成传感器侦测和图形参数配置),主要思想是给控制寄存器写值,读回其返回值,以此判断具体的传感器型号       
    36.     {          
    37.         spca50x->user = 0;          
    38.         init_MUTEX (&spca50x->lock);                  //信号量初始化         
    39.         init_MUTEX (&spca50x->buf_lock);          
    40.         spca50x->v4l_lock = SPIN_LOCK_UNLOCKED;         
    41.         spca50x->buf_state = BUF_NOT_ALLOCATED;       
    42.     }                                      
    43.     else       
    44.     {  
    45.         err ("Failed to configure camera");         
    46.             goto error;       
    47.     }   
    48.     
    49.   
    50.     /* Init video stuff */   
    51.     
    52.     spca50x->vdev = video_device_alloc ();           //设备控制块内存分配     
    53.     if (!spca50x->vdev)       
    54.         goto error;  
    55.     memcpy (spca50x->vdev, &spca50x_template, sizeof (spca50x_template));    
    56.     //系统调用的挂接,在此将驱动实现的系统调用,挂到内核中     
    57.     video_set_drvdata (spca50x->vdev, spca50x);   
    58.     
    59.         if (video_register_device (spca50x->vdev, VFL_TYPE_GRABBER, video_nr) < 0)       
    60.     {                                              
    61.     //video设备注册         
    62.         err ("video_register_device failed");         
    63.         goto error;       
    64.     }   
    65.     
    66.     spca50x->present = 1;     
    67.     if (spca50x->force_rgb)   
    68.       
    69.         info ("data format set to RGB");     
    70.     spca50x->task.sync = 0;   
    71.     
    72.     spca50x->task.routine = auto_bh;     
    73.     spca50x->task.data = spca50x;     
    74.     spca50x->bh_requested = 0;   
    75.               
    76.     MOD_DEC_USE_COUNT; //增加模块使用数     
    77.     return spca50x; //返回数剧结构   
    78. error://错误处理     
    79.     if (spca50x->vdev)       
    80.     {   
    81.         
    82.         if (spca50x->vdev->minor == -1)   
    83.          
    84.             video_device_release (spca50x->vdev);         
    85.         else   
    86.          
    87.             video_unregister_device (spca50x->vdev);         
    88.         spca50x->vdev = NULL;       
    89.     }   
    90.     
    91.     if (spca50x)       
    92.     {   
    93.         
    94.         kfree (spca50x);         
    95.         spca50x = NULL;       
    96.     }   
    97.     
    98.     MOD_DEC_USE_COUNT;     
    99.     return NULL;   
    100. nodevice:   
    101.     
    102.     return NULL;   
    103. }  


    b -- Spca5xx_disconnect  的具体实现如下:
    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. static void  spca5xx_disconnect (struct usb_device *dev, void *ptr)   
    2. {      
    3.     struct usb_spca50x *spca50x = (struct usb_spca50x *) ptr;     
    4.     int n;      
    5.     MOD_INC_USE_COUNT; //增加模块使用数     
    6.     if (!spca50x)       
    7.         return;      
    8.     down (&spca50x->lock); //减少信号量     
    9.     spca50x->present = 0;  //驱动卸载置0      
    10.     for (n = 0; n < SPCA50X_NUMFRAMES; n++)       //标示所有帧ABORTING状态       
    11.     {  
    12.         spca50x->frame[n].grabstate = FRAME_ABORTING;       
    13.         spca50x->curframe = -1;     
    14.       
    15.     }  
    16.      for (n = 0; n < SPCA50X_NUMFRAMES; n++)       //唤醒所有等待进程       
    17.     {  
    18.         if (waitqueue_active (&spca50x->frame[n].wq))         
    19.             wake_up_interruptible (&spca50x->frame[n].wq);     
    20.           
    21.         if (waitqueue_active (&spca50x->wq))          
    22.             wake_up_interruptible (&spca50x->wq);      
    23.     }  
    24.     spca5xx_kill_isoc(spca50x);  //子函数终止URB包的传输     
    25.     PDEBUG (3,"Disconnect Kill isoc done");      
    26.     up (&spca50x->lock);  //增加信号量      
    27.     while(spca50x->user) /如果还有进程在使用,进程切换         
    28.         schedule();        
    29.     down (&spca50x->lock);       
    30.     if (spca50x->vdev)    
    31.     {         
    32.         video_unregister_device (spca50x->vdev);   //注销video设备       
    33.         usb_driver_release_interface (&spca5xx_driver,&spca50x->dev->actconfig->interface[spca50x->iface]); //端口释放         
    34.         spca50x->dev = NULL;         
    35.     }  
    36.     up (&spca50x->lock);   
    37. #ifdef CONFIG_PROC_FS          
    38.     destroy_proc_spca50x_cam (spca50x); //注销PROC文件   
    39. #endif /* CONFIG_PROC_FS */   
    40.          
    41.     if (spca50x && !spca50x->user)                      //释放内存空间          
    42.     {             
    43.         spca5xx_dealloc (spca50x);            
    44.         kfree (spca50x);            
    45.         spca50x = NULL;          
    46.     }      
    47.     MOD_DEC_USE_COUNT;                              //减少模块记数     
    48.     PDEBUG (3, "Disconnect complete");   
    49. }  
    [cpp]  view plain  copy
    1. static void  spca5xx_disconnect (struct usb_device *dev, void *ptr)   
    2. {      
    3.     struct usb_spca50x *spca50x = (struct usb_spca50x *) ptr;     
    4.     int n;      
    5.     MOD_INC_USE_COUNT; //增加模块使用数     
    6.     if (!spca50x)       
    7.         return;      
    8.     down (&spca50x->lock); //减少信号量     
    9.     spca50x->present = 0;  //驱动卸载置0      
    10.     for (n = 0; n < SPCA50X_NUMFRAMES; n++)       //标示所有帧ABORTING状态       
    11.     {  
    12.         spca50x->frame[n].grabstate = FRAME_ABORTING;       
    13.         spca50x->curframe = -1;     
    14.       
    15.     }  
    16.      for (n = 0; n < SPCA50X_NUMFRAMES; n++)       //唤醒所有等待进程       
    17.     {  
    18.         if (waitqueue_active (&spca50x->frame[n].wq))         
    19.             wake_up_interruptible (&spca50x->frame[n].wq);     
    20.           
    21.         if (waitqueue_active (&spca50x->wq))          
    22.             wake_up_interruptible (&spca50x->wq);      
    23.     }  
    24.     spca5xx_kill_isoc(spca50x);  //子函数终止URB包的传输     
    25.     PDEBUG (3,"Disconnect Kill isoc done");      
    26.     up (&spca50x->lock);  //增加信号量      
    27.     while(spca50x->user) /如果还有进程在使用,进程切换         
    28.         schedule();        
    29.     down (&spca50x->lock);       
    30.     if (spca50x->vdev)    
    31.     {         
    32.         video_unregister_device (spca50x->vdev);   //注销video设备       
    33.         usb_driver_release_interface (&spca5xx_driver,&spca50x->dev->actconfig->interface[spca50x->iface]); //端口释放         
    34.         spca50x->dev = NULL;         
    35.     }  
    36.     up (&spca50x->lock);   
    37. #ifdef CONFIG_PROC_FS          
    38.     destroy_proc_spca50x_cam (spca50x); //注销PROC文件   
    39. #endif /* CONFIG_PROC_FS */   
    40.          
    41.     if (spca50x && !spca50x->user)                      //释放内存空间          
    42.     {             
    43.         spca5xx_dealloc (spca50x);            
    44.         kfree (spca50x);            
    45.         spca50x = NULL;          
    46.     }      
    47.     MOD_DEC_USE_COUNT;                              //减少模块记数     
    48.     PDEBUG (3, "Disconnect complete");   
    49. }  



    二、上层软件接口模块:   

            该模块通过file_operations数据结构,依据V4L协议规范,实现设备的关键系统调用,实现设备文件化的UNIX系统设计特点。作为摄相头驱动,其功能在于数据采集,而没有向摄相头输出的功能,因此在源码中没有实现write系统调用。

    其关键的数据结构如下:

    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. static struct video_device spca50x_template = {     
    2.     .owner = THIS_MODULE,    
    3.     .name = "SPCA5XX USB Camera",     
    4.     .type = VID_TYPE_CAPTURE,    
    5.     .hardware = VID_HARDWARE_SPCA5XX,     
    6.     .fops = &spca5xx_fops,           
    7. };   
    8.   
    9.   
    10. static struct file_operations spca5xx_fops = {     
    11.     .owner = THIS_MODULE,    
    12.     .open = spca5xx_open, //open功能     
    13.     .release = spca5xx_close,//close功能     
    14.     .read = spca5xx_read, //read功能     
    15.     .mmap = spca5xx_mmap, //内存映射功能     
    16.     .ioctl = spca5xx_ioctl, //文件信息获取    
    17.     .llseek = no_llseek,//文件定位功能未实现   
    18. };   
    [cpp]  view plain  copy
    1. static struct video_device spca50x_template = {     
    2.     .owner = THIS_MODULE,    
    3.     .name = "SPCA5XX USB Camera",     
    4.     .type = VID_TYPE_CAPTURE,    
    5.     .hardware = VID_HARDWARE_SPCA5XX,     
    6.     .fops = &spca5xx_fops,           
    7. };   
    8.   
    9.   
    10. static struct file_operations spca5xx_fops = {     
    11.     .owner = THIS_MODULE,    
    12.     .open = spca5xx_open, //open功能     
    13.     .release = spca5xx_close,//close功能     
    14.     .read = spca5xx_read, //read功能     
    15.     .mmap = spca5xx_mmap, //内存映射功能     
    16.     .ioctl = spca5xx_ioctl, //文件信息获取    
    17.     .llseek = no_llseek,//文件定位功能未实现   
    18. };   

    1. Open功能

    完成设备的打开和初始化,并初始化解码器模块。其具体实现如下:

    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. static int  spca5xx_open(struct video_device *vdev, int flags)   
    2. {      
    3.     struct usb_spca50x *spca50x = video_get_drvdata (vdev);     
    4.     int err;      
    5.     MOD_INC_USE_COUNT;                         //增加模块记数     
    6.     down (&spca50x->lock);                                
    7.     err = -ENODEV;      
    8.   
    9.     if (!spca50x->present)                 //检查设备是不是存在,有不有驱动,是不是忙       
    10.         goto out;    
    11.     err = -EBUSY;     
    12.     if (spca50x->user)       
    13.         goto out;      
    14.     err = -ENOMEM;      
    15.     if (spca50x_alloc (spca50x))    
    16.         goto out;                      
    17.       
    18.     err = spca50x_init_source (spca50x);           //初始化传感器和解码模块,在此函数的实现中,对每一款DSP芯片的初始化都不一样,对中星微301P的DSP芯片的初始化在子函数zc3xx_init,其实现方法为寄存器填值。     
    19.     if (err != 0)  
    20.     {          
    21.         PDEBUG (0, "DEALLOC error on spca50x_init_source\n");         
    22.         up (&spca50x->lock);          
    23.         spca5xx_dealloc (spca50x);         
    24.         goto out2;       
    25.     }   
    26.   
    27.     spca5xx_initDecoder(spca50x);                  //解码模块初始化,其模块的具体实现采用的是huffman算法      spca5xx_setFrameDecoder(spca50x);     
    28.     spca50x->user++;      
    29.       
    30.     err = spca50x_init_isoc (spca50x);              //初始化URB(usb request block) 包,启动摄相头,采用同步传输的方式传送数据     
    31.     if (err)       
    32.     {          
    33.         PDEBUG (0, " DEALLOC error on init_Isoc\n");         
    34.         spca50x->user--;          
    35.         spca5xx_kill_isoc (spca50x);         
    36.         up (&spca50x->lock);          
    37.         spca5xx_dealloc (spca50x);         
    38.         goto out2;  
    39.     }      
    40.   
    41.     spca50x->brightness = spca50x_get_brghtness (spca50x) << 8;     
    42.     spca50x->whiteness = 0;   
    43.   
    44. out:      
    45.     up (&spca50x->lock);   
    46. out2:     
    47.     if (err)       
    48.         MOD_DEC_USE_COUNT;     
    49.     if (err)          
    50.     {          
    51.         PDEBUG (2, "Open failed");       
    52.     }     
    53.     else       
    54.     {          
    55.         PDEBUG (2, "Open done");      
    56.     }      
    57.     return err;   
    58. }  
    [cpp]  view plain  copy
    1. static int  spca5xx_open(struct video_device *vdev, int flags)   
    2. {      
    3.     struct usb_spca50x *spca50x = video_get_drvdata (vdev);     
    4.     int err;      
    5.     MOD_INC_USE_COUNT;                         //增加模块记数     
    6.     down (&spca50x->lock);                                
    7.     err = -ENODEV;      
    8.   
    9.     if (!spca50x->present)                 //检查设备是不是存在,有不有驱动,是不是忙       
    10.         goto out;    
    11.     err = -EBUSY;     
    12.     if (spca50x->user)       
    13.         goto out;      
    14.     err = -ENOMEM;      
    15.     if (spca50x_alloc (spca50x))    
    16.         goto out;                      
    17.       
    18.     err = spca50x_init_source (spca50x);           //初始化传感器和解码模块,在此函数的实现中,对每一款DSP芯片的初始化都不一样,对中星微301P的DSP芯片的初始化在子函数zc3xx_init,其实现方法为寄存器填值。     
    19.     if (err != 0)  
    20.     {          
    21.         PDEBUG (0, "DEALLOC error on spca50x_init_source\n");         
    22.         up (&spca50x->lock);          
    23.         spca5xx_dealloc (spca50x);         
    24.         goto out2;       
    25.     }   
    26.   
    27.     spca5xx_initDecoder(spca50x);                  //解码模块初始化,其模块的具体实现采用的是huffman算法      spca5xx_setFrameDecoder(spca50x);     
    28.     spca50x->user++;      
    29.       
    30.     err = spca50x_init_isoc (spca50x);              //初始化URB(usb request block) 包,启动摄相头,采用同步传输的方式传送数据     
    31.     if (err)       
    32.     {          
    33.         PDEBUG (0, " DEALLOC error on init_Isoc\n");         
    34.         spca50x->user--;          
    35.         spca5xx_kill_isoc (spca50x);         
    36.         up (&spca50x->lock);          
    37.         spca5xx_dealloc (spca50x);         
    38.         goto out2;  
    39.     }      
    40.   
    41.     spca50x->brightness = spca50x_get_brghtness (spca50x) << 8;     
    42.     spca50x->whiteness = 0;   
    43.   
    44. out:      
    45.     up (&spca50x->lock);   
    46. out2:     
    47.     if (err)       
    48.         MOD_DEC_USE_COUNT;     
    49.     if (err)          
    50.     {          
    51.         PDEBUG (2, "Open failed");       
    52.     }     
    53.     else       
    54.     {          
    55.         PDEBUG (2, "Open done");      
    56.     }      
    57.     return err;   
    58. }  

    2.Close功能

    完成设备的关闭,其具体过程是:

    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. static void spca5xx_close(struct video_device *vdev)   
    2. {     
    3.     struct usb_spca50x *spca50x =vdev->priv;     
    4.     int i;     
    5.     PDEBUG (2, "spca50x_close");     
    6.     down (&spca50x->lock);  //参数设置     
    7.     spca50x->user--;     
    8.     spca50x->curframe = -1;   
    9.     
    10.     if(spca50x->present)//present:是或有驱动加载       
    11.     {        
    12.         spca50x_stop_isoc (spca50x);//停止摄相头工作和数据包送         
    13.         spcaCameraShutDown (spca50x);//关闭摄相头,由子函数spca50x_stop_iso完成     
    14.         for (i = 0; i < SPCA50X_NUMFRAMES; i++)    //唤醒所有等待进程       
    15.         {        
    16.             if(waitqueue_active(&spca50x->frame[i].wq))   
    17.                 wake_up_interruptible (&spca50x->frame[i].wq);       
    18.         }   
    19.         if(waitqueue_active (&spca50x->wq))          
    20.             wake_up_interruptible (&spca50x->wq);     
    21.     }    
    22.       
    23.     up(&spca50x->lock);   
    24.     spca5xx_dealloc (spca50x);//回收内存空间     
    25.       
    26.     PDEBUG(2,"Release ressources done");     
    27.     MOD_DEC_USE_COUNT;   
    28. }   
    [cpp]  view plain  copy
    1. static void spca5xx_close(struct video_device *vdev)   
    2. {     
    3.     struct usb_spca50x *spca50x =vdev->priv;     
    4.     int i;     
    5.     PDEBUG (2, "spca50x_close");     
    6.     down (&spca50x->lock);  //参数设置     
    7.     spca50x->user--;     
    8.     spca50x->curframe = -1;   
    9.     
    10.     if(spca50x->present)//present:是或有驱动加载       
    11.     {        
    12.         spca50x_stop_isoc (spca50x);//停止摄相头工作和数据包送         
    13.         spcaCameraShutDown (spca50x);//关闭摄相头,由子函数spca50x_stop_iso完成     
    14.         for (i = 0; i < SPCA50X_NUMFRAMES; i++)    //唤醒所有等待进程       
    15.         {        
    16.             if(waitqueue_active(&spca50x->frame[i].wq))   
    17.                 wake_up_interruptible (&spca50x->frame[i].wq);       
    18.         }   
    19.         if(waitqueue_active (&spca50x->wq))          
    20.             wake_up_interruptible (&spca50x->wq);     
    21.     }    
    22.       
    23.     up(&spca50x->lock);   
    24.     spca5xx_dealloc (spca50x);//回收内存空间     
    25.       
    26.     PDEBUG(2,"Release ressources done");     
    27.     MOD_DEC_USE_COUNT;   
    28. }   

    3、 Read功能

     完成数据的读取,其主要的工作就是将数据由内核空间传送到进程用户空间

    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. static long spca5xx_rea(struct video_device *dev, char * buf, unsigned long count,int noblock)   
    2. {     
    3.     struct usb_spca50x *spca50x = video_get_drvdata (dev);     
    4.     int i;     
    5.     int frmx = -1;     
    6.     int rc;     
    7.     volatile struct spca50x_frame *frame;   
    8.       
    9.         if(down_interruptible(&spca50x->lock))  //获取信号量         
    10.         return -EINTR;   
    11.       
    12.         if(!dev || !buf){//判断设备情况       
    13.         up(&spca50x->lock);       
    14.         return -EFAULT;   
    15.     }    
    16.     
    17.     if(!spca50x->dev){       
    18.         up(&spca50x->lock);       
    19.         return -EIO;   
    20.     }   
    21.       
    22.     if (!spca50x->streaming){       
    23.         up(&spca50x->lock);       
    24.         return -EIO;   
    25.     }   
    26.       
    27.         if((rc = wait_event_interruptible(spca50x->wq,     //在指定的队列上睡眠,直到参数2的条件为真   
    28.               spca50x->frame[0].grabstate == FRAME_DONE ||   
    29.               spca50x->frame[1].grabstate == FRAME_DONE ||                 
    30.           spca50x->frame[2].grabstate == FRAME_DONE ||                 
    31.               spca50x->frame[3].grabstate == FRAME_DONE )))    
    32.         {                 
    33.         up(&spca50x->lock);                 
    34.         return rc;          
    35.     }    
    36.     
    37.   
    38.     for (i = 0; i < SPCA50X_NUMFRAMES; i++)         //当数据到来       
    39.         if (spca50x->frame[i].grabstate == FRAME_DONE)   //标识数已到         
    40.             frmx = i;     
    41.     if (frmx < 0)       
    42.     {   
    43.         
    44.         PDEBUG(2, "Couldnt find a frame ready to be read.");         
    45.         up(&spca50x->lock);         
    46.         return -EFAULT;       
    47.     }   
    48.     
    49.     frame = &spca50x->frame[frmx];   
    50.     PDEBUG (2, "count asked: %d available: %d", (int) count,(int) frame->scanlength);     
    51.     if (count > frame->scanlength)       
    52.         count = frame->scanlength;   
    53.     
    54.     if ((i = copy_to_user (buf, frame->data, count)))   //实现用户空间和内核空间的数据贝       
    55.     {   
    56.         
    57.         PDEBUG (2, "Copy failed! %d bytes not copied", i);             
    58.         up(&spca50x->lock);         
    59.         return -EFAULT;       
    60.     }   
    61.     
    62.     /* Release the frame */    
    63.     frame->grabstate = FRAME_READY; //标识数据已空   
    64.     up(&spca50x->lock);                             
    65.     return count;//返回拷贝的数据数   
    66. }  
    [cpp]  view plain  copy
    1. static long spca5xx_rea(struct video_device *dev, char * buf, unsigned long count,int noblock)   
    2. {     
    3.     struct usb_spca50x *spca50x = video_get_drvdata (dev);     
    4.     int i;     
    5.     int frmx = -1;     
    6.     int rc;     
    7.     volatile struct spca50x_frame *frame;   
    8.       
    9.         if(down_interruptible(&spca50x->lock))  //获取信号量         
    10.         return -EINTR;   
    11.       
    12.         if(!dev || !buf){//判断设备情况       
    13.         up(&spca50x->lock);       
    14.         return -EFAULT;   
    15.     }    
    16.     
    17.     if(!spca50x->dev){       
    18.         up(&spca50x->lock);       
    19.         return -EIO;   
    20.     }   
    21.       
    22.     if (!spca50x->streaming){       
    23.         up(&spca50x->lock);       
    24.         return -EIO;   
    25.     }   
    26.       
    27.         if((rc = wait_event_interruptible(spca50x->wq,     //在指定的队列上睡眠,直到参数2的条件为真   
    28.               spca50x->frame[0].grabstate == FRAME_DONE ||   
    29.               spca50x->frame[1].grabstate == FRAME_DONE ||                 
    30.           spca50x->frame[2].grabstate == FRAME_DONE ||                 
    31.               spca50x->frame[3].grabstate == FRAME_DONE )))    
    32.         {                 
    33.         up(&spca50x->lock);                 
    34.         return rc;          
    35.     }    
    36.     
    37.   
    38.     for (i = 0; i < SPCA50X_NUMFRAMES; i++)         //当数据到来       
    39.         if (spca50x->frame[i].grabstate == FRAME_DONE)   //标识数已到         
    40.             frmx = i;     
    41.     if (frmx < 0)       
    42.     {   
    43.         
    44.         PDEBUG(2, "Couldnt find a frame ready to be read.");         
    45.         up(&spca50x->lock);         
    46.         return -EFAULT;       
    47.     }   
    48.     
    49.     frame = &spca50x->frame[frmx];   
    50.     PDEBUG (2, "count asked: %d available: %d", (int) count,(int) frame->scanlength);     
    51.     if (count > frame->scanlength)       
    52.         count = frame->scanlength;   
    53.     
    54.     if ((i = copy_to_user (buf, frame->data, count)))   //实现用户空间和内核空间的数据贝       
    55.     {   
    56.         
    57.         PDEBUG (2, "Copy failed! %d bytes not copied", i);             
    58.         up(&spca50x->lock);         
    59.         return -EFAULT;       
    60.     }   
    61.     
    62.     /* Release the frame */    
    63.     frame->grabstate = FRAME_READY; //标识数据已空   
    64.     up(&spca50x->lock);                             
    65.     return count;//返回拷贝的数据数   
    66. }  

    4、Mmap功能

    实现将设备内存映射到用户进程的地址空间的功能,其关键函数是remap_page_range,其具体实现如下:

    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. static int spca5xx_mmap(struct video_device *dev,const char *adr, unsigned long size)   
    2. {   
    3.     
    4.     unsigned long start = (unsigned long) adr;     
    5.     struct usb_spca50x *spca50x = dev->priv;     
    6.     unsigned long page, pos;     
    7.     if (spca50x->dev == NULL)       
    8.         return -EIO;   
    9.       
    10.     PDEBUG (4, "mmap: %ld (%lX) bytes", size, size);     
    11.     if(size > (((SPCA50X_NUMFRAMES * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE -1)))       
    12.         return -EINVAL;   
    13.          
    14.     if (down_interruptible(&spca50x->lock))  //获取信号量                 
    15.         return -EINTR;   
    16.     
    17.     pos = (unsigned long) spca50x->fbuf;  
    18.     while (size > 0)  //循环实现内存映射       
    19.     {                   
    20.         page = kvirt_to_pa (pos);   
    21.         if (remap_page_range (start, page, PAGE_SIZE, PAGE_SHARED)){  //实现内存映射   
    22.             up(&spca50x->lock);   
    23.             return -EAGAIN;      
    24.         }         
    25.       
    26.         start += PAGE_SIZE;         
    27.         pos += PAGE_SIZE;         
    28.         if (size > PAGE_SIZE)          
    29.             size -= PAGE_SIZE;         
    30.         else       
    31.             size = 0;       
    32.     }   
    33.   
    34.     up(&spca50x->lock); //释放信号量     
    35.     return 0;   
    36. }  
    [cpp]  view plain  copy
    1. static int spca5xx_mmap(struct video_device *dev,const char *adr, unsigned long size)   
    2. {   
    3.     
    4.     unsigned long start = (unsigned long) adr;     
    5.     struct usb_spca50x *spca50x = dev->priv;     
    6.     unsigned long page, pos;     
    7.     if (spca50x->dev == NULL)       
    8.         return -EIO;   
    9.       
    10.     PDEBUG (4, "mmap: %ld (%lX) bytes", size, size);     
    11.     if(size > (((SPCA50X_NUMFRAMES * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE -1)))       
    12.         return -EINVAL;   
    13.          
    14.     if (down_interruptible(&spca50x->lock))  //获取信号量                 
    15.         return -EINTR;   
    16.     
    17.     pos = (unsigned long) spca50x->fbuf;  
    18.     while (size > 0)  //循环实现内存映射       
    19.     {                   
    20.         page = kvirt_to_pa (pos);   
    21.         if (remap_page_range (start, page, PAGE_SIZE, PAGE_SHARED)){  //实现内存映射   
    22.             up(&spca50x->lock);   
    23.             return -EAGAIN;      
    24.         }         
    25.       
    26.         start += PAGE_SIZE;         
    27.         pos += PAGE_SIZE;         
    28.         if (size > PAGE_SIZE)          
    29.             size -= PAGE_SIZE;         
    30.         else       
    31.             size = 0;       
    32.     }   
    33.   
    34.     up(&spca50x->lock); //释放信号量     
    35.     return 0;   
    36. }  

    5、Ioctl功能:  

    实现文件信息的获取功能

    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. static int spca5xx_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)   
    2. {         
    3.     struct video_device *vdev = file->private_data;          
    4.     struct usb_spca50x *spca50x = vdev->priv;          
    5.     int rc;   
    6.          
    7.     if(down_interruptible(&spca50x->lock))       //获取信号量                 
    8.         return -EINTR;   
    9.         
    10.     rc = video_usercopy (inode, file, cmd, arg, spca5xx_do_ioctl);  //将信息传送到用户进程,其关键函数实现spca5xx_do_ioctl   
    11.     up(&spca50x->lock);     
    12.     return rc;  
    13. }   
    [cpp]  view plain  copy
    1. static int spca5xx_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)   
    2. {         
    3.     struct video_device *vdev = file->private_data;          
    4.     struct usb_spca50x *spca50x = vdev->priv;          
    5.     int rc;   
    6.          
    7.     if(down_interruptible(&spca50x->lock))       //获取信号量                 
    8.         return -EINTR;   
    9.         
    10.     rc = video_usercopy (inode, file, cmd, arg, spca5xx_do_ioctl);  //将信息传送到用户进程,其关键函数实现spca5xx_do_ioctl   
    11.     up(&spca50x->lock);     
    12.     return rc;  
    13. }   

    spca5xx_do_ioctl函数的实现依赖于不同的硬件,本驱动为了支持多种芯片,实现程序过于烦琐,其主要思想是通过copy_to_user(arg,b,sizeof(struct video_capability)函数将设备信息传递给用户进程。


    三、数据传输模块

          源程序采用tasklet来实现同步快速传递数据,并通过spcadecode.c上的软件解码模块实现图形信息的解码。此模块的入口点挂节在spca_open函数中,其具体的函数为spca50x_init_isoc。当设备被打开时,同步传输数据也已经开始,并通过spca50x_move_data函数将数据传递给驱动程序,驱动程序通过轮询的办法实现对数据的访问。

    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. Void outpict_do_tasklet (unsigned long ptr)   
    2. {     
    3.     int err;     
    4.     struct spca50x_frame *taskletframe = (struct spca50x_frame *) ptr;     
    5.     taskletframe->scanlength = taskletframe->highwater - taskletframe->data;   
    6.       PDEBUG (2, "Tasklet ask spcadecoder hdrwidth %d hdrheight %d method %d",           
    7.         taskletframe->hdrwidth, taskletframe->hdrheight,            
    8.         taskletframe->method);   
    9.     
    10.     err = spca50x_outpicture (taskletframe);  //输出处理过的图片数据     
    11.     if (err != 0)       
    12.     {        
    13.         PDEBUG (0, "frame decoder failed (%d)", err);         
    14.         taskletframe->grabstate = FRAME_ERROR;      
    15.     }     
    16.     else       
    17.     {        
    18.         taskletframe->grabstate = FRAME_DONE;       
    19.     }   
    20.     
    21.     if (waitqueue_active (&taskletframe->wq))//如果有进程等待,唤醒等待进程       
    22.         wake_up_interruptible (&taskletframe->wq);   
    23. }  
    [cpp]  view plain  copy
    1. Void outpict_do_tasklet (unsigned long ptr)   
    2. {     
    3.     int err;     
    4.     struct spca50x_frame *taskletframe = (struct spca50x_frame *) ptr;     
    5.     taskletframe->scanlength = taskletframe->highwater - taskletframe->data;   
    6.       PDEBUG (2, "Tasklet ask spcadecoder hdrwidth %d hdrheight %d method %d",           
    7.         taskletframe->hdrwidth, taskletframe->hdrheight,            
    8.         taskletframe->method);   
    9.     
    10.     err = spca50x_outpicture (taskletframe);  //输出处理过的图片数据     
    11.     if (err != 0)       
    12.     {        
    13.         PDEBUG (0, "frame decoder failed (%d)", err);         
    14.         taskletframe->grabstate = FRAME_ERROR;      
    15.     }     
    16.     else       
    17.     {        
    18.         taskletframe->grabstate = FRAME_DONE;       
    19.     }   
    20.     
    21.     if (waitqueue_active (&taskletframe->wq))//如果有进程等待,唤醒等待进程       
    22.         wake_up_interruptible (&taskletframe->wq);   
    23. }  

    值得一提的是spcadecode.c上解码模块将原始压缩图形数据流yyuyv,yuvy, jpeg411,jpeg422解码为RGB图形,但此部分解压缩算法的实现也依赖于压缩的格式,归根结底依赖于DSP(数字处理芯片)中的硬件压缩算法。 


    四.USB CORE的支持

           LINUX下的USB设备对下层硬件的操作依靠系统实现的USB CORE层,USB CORE对上层驱动提供了众多函数接口如:usb_control_msg,usb_sndctrlpipe等,其中最典型的使用为源码中对USB端点寄存器的读写函数spca50x_reg_write和spca50x_reg_read等,具体实现如下:(举spca50x_reg_write的实现,其他类似)

    [cpp]  view plain  copy
    在CODE上查看代码片 派生到我的代码片
    1. static int spca50x_reg_write(struct usb_device *dev,__u16 reg,__u16 index,__u16 value)   
    2. {         
    3.     int rc;          
    4.     rc = usb_control_msg(dev,          //通过USB CORE提供的接口函数设置寄存器的值   
    5.                 usb_sndctrlpipe(dev, 0),   
    6.                         reg,   
    7.                         USB_TYPE_VENDOR | USB_RECIP_DEVICE,   
    8.                         value, index, NULL, 0, TimeOut);   
    9.          
    10.     PDEBUG(5, "reg write: 0x%02X,0x%02X:0x%02X, 0x%x", reg, index, value, rc);          
    11.     if (rc < 0)                
    12.         err("reg write: error %d", rc);          
    13.     return rc;   
    14. }   
    [cpp]  view plain  copy
    1. static int spca50x_reg_write(struct usb_device *dev,__u16 reg,__u16 index,__u16 value)   
    2. {         
    3.     int rc;          
    4.     rc = usb_control_msg(dev,          //通过USB CORE提供的接口函数设置寄存器的值   
    5.                 usb_sndctrlpipe(dev, 0),   
    6.                         reg,   
    7.                         USB_TYPE_VENDOR | USB_RECIP_DEVICE,   
    8.                         value, index, NULL, 0, TimeOut);   
    9.          
    10.     PDEBUG(5, "reg write: 0x%02X,0x%02X:0x%02X, 0x%x", reg, index, value, rc);          
    11.     if (rc < 0)                
    12.         err("reg write: error %d", rc);          
    13.     return rc;   
    展开全文
  • USB摄像头以其良好的性能和低廉的价格得到广泛应用。同时因其灵活、方便的特性,易于集成到嵌入式系统中。但是如果使用现有的符合Video for Linux标准的驱动...Linux系统中的USB摄像头驱动程序USB设备驱动程序完全符...

    USB摄像头以其良好的性能和低廉的价格得到广泛应用。同时因其灵活、方便的特性,易于集成到嵌入式系统中。但是如果使用现有的符合Video for Linux标准的驱动程序配合通用应用程序,难以充分利用USB带宽,帧速不高,不易满足实时监控等要求。本文首先介绍在Linux系统下USB摄像头驱动编制的一般方法,然后说明在此基础上如何提高帧速。

    Linux系统中的USB摄像头驱动程序

    USB设备驱动程序完全符合通用设备驱动的准则,不同的是内核提供了一些特别的API函数,方便驱动注册、销毁自己,例如usb_reSister()和usb_dereSister();2.4版的内核还提供了对于hotplug的支持。

    1.USB摄像头驱动的一般编写方法

    摄像头属于视频类设备。在目前的Linux核心中,视频部分的标准是Video for Linux(简称V4L)。这个标准其实定义了一套接口,内核、驱动、应用程序以这个接口为标准进行交流。目前的V4L涵盖了视、音频流捕捉及处理等内容,USB摄像头也属于它支持的范畴。

    因此,USB摄像头的驱动应当与内核提供的视频驱动挂钩。即首先在驱动中声明一个video_device结构,并为其指定文件操作函数指针数组.fops,向系统注册。在应用程序发出文件操作的相关命令时,核心根据这些指针调用相应函数,并将该结构作为参数传递给它们。这样,就完成了驱动和核心之间的通信。例如:

    static struct video_device vdev_template={……};

    //声明video_device,指出挂接驱动

    static struct file_operations ov511_fops={……};

    //声明本驱动的文件操作函数指针

    struct video_device*vdev=video_devdata(file);

    //从文件指针中提取出video_device结构

    在video_device结构中,有一个私有指针priv,可以将它指向一块保留内存。在这块内存中,保存着本驱动、本设备的相关初始化信息。这块内存的申请、初始化、指针指向等工作都是在USB驱动的枚举函数.probe中完成。这样,在枚举函数将控制权返还给系统后,因为内核不销毁保留内存,所以驱动仍然保留着自己的信息。这点与Windows系统中WDM驱动有异曲同工之处。当然,在驱动卸载函数中,应当将申请的各块内存全部释放。

    2 使用双URB轮流通信

    众所周知,USBl.1总线标准定义了控制、中断、批量、等时等四种管道。对于时间性极强但是准确度要求不高的视频捕捉应用来说,摄像头应当使用等时传输方式。为了尽可能快地得到图像数据,应当在URB中指定USB_ISO_ASAP标志。

    urb-》transfer_flags=USB_ISO_ASAP;//尽可能快地发出本URB

    Linux系统中任何USB传输都通过URB实现。为提高速度,可以考虑扩大URB的缓冲,这样可以降低每个USB事务中握手信息所占比例,提高有效数据的传输速度。但是受限于总线带宽和具体的USB设备芯片,单纯扩大URB的缓冲不能无限制地解决问题。具体分析一下USB传输在操作系统中的实现:每次传输都要包括URB的建立、发出、回收、数据整理等阶段,这些时间不产生有效数据。因此可以建立两个URB,在等待一个URB被回收时,也就是图像正在被传感器采集时,处理、初始化另一个URB,并在回收后立刻将其发出。两个URB交替使用,大大减少了额外时间。工作流程如图1所示。

    这个过程是在URB的完成例程中实现的,有两点需要注意:首先处理再次初始化的代码时间不能长,否则会造成完成例程的重人,如果确实来不及,可以在完成例程中设定标志,例如“数据采集好”旗语,由应用程序使用阻塞ioctl()来查询该旗语并做处理;其次由于CPU可能会在完成例程中停留较长时间,系统负担较大,可以在.open函数中初始化两个URB并将其发出,有限度地减轻系统负担。

    3 使用双帧缓冲提高效率

    Linux系统中,文件操作通常是由read、write等系统调用来完成。这些系统调用在驱动中的解决方法就是用 copy_to_user()、copy_from_user()等函数在核态、户态内存空间中互相拷贝。但是对于大批量的图像数据,采用拷贝的方法显然会增加时间开销,因此用内存映射的方法解决。首先使用vmalloc()申请足够大的核态内存,将其作为图像数据缓冲空间,两个URB带回的图像数据在这里暂存;然后使用remap_page_range()函数将其逐页映射到用户空间中。户态的图像处理程序使用mmap()函数,直接读写核态图像缓冲内存,大大减少额外开销。0b1331709591d260c1c78e86d0c51c18.png

    展开全文
  • usb2.0 camera 摄像头驱动是一款万能的摄像头驱动程序,几乎支持市面上所有的摄像头型号,支持win7、win8和64位操作系统。usb2.0 camera驱动使用说明64位系统必须运行UniversalThemePatcher-x64.exe。需要管理员权限...
  • 本文从Linux内核的USB核心模块出发,遵循Video4Linux接口标准,采用urb策略与内存映射的方式以提高数据读取速度,设计开发了基于Linux环境下的USB摄像头驱动,并在ARM9实验平台上对该驱动程序进行了测试与分析。
  • packagecom.example.textureviewdemo;importjava.io.IOException;importandroid.graphics.SurfaceTexture;importandroid.media.AudioManager;importandroid.media.MediaPlayer;importandroid.media.MediaPlayer.OnBu...

    packagecom.example.textureviewdemo;importjava.io.IOException;importandroid.graphics.SurfaceTexture;importandroid.media.AudioManager;importandroid.media.MediaPlayer;importandroid.media.MediaPlayer.OnBufferingUpdateListener;importandroid.media.MediaPlayer.OnCompletionListener;importandroid.media.MediaPlayer.OnPreparedListener;importandroid.media.MediaPlayer.OnVideoSizeChangedListener;importandroid.os.Bundle;importandroid.app.Activity;importandroid.content.res.AssetFileDescriptor;importandroid.view.Menu;importandroid.view.Surface;importandroid.view.TextureView;importandroid.view.TextureView.SurfaceTextureListener;publicclass MainActivity extends Activity implements SurfaceTextureListener, OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener, OnVideoSizeChangedListener {privateTextureView mTextureView;privateMediaPlayer mMediaPlayer;@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    findViewById();

    init();

    }privatevoidinit() {

    mTextureView.setSurfaceTextureListener(this);

    }privatevoidfindViewById() {

    mTextureView = (TextureView) findViewById(R.id.textureview);

    }@OverridepublicvoidonVideoSizeChanged(MediaPlayer arg0,intarg1,intarg2) {

    }@OverridepublicvoidonPrepared(MediaPlayer arg0) {

    }@OverridepublicvoidonCompletion(MediaPlayer arg0) {

    }@OverridepublicvoidonBufferingUpdate(MediaPlayer arg0,intarg1) {

    }@OverridepublicvoidonSurfaceTextureAvailable(SurfaceTexture surface,intarg1,intarg2) {

    Surface s =newSurface(surface);try{

    mMediaPlayer =newMediaPlayer();

    AssetFileDescriptor fd =this.getAssets().openFd("video.mp4");

    mMediaPlayer.setDataSource(fd.getFileDescriptor(),

    fd.getStartOffset(), fd.getLength());

    mMediaPlayer.setSurface(s);

    mMediaPlayer.prepare();

    mMediaPlayer.setOnBufferingUpdateListener(this);

    mMediaPlayer.setOnCompletionListener(this);

    mMediaPlayer.setOnPreparedListener(this);

    mMediaPlayer.setOnVideoSizeChangedListener(this);

    mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

    mMediaPlayer.setLooping(true);

    mMediaPlayer.start();

    }catch(IllegalArgumentException e) {

    e.printStackTrace();

    }catch(SecurityException e) {

    e.printStackTrace();

    }catch(IllegalStateException e) {

    e.printStackTrace();

    }catch(IOException e) {

    e.printStackTrace();

    }

    }@OverridepublicbooleanonSurfaceTextureDestroyed(SurfaceTexture arg0) {

    mMediaPlayer.stop();returntrue;

    }@OverridepublicvoidonSurfaceTextureSizeChanged(SurfaceTexture arg0,intarg1,intarg2) {

    }@OverridepublicvoidonSurfaceTextureUpdated(SurfaceTexture arg0) {

    }

    }

    展开全文
  • 驱动程序-其它驱动-usb视频设备驱动(usb摄像头驱动).zip
  • USB摄像头驱动框架

    2019-08-07 12:27:31
    写一个USB摄像头驱动程序 1.构造一个usb_driver 2.设置 probe: 2.1. 分配video_device:video_device_alloc 2.2. 设置 .fops .ioctl_ops (里面需要设置11项) 如果要用内核提供的缓冲区操作函数,还需要构造一...
  • ROS uvc_cam USB 网络摄像头驱动程序的分支。 请注意,此驱动程序实际上使用 Video4Linux API,因此即使它们支持 UVC 设备,也无法在非 Linux 平台上运行。 请注意,此驱动程序不再维护。 它被留下以防万一人们...
  • 这是用于Android的USB网络摄像头驱动程序的实现,该驱动程序提供了纯Java接口。 该项目的目标是避免其他可用库的缺点,并以最小的“调整”要求为多种网络摄像头设备提供跨设备支持。 引擎盖下有本机C代码,但是库...
  • STM32F103USB摄像头驱动

    万次阅读 热门讨论 2015-04-03 13:55:23
    代码是从原子的触控鼠标实验改过来的,煎蛋实现了一个USB摄像头,可以将一帧320*240的JPG图片发送到HOST,所以并不包含摄像头驱动代码. 代码很简单,作为学习UVC或者参考也是不错的. PC上看到的图像 MDK项目文件: ...
  • Linux USB 摄像头驱动

    万次阅读 热门讨论 2017-12-10 11:33:59
          在 cortex-a8 中,可接入摄像头的接口通常可以分为两种, CAMERA 接口和 USB 接口的摄像头。这一章主要是介绍 USB 摄像头...这一章我们讲 USB 摄像头设备驱动,那么是不是支持所有的 USB 摄像头驱动...
  • 从0写USB摄像头驱动程序

    千次阅读 2015-10-01 14:58:41
    从0写USB摄像头驱动程序 1.构造一个usb_driver结构体 .id_table .probe 1.分配video_device结构体 2.设置 3.注册 2.下面具体分析probe函数中的内容: 定义:static struct video_device *myuvc_vdev; myuvc_vdev=...
  • 普通USB摄像头开发

    2016-03-13 08:47:45
    usb摄像头编程,采用纯API写的视频捕捉程序。你可在此基础上再写出适合自己的程序
  • 网络摄像头通常支持 USB 视频类 (UVC) 驱动程序,并且在 Linux 上,系统采用标准的 Video4Linux (V4L) 驱动程序控制 UVC 摄像头。 如果系统支持网络摄像头,设备便可用于视频聊天和照片冲印机等轻量级用例。此功能...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,539
精华内容 3,815
关键字:

usb摄像头驱动程序