海王  
公告
日历
统计
  • 随笔 - 410
  • 文章 - 2
  • 评论 - 11
  • 引用 - 0

导航

 

2010年8月19日

http://blog.csdn.net/ipromiseu/archive/2010/03/29/5428578.aspx

一.什么是video4linux
Video4linux2(简称V4L2),是linux中关于视频设备的内核驱动。

V4L2较V4L有较大的改动,并已成为2.6的标准接口,函盖video\dvb\FM...,多数驱动都在向V4l2迁移。更好地了解V4L2先从应用入手,然后再深入到内核中结合物理设备/接口的规范实现相应的驱动。V4L2采用流水线的方式,操作更简单直观,基本遵循打开视频设备、设置格式、处理数据、关闭设备,更多的具体操作通过ioctl函数来实现。

在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video0下。

二、一般操作流程(视频设备):
1. 打开设备文件。 int fd=open(”/dev/video0″,O_RDWR);
2. 取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability
3. 选择视频输入,一个视频设备可以有多个视频输入。VIDIOC_S_INPUT,struct v4l2_input
4. 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format
5. 向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers
6. 将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。mmap
7. 将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer
8. 开始视频的采集。VIDIOC_STREAMON
9. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF
10. 将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF
11. 停止视频的采集。VIDIOC_STREAMOFF
12. 关闭视频设备。close(fd);
三、常用的结构体(参见/usr/include/linux/videodev2.h):

struct v4l2_requestbuffers reqbufs;//向驱动申请帧缓冲的请求,里面包含申请的个数
struct v4l2_capability cap;//这个设备的功能,比如是否是视频输入设备
struct v4l2_input input; //视频输入
struct v4l2_standard std;//视频的制式,比如PAL,NTSC
struct v4l2_format fmt;//帧的格式,比如宽度,高度等

struct v4l2_buffer buf;//代表驱动中的一帧
v4l2_std_id stdid;//视频制式,例如:V4L2_STD_PAL_B
struct v4l2_queryctrl query;//查询的控制
struct v4l2_control control;//具体控制的值

四、细节

1.打开视频设备
在V4L2中,视频设备被看做一个文件。使用open函数打开这个设备:

// 用非阻塞模式打开摄像头设备int cameraFd;cameraFd = open("/dev/video0", O_RDWR | O_NONBLOCK, 0);// 如果用阻塞模式打开摄像头设备,上述代码变为://cameraFd = open("/dev/video0", O_RDWR, 0);应用程序能够使用阻塞模式或非阻塞模式打开视频设备,如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。

2. 设定属性及采集方式
打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。这一步是可选的。在Linux编程中,一般使用ioctl函数来对设备的I/O通道进行管理:

int ioctl (int __fd, unsigned long int __request, .../*args*/) ;在进行V4L2开发中,常用的命令标志符如下(some are optional):

VIDIOC_REQBUFS:分配内存
VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
VIDIOC_QUERYCAP:查询驱动功能
VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式
VIDIOC_S_FMT:设置当前驱动的频捕获格式
VIDIOC_G_FMT:读取当前驱动的频捕获格式
VIDIOC_TRY_FMT:验证当前驱动的显示格式
VIDIOC_CROPCAP:查询驱动的修剪能力
VIDIOC_S_CROP:设置视频信号的边框
VIDIOC_G_CROP:读取视频信号的边框
VIDIOC_QBUF:把数据从缓存中读取出来
VIDIOC_DQBUF:把数据放回缓存队列
VIDIOC_STREAMON:开始视频显示函数
VIDIOC_STREAMOFF:结束视频显示函数
VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。
2.1检查当前视频设备支持的标准
在亚洲,一般使用PAL(720X576)制式的摄像头,而欧洲一般使用NTSC(720X480),使用VIDIOC_QUERYSTD来检测:

v4l2_std_id std;do {  ret = ioctl(fd, VIDIOC_QUERYSTD, &std);} while (ret == -1 && errno == EAGAIN);switch (std) {    case V4L2_STD_NTSC:        //……    case V4L2_STD_PAL:        //……}2.2 设置视频捕获格式
当检测完视频设备支持的标准后,还需要设定视频捕获格式,结构如下:

struct v4l2_format fmt;

memset ( &fmt, 0, sizeof(fmt) );fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;fmt.fmt.pix.width       = 720;fmt.fmt.pix.height      = 576;fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {  return -1;}v4l2_format结构如下:struct v4l2_format{    enum v4l2_buf_type type;    // 数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE     union    {        struct v4l2_pix_format    pix;          struct v4l2_window        win;          struct v4l2_vbi_format    vbi;          __u8    raw_data[200];              } fmt;};struct v4l2_pix_format{    __u32                   width;         // 宽,必须是16的倍数    __u32                   height;        // 高,必须是16的倍数    __u32                   pixelformat;   // 视频数据存储类型,例如是YUV4:2:2还是RGB    enum v4l2_field         field;    __u32                   bytesperline;        __u32                   sizeimage;    enum v4l2_colorspace    colorspace;    __u32                   priv;       };2.3 分配内存接下来可以为视频捕获分配内存:

struct v4l2_requestbuffers  req;if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {  return -1;}v4l2_requestbuffers 结构如下:struct v4l2_requestbuffers{    __u32               count;  // 缓存数量,也就是说在缓存队列里保持多少张照片    enum v4l2_buf_type  type;   // 数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE     enum v4l2_memory    memory; // V4L2_MEMORY_MMAP 或 V4L2_MEMORY_USERPTR    __u32               reserved[2];};2.4 获取并记录缓存的物理空间
使用VIDIOC_REQBUFS,我们获取了req.count个缓存,下一步通过调用VIDIOC_QUERYBUF命令来获取这些缓存的地址,然后使用mmap函数转换成应用程序中的绝对地址,最后把这段缓存放入缓存队列:

typedef struct VideoBuffer {    void   *start;    size_t  length;} VideoBuffer;VideoBuffer*          buffers = calloc( req.count, sizeof(*buffers) );struct v4l2_buffer    buf;for (numBufs = 0; numBufs < req.count; numBufs++) {    memset( &buf, 0, sizeof(buf) );    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    buf.memory = V4L2_MEMORY_MMAP;    buf.index = numBufs;    // 读取缓存    if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {        return -1;    }    buffers[numBufs].length = buf.length;    // 转换成相对地址    buffers[numBufs].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,        MAP_SHARED,fd, buf.m.offset);    if (buffers[numBufs].start == MAP_FAILED) {        return -1;    }    // 放入缓存队列    if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {        return -1;    }}2.5 视频采集方式
操作系统一般把系统使用的内存划分成用户空间和内核空间,分别由应用程序管理和操作系统管理。应用程序可以直接访问内存的地址,而内核空间存放的是供内核访问的代码和数据,用户不能直接访问。v4l2捕获的数据,最初是存放在内核空间的,这意味着用户不能直接访问该段内存,必须通过某些手段来转换地址。

一共有三种视频采集方式:使用read、write方式;内存映射方式和用户指针模式。

read、write方式,在用户空间和内核空间不断拷贝数据,占用了大量用户内存空间,效率不高。

内存映射方式:把设备里的内存映射到应用程序中的内存控件,直接处理设备内存,这是一种有效的方式。上面的mmap函数就是使用这种方式。

用户指针模式:内存片段由应用程序自己分配。这点需要在v4l2_requestbuffers里将memory字段设置成V4L2_MEMORY_USERPTR。

2.6 处理采集数据
V4L2有一个数据缓存,存放req.count数量的缓存数据。数据缓存采用FIFO的方式,当应用程序调用缓存数据时,缓存队列将最先采集到的视频数据缓存送出,并重新采集一张视频数据。这个过程需要用到两个ioctl命令,VIDIOC_DQBUF和VIDIOC_QBUF:

struct v4l2_buffer buf;memset(&buf,0,sizeof(buf));buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory=V4L2_MEMORY_MMAP;buf.index=0;//读取缓存if (ioctl(cameraFd, VIDIOC_DQBUF, &buf) == -1){    return -1;}//…………视频处理算法//重新放入缓存队列if (ioctl(cameraFd, VIDIOC_QBUF, &buf) == -1) {    return -1;}3. 关闭视频设备
使用close函数关闭一个视频设备

close(cameraFd)如果使用mmap,最后还需要使用munmap方法。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ipromiseu/archive/2010/03/29/5428578.aspx

posted @ 2010-08-19 23:16 海王 阅读(730) 评论(1) 编辑
 

时代周刊最近举办了第一届年度博客评选,选25个最好的博客,让我们一起来看看。

1.The Huffington Post

政治类博客。通过大量的视频、图片和文字关注米国热门政治、军事、传媒和民生等问题。

2.Lifehacker

生活类博客。生活中有如此多的麻烦事,主要提供Windows、Mac os x、Linux等操作系统的技巧,当然也有诸如如何通过游泳减肥,旅行时不要带太多东西,钱包要放在前面的牛仔裤口袋里等生活小技巧。 lifehacker的口号是不要生活得像个奇客,而要像奇客一样生活?

3.Metafilter

媒体聚合类博客,metafilter已经有长达9年的历史,和国内的爱枣报有点类似。

4.TreeHugger

环保类博客,关注自然、饮食、健康等,口号是“给你一个绿色的世界”。

5.PostSecret

blogspot上架设的博客,目前我这里无法访问。

6.Blog di Beppe Grillo

评论性博客,因其上面有free ti-bet等不河蟹内容,故没有给出链接。

7.Engadget

关于电脑周边的科技型博客,中文博客名为瘾科技。

8.Freakonomics

又一个评论性博客。

9.Gigazine

日本语博客。
10.Ace of Spades HQ

评论性博客,博主的简介很暴力,图片上面的注释是“FBI通缉犯”,而捐款文字更是暴力:我穷困潦倒,请给我钱。(I have no life,please give me money.)而其最近的评论居然全部都是”上海翻译公司“的spam,强。

11.Radosh.net

关注流行、趣味和美女方面的东东。

12.Gawker

关注一些八卦消息。

13.Andrew Sullivan

不知道怎么归类。

14.Velveteen Rabbi

人文类博客,貌似是个学生写的。

15.Boing Boing

趣味类博客。

16.TechCrunch

关注互联网最新产品和应用。

17.Web 2.Oh…really?

wordpress.com下的博客,同样无法访问,看标题应该是关于web2.0的。

18.The Sartorialist

blogspot博客。

19.Daily Kos

政治性博客。

20.The Consumerist

博主自我介绍是关于消费折扣之类的博客,但内容却又许多交通工具、笔记本电脑等方面的消息。

21.Indexed

blogspot博客,无法访问。

22.Threat Level

关注隐私、安全、政治和网络犯罪等。

23.The Dullest Blog in the World

世界上最枯燥的博客,作者像记流水帐一样记录生活中极其无聊的事,诸如“今天,我看到一只钢笔掉在了地上,我就把它捡起来“之类。

24.Bad Jocks

生活、人文类博客,貌似无法访问。

25.The Reverse Cowgirl

摄影博客,作者是给花花公子等杂志供稿的摄影人,关注女性,有不河蟹内容。

遗憾的是,这些所谓最好的博客我一个都不知道,之前也一个都没有看过。什么时候也评出最好的中文博客呢?相信你也有自己的想法吧,留言告知吧。

英文原文链接:http://www.time.com/time/specials/2007/0,28757,1725323,00.html

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ipromiseu/archive/2010/04/22/5518004.aspx

posted @ 2010-08-19 22:58 海王 阅读(76) 评论(0) 编辑
 

http://coolshell.cn/?p=1870

 

很早以前就想写一篇和面试相关的文章了,今天在网络上看到一篇关于如何去面试程序员的英文文章,发现其中有很多和我共鸣的东西,所以仿照其标题通过自己的经历写下了这篇文章。

工作这么多年来,即被面试过,也面试过他人,对于程序员的面试,经历过很不错的面试,很专业的面试,也经历过一些BT和令人不爽的面试,我个人觉得一个好的面试,面试官是很重要的,所以,本文想从“面试官”的角度来阐述一下。于是,有了下面这样一篇的文章,希望本文对你的职场经历有用,特别是那些正在招聘和面试程序员的朋友,我觉得这篇文章会对大家有很多启示。此外,做为被面试的人,你可以看看本站的《别的程序员是怎么读你的简历的》《程序员需要具备的基本技能》《优秀程序员的十个习惯》其它一些和程序员相关的文章。

对于招聘方来说,在招聘程序员的时候,我估计面试应聘者时,最主要想知道的是下面三件事:

这个程序员的是否够聪明?
这个程序员能否把事情搞定?
这个程序员能和我的团队在一起工作吗?
我相信,这是所有团队经理招人要考虑的三个问题,所有的问题也基本上围绕着这三个问题。有些时候,你也许觉得程序员的技术技能可以同时解决这三个问题,一个技术能力优秀的人必然是一个聪明的,可以搞定事情的人,当然也就能和团队一起工作了。是的,感觉看起来是这个样子,但其实并不是这样的。有些人的确很聪明,但却不能处理好工作上的事情,这样人应该是你的朋友,你的顾问,但不应该是你的雇员。有的人为人很不错,和团队所有人都合得来,但并不是很聪明,但工作很刻苦很努力,这样的人可以成为你的下属,比如某个下属骨干的助手,或是整个团队的助手。如果某个人不能和团队一起工作,无论其有多聪明,解决问题的能力有多强,你都不应该和他在一起工作。人个认为,团队的和谐是一切事情的前提。

对于传统的面试招聘过程,基本上来说都是下面这样的样子的:

阅读应聘者的简历,让应聘者做个自我介绍。
问一些比较难的非常细节的技术问题,以一问一答的形式。
给面试者一些和几个编程难题。(比如某些怪异的算法题)
我个人觉得这种面试方法很可笑,也很糟糕,尤其是后面两点。通常来说,这样的面试只会让你面试到一些“书呆子”或是一些“技术痴迷者”,下面让我来一条一条地剖析一下这几条的弊端。

你很难从一个人的简历或是自我介绍上了解一个人。因为这些都是当事人自己写的,或是自己阐述的。所以,这并不是很准确的,通过简历,你只能知道很简单的事情,这对于是否能招入团是远远不够的。而在面试的开始,让应聘者做自我介绍,只会让面试者以很正式的态度来面对整个面试。一但面试过程很正式,很严肃,就会让人很拘禁,其实,这并不是我们想要的,我要的是应聘者真实和自然的表现,从而才能了解到最真实的东西。
问几个技术难题。比如:我个人经历过的——“ps的-a参数是什么意思?”,“vi中删除换行符的命令是什么?”,“C++的关键字explict,mutable是用来干什么?”等等,等等。以前做为一个应聘者来说,我非常讨厌这样的问题,因为这样的问题查一下手册就知道。难道他要招的是一个字典手册?不是一个人?对于这方面,重要的不是知识,重要的是其查找知识的能力。
给应聘者一个或几个很难的算法题,给上十几分钟,然后让面试者把伪代码或是代码写下来。这样的做法是相当可笑的,不能讨论不能查资料,让人在一种压力状态下作答,这根本就不是实际工作中的状态,而我们的面试也就成了一种刁难(我最变态的经历是,当我把写在两页纸上的代码上交上去后,面试官把其交给旁边程序员输出电脑做校验,结果程序员说,编译出错。于是,面试官说,“很遗憾,可能你写的程序还不多”,相当可笑)。对于这点来说,重要的不是那个解题的答案,而是解题的思路和方法。
我以前经历过很多的面试,当技术人员来和我做面试的时候,我发现,“技术人员的思维”对于某些人来说根本分不清面试和考试,在潜意识里,他们在很多时候不是在面试这个人,而是在刁难这个人并以此展示自己的技能。我个人认为我是一个好的程序员,但我可以告诉你我无法通过那样的面试,因为那样的面试是为他们自己准备的,而不是为应聘者准备的。

那么,我又是怎样去面试的呢?

一、确认简历。首先,阅读一下别人的简历是需要的,从简历上,工作经历,项目经历,技术技能这三个事情是你需要了解的。一般来说,你可以先通过电话确定一下他的工作经历,项目经历和技术技能,然后,如果他和你需要的人条件相符的话,可以叫到公司做面对面的面试。千万不要把别人叫来,你又说你的经历和我们的工作有差距之类的话。(我有过一次面试经历,公司我不说了,反正是那个号称需要有良好沟通的公司,面试了我9次左右,从一般的程序员,PM,经理,到总经理,而最后一次直接告诉我,我以前的经历和他们的要求差距很大。我不禁要问了,前面若干次的面试他们都在干什么呢?)

二、面试开场。其次,把人邀请来公司面试,应聘者到了公司来面试,有一点很重要,那就是你一定要让整个面试过程变得很随意,很放松,就像普通的聊天和一般朋友间的交流一样。这样应聘者才会放松并拿出真实的样子来和你谈话和聊天,你才能在很短的时间内了解得更多。让应聘者放下心理负担,让其表现得自然一些,这是招聘方的责任。千万不要说,别人太紧张发挥的不好,有时候,招聘方得想想自己的问题。

面试开场的时候,千万不要让应聘者介绍自己,因为,应聘者早就给你发过简历了,而你也给其打过电话了。另外,应聘者对这个面试惯例通常都会准备得非常不错的,另一方面,这会让整个面试过程太正式太严肃了。所以,不妨问问应聘者是怎么过来的?最近怎么样?还可以和应聘者谈一个大众话题,比如喜欢什么体育,音乐,电影,社会热点什么的,自己也别板着个脸,说说笑笑,试图让大家都放松下来。另外,通过这些闲聊,你可以知道他/她的与人交往能力和一些性格。另外,不要让桌子放在你和应聘者之间,把环境搞得随意一些。

三、多让应聘者说说他的经历。接下来,如果你要觉得这个应聘者是否是一个可以解决问题,是一个可以把事情搞定的人,不用问他/她会做什么,直接问问其做过什么?干过什么事?对于一个好的程序员来说,很难想像其没有相关的实践,就算你是在大学里,你也应该做过什么。如果你有解决问题的能力,那么,很显然,今天你应该解决了很多问题,也搞定了很多事情,听听应聘者说一说他的那些事。(不要使用一问一答这种方式,应该让应聘者多说,而多听,多想)

在他讲他的项目的时候,通常来说你要注意下面几点:

沟通表达能力。应聘者能不能把一个事情讲清楚。如果这个人聪明的话,他就可以用最简单的语言把一个复杂的事情讲清楚。而且,这是一个好的程序员最基本的能力。而且,你可以在应聘者一边描述其经历的时候,你可以和应聘者有一些的良好的来来回回的交谈,这样就可以知道,他的沟通能力和沟通方式,从而了解他的性格,。
角色和位置。也许他参与了一个很大的项目,但只是做了一个很简单的模块。所以,了解其在项目中的担任的角色和位置是非常必要的。当应聘者说到“我们”或者“大家”之类的词汇时,一定要向下细化和明确。
做出的贡献和解决了什么的问题。这个很重要,通过了解这个,你可以知道面试者是否聪明,是否有能力解决问题,是否有好的技术底子。
演示。如果可能,你可以让应聘者展示一些其写过的代码,做过的设计,或是直接给你看看他写的程序的演示。(从设计上,代码的风格,重用性,维护性上你可以了解很多很多)
基础知识。了解该项目中应聘者使用的技术的一些基础知识,比如,通过整个过程,你可以问一些网络,语言,面象对象,系统的一些基础知识。基础知识是非常重要的,这直接关系到了他的能力。
流程和工具。了解应聘者所熟悉的项目的流程(银弹,瀑布,敏捷,……),还有流程中的一些工件(如:需求文档,设计文档,测试方档等),以及在开发过程中使用的工具(内存测试,代码检查,BUG报告,版本维护,开发调试……)(关于程序员的基本技能,你可以参考——《程序员需要具备的基本技能》)
有人会说,应聘者的经历可以被他自己编出来的,他可以把一些不是他做的事说成是他做的。是的,的确是有这种可能。不过,不要忘了,一个谎言背后需要用更多的谎言来圆谎的,所以,你不必担心这个问题,只要你在应聘者的描述过程中逐步求精,细化问题,你会知道应聘者是否是在编故事的。

千万记住下面几点:

谈话风格要随意和自然,不要正式。
在了解应聘者以前做过的事的时候,不要太投入了。因为招聘方也是技术人员,所以有时候,招聘者自己会因为应聘者所做的项目中的技术太过迷人而被吸引了。
要注意引导应聘人。相信我,应聘的程序员十个人有八个人讲不清楚以前做的是什么。因为他们直接跳过了项目背景和要解决什么样的问题,而直接进入具体实现。
不要一问一答,应该多让应聘者说,这样才能多全方位了解一个人。
了解一个人的过去,了解一个人做过的事情,比其会做什么更重要。
了解一个人的性格,想法,思维和行为,比了解其技术技能更重要。
沟通能力,表达能力,语言组织能力,理解能力,等方面的能力,关系到了是否能和别人一起工作。
基础知识比知识的点滴要重要得多。你可能不知道其个C++的关键字,但你应该要知道C++的继承和多态。
技术技能固然很重要,但比其更重要的是这个人获取知识的能力,学习能力是在计算机这样变化飞快行业中必需具备的。
是否可以进行培养,比掌握的技能更重要。
四、实际参与??这一步可能是很不好实施的。因为,这需要一些应聘者付出一定的时间,如果是毕业生,那没有问题,先让他来实习一段时间。但如果别人有工作,就不好了。也许你会说,这就是试用期的用处了。不过,我个人觉得,你得要尊重应聘者,人家把那边的工作辞了,来你这边工作,三个月试用期间,如果没有什么原则上的问题,你作为一个招聘方又反悔了,这样做很是相当的不好。如果发现这样的事,只能是招聘者自己的问题。

在面试过程中,一些招聘者会让应聘者们一起做个游戏,或是搞个辩论比赛,或是现场组个团队干个简单的事情,有的甚至让应聘者请一天假到自己的公司里来和自己的团队一同工作一天,并要完成某个事情(甚至给其设置上deadline),并通过这些来考量应聘者的实际参与能力。

是的,如果没有一起工作过,没有一些实际的事情发生,单靠几个小时的面试很难了解一个人的。设置上这些面试的环节,在最短的时间内来了解应聘者的一切,对于招聘方来说无可厚非。而且有的时候也能得到不错的效果。在这里,我只提一点,有时候这样的周期拉得很长,让应聘者付出了很多,反尔会让应聘者产生反感和厌烦情绪,从某种意义上来说,这实在是对应聘者的不尊重。

对于这一点,我一直持疑问的态度,所以,我在其后打了两个问号。老实说,对于实际参与这一环节,我个人的意见是适可而止,因为时间太短了,无论你怎么做你都无法了解完整。即然无法了解完整,那就获取你最需要的吧,就是本文开头的那三个问题,以及上面所述的“第三点”(了解应聘者的以往经历)。

也许这个文章中有一些你不同意的观点,没问题,欢迎批评,如果你有更好的做法,我也想听听,不妨在这里留个言,如果不想留也可以email给我。

(全文完)

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ipromiseu/archive/2010/04/21/5512410.aspx

posted @ 2010-08-19 22:55 海王 阅读(387) 评论(1) 编辑
 

如果这篇文章没有分享给你,那是我的错。
如果这篇文章分享给你了,你却没有读,继续走弯路的你不要怪我。
如果你看了这篇文章,只读了一半你就说没时间了,说明你已经是个“茫”人了。
如果你看完了,你觉得这篇文章只是讲讲大道理,说明你的人生阅历还不够,需要你把这篇文章珍藏,走出去碰几年壁,头破血流后再回来,再读,你就会感叹自己的年少无知。
如果你看完了,觉得很有道理,然后束之高阁,继续走进拥挤的地铁,依然用着自己昨日的观念来思考自己的未来,你的人生也将继续重复着昨日的状况。
如果你看完了,觉得那是一个过来人,对你的人生忠告,并你也愿意用他告诉你的思想去指导自己今后的生活,对你来讲成功不是很难,难的是你是否可以用这篇文章里的思想一直鞭策自己。
如果你看完了,觉得那是一个长辈用他的一生的时间来写的一篇对你忠告的文章,说明你已经有了和他相似的人生阅历,只要你继续努力,成就伟业并不难,难的是你是否可以把自己的人生经验和他人分享呢?
体验决定深度,知识决定广度。你的人生是什么呢?
----------强烈推荐
一、关于工作与生活
  我有个有趣的观察,外企公司多的是25-35岁的白领,40岁以上的员工很少,二三十岁的外企员工是意气风发的,但外企公司40岁附近的经理人是很尴尬的。我见过的40岁附近的外企经理人大多在一直跳槽,最后大多跳到民企,比方说,唐骏。外企员工的成功很大程度上是公司的成功,并非个人的成功,西门子的确比国美大,但并不代表西门子中国经理比国美的老板强,甚至可以说差得很远。而进外企的人往往并不能很早理解这一点,把自己的成功90%归功于自己的能力,实际上,外企公司随便换个中国区总经理并不会给业绩带来什么了不起的影响。好了问题来了,当这些经理人40多岁了,他们的薪资要求变得很高,而他们的才能其实又不是那么出众,作为外企公司的老板,你会怎么选择?有的是只要不高薪水的,要出位的精明强干精力充沛的年轻人,有的是,为什么还要用你?
  从上面这个例子,其实可以看到我们的工作轨迹,二三十岁的时候,生活的压力还比较小,身体还比较好,上面的父母身体还好,下面又没有孩子,不用还房贷,也没有孩子要上大学,当个外企小白领还是很光鲜的,挣得不多也够花了。但是人终归要结婚生子,终归会老,到了40岁,父母老了,要看病要吃药,要有人看护,自己要还房贷,要过基本体面的生活,要养小孩……那个时候需要挣多少钱才够花才重要。所以,看待工作,眼光要放远一点,一时的谁高谁低并不能说明什么。
  从这个角度上来说,我不太赞成过于关注第一份工作的薪水,更没有必要攀比第一份工作的薪水,这在刚刚出校园的学生中间是很常见的。正常人大概要工作 35年,这好比是一场马拉松比赛,和真正的马拉松比赛不同的是,这次比赛没有职业选手,每个人都只有一次机会。要知到,有很多人甚至坚持不到终点,大多数人最后是走到终点的,只有少数人是跑过终点的,因此在刚开始的时候,去抢领先的位置并没有太大的意义。刚进社会的时候如果进500强公司,大概能拿到3k -6k/月的工资,有些特别技术的人才可能可以到8k/月,可问题是,5年以后拿多少?估计5k-10k了不起了。起点虽然高,但增幅有限,而且,后面的年轻人追赶的压力越来越大。
  我前两天问我的一个销售,你会的这些东西一个新人2年就都学会了,但新人所要求的薪水却只是你的一半,到时候,你怎么办?
  职业生涯就像一场体育比赛,有初赛、复赛、决赛。初赛的时候大家都刚刚进社会,大多数都是实力一般的人,这时候努力一点认真一点很快就能让人脱颖而出,于是有的人二十多岁做了经理,有的人迟些也终于赢得了初赛,三十多岁成了经理。然后是复赛,能参加复赛的都是赢得初赛的,每个人都有些能耐,在聪明才智上都不成问题,这个时候再想要胜出就不那么容易了,单靠一点点努力和认真还不够,要有很强的坚忍精神,要懂得靠团队的力量,要懂得收服人心,要有长远的眼光……
  看上去赢得复赛并不容易,但,还不是那么难。因为这个世界的规律就是给人一点成功的同时让人骄傲自满,刚刚赢得初赛的人往往不知道自己赢得的仅仅是初赛,有了一点小小的成绩大多数人都会骄傲自满起来,认为自己已经懂得了全部,不需要再努力再学习了,他们会认为之所以不能再进一步已经不是自己的原因了。虽然他们仍然不好对付,但是他们没有耐性,没有容人的度量,更没有清晰长远的目光。就像一只愤怒的斗牛,虽然猛烈,最终是会败的,而赢得复赛的人则象斗牛士一样,不急不躁,跟随着自己的节拍,慢慢耗尽对手的耐心和体力。赢得了复赛以后,大约已经是一位很了不起的职业经理人了,当上了中小公司的总经理,大公司的副总经理,主管着每年几千万乃至几亿的生意。
  最终的决赛来了,说实话我自己都还没有赢得决赛,因此对于决赛的决胜因素也只能凭自己的猜测而已,这个时候的输赢或许就像武侠小说里写得那样,大家都是高手,只能等待对方犯错了,要想轻易击败对手是不可能的,除了使上浑身解数,还需要一点运气和时间。世界的规律依然发挥着作用,赢得复赛的人已经不只是骄傲自满了,他们往往刚愎自用,听不进去别人的话,有些人的脾气变得暴躁,心情变得浮躁,身体变得糟糕,他们最大的敌人就是他们自己,在决赛中要做的只是不被自己击败,等着别人被自己击败。这和体育比赛是一样的,最后高手之间的比赛,就看谁失误少谁就赢得了决赛。
  二、 根源
  你工作快乐么?你的工作好么?
  有没有觉得干了一段时间以后工作很不开心?有没有觉得自己入错了行?有没有觉得自己没有得到应有的待遇?有没有觉得工作像一团乱麻每天上班都是一种痛苦?有没有很想换个工作?有没有觉得其实现在的公司并没有当初想象得那么好?有没有觉得这份工作是当初因为生存压力而找的,实在不适合自己?你从工作中得到你想要得到的了么?你每天开心么?
  天涯上愤怒的人很多,你有没有想过,你为什么不快乐?你为什么愤怒?
  其实,你不快乐的根源,是因为你不知道要什么!你不知道要什么,所以你不知道去追求什么,你不知道追求什么,所以你什么也得不到。
  我总觉得,职业生涯首先要关注的是自己,自己想要什么?大多数人大概没想过这个问题,唯一的想法只是——我想要一份工作,我想要一份不错的薪水,我知道所有人对于薪水的渴望,可是,你想每隔几年重来一次找工作的过程么?你想每年都在这种对于工作和薪水的焦急不安中度过么?不想的话,就好好想清楚。饮鸩止渴,不能因为口渴就拼命喝毒药。越是焦急,越是觉得自己需要一份工作,越饥不择食,越想不清楚,越容易失败,你的经历越来越差,下一份工作的人看着你的简历就皱眉头。于是你越喝越渴,越渴越喝,陷入恶性循环。最终只能哀叹世事不公或者生不逢时,只能到天涯上来发泄一把,在失败者的共鸣当中寻求一点心理平衡罢了。大多数人都有生存压力,我也是,有生存压力就会有很多焦虑,积极的人会从焦虑中得到动力,而消极的人则会因为焦虑而迷失方向。所有人都必须在压力下做出选择,这就是世道,你喜欢也罢不喜欢也罢。
  一般我们处理的事情分为重要的事情和紧急的事情,如果不做重要的事情就会常常去做紧急的事情。比如锻炼身体保持健康是重要的事情,而看病则是紧急的事情。如果不锻炼身体保持健康,就会常常为了病痛烦恼。又比如防火是重要的事情,而救火是紧急的事情,如果不注意防火,就要常常救火。找工作也是如此,想好自己究竟要什么是重要的事情,找工作是紧急的事情,如果不想好,就会常常要找工作。往往紧急的事情给人的压力比较大,迫使人们去赶紧做,相对来说重要的事情反而没有那么大的压力,大多数人做事情都是以压力为导向的,压力之下,总觉得非要先做紧急的事情,结果就是永远到处救火,永远没有停歇的时候。(很多人的工作也像是救火队一样忙碌痛苦,也是因为工作中没有做好重要的事情。)那些说自己活在水深火热为了生存顾不上那么多的朋友,今天找工作困难是当初你们没有做重要的事情,是结果不是原因。如果今天你们还是因为急于要找一份工作而不去思考,那么或许将来要继续承受痛苦找工作的结果。
  我始终觉得我要说的话题,沉重了点,需要很多思考,远比唐笑打武警的话题来的枯燥乏味,但是,天下没有轻松的成功,成功,要付代价。请先忘记一切的生存压力,想想这辈子你最想要的是什么?所以,最要紧的事情,先想好自己想要什么。
  三、什么是好工作
  当初微软有个唐骏,很多大学里的年轻人觉得这才是他们向往的职业生涯,我在清华bbs里发的帖子被这些学子们所不屑,那个时候学生们只想出国或者去外企,不过如今看来,我还是对的,唐骏去了盛大,陈天桥创立的盛大,一家民营公司。一个高学历的海归在500强的公司里拿高薪水,这大约是很多年轻人的梦想,问题是,每年毕业的大学生都在做这个梦,好的职位却只有500个。
  人都是要面子的,也是喜欢攀比的,即使在工作上也喜欢攀比,不管那是不是自己想要的。大家认为外企公司很好,可是好在哪里呢?好吧,他们在比较好的写字楼,这是你想要的么?他们出差住比较好的酒店,这是你想要的么?别人会羡慕一份外企公司的工作,这是你想要的么?那一切都是给别人看的,你干吗要活得那么辛苦给别人看?另一方面,他们薪水福利一般,并没有特别了不起,他们的晋升机会比较少,很难做到很高阶的主管,他们虽然厌恶常常加班,却不敢不加班,因为“你不干有得是人干”,大部分情况下会找个台湾人香港人新加坡人来管你,而这些人又往往有些莫名其妙的优越感。你想清楚了么?500强一定好么?找工作究竟是考虑你想要什么,还是考虑别人想看什么?
  我的大学同学们大多数都到美国了,甚至毕业这么多年了,还有人最近到国外去了。出国真的有那么好么?我的大学同学们,大多数还是在博士、博士后、访问学者地挣扎着,至今只有一个正经在一个美国大学里拿到个正式的教职。国内的教授很难当么?我有几个表亲也去了国外了,他们的父母独自在国内,没有人照顾,有好几次人在家里昏倒都没人知道,出国,真的这么光彩么?就像有人说的“很多事情就像看A片,看的人觉得很爽,做的人未必。”
  人总想找到那个最好的,可是,什么是最好的?你觉得是最好的那个,是因为你的确了解,还是因为别人说他是最好的?即使他对于别人是最好的,对于你也一定是最好的么?
  对于自己想要什么,自己要最清楚,别人的意见并不是那么重要。很多人总是常常被别人的意见所影响,亲戚的意见,朋友的意见,同事的意见……问题是,你究竟是要过谁的一生?人的一生不是父母一生的续集,也不是儿女一生的前传,更不是朋友一生的外篇,只有你自己对自己的一生负责,别人无法也负不起这个责任。自己做的决定,至少到最后,自己没什么可后悔。对于大多数正常智力的人来说,所做的决定没有大的对错,无论怎么样的选择,都是可以尝试的。比如你没有考自己上的那个学校,没有入现在这个行业,这辈子就过不下去了?就会很失败?不见得。
  我想,好工作,应该是适合你的工作,具体点说,应该是能给你带来你想要的东西的工作,你或许应该以此来衡量你的工作究竟好不好,而不是拿公司的大小,规模,外企还是国企,是不是有名,是不是上市公司来衡量。小公司,未必不是好公司,赚钱多的工作,也未必是好工作。你还是要先弄清楚你想要什么,如果你不清楚你想要什么,你就永远也不会找到好工作,因为你永远只看到你得不到的东西,你得到的,都是你不想要的。
  可能,最好的,已经在你的身边,只是,你还没有学会珍惜。人们总是盯着得不到的东西,而忽视了那些已经得到的东西。
  四、普通人
  我发现中国人的励志和国外的励志存在非常大的不同,中国的励志比较鼓励人立下大志愿,卧薪尝胆,有朝一日成富成贵。而国外的励志比较鼓励人勇敢面对现实生活,面对普通人的困境,虽然结果也是成富成贵,但起点不一样,相对来说,我觉得后者在操作上更现实,而前者则需要用999个失败者来堆砌一个成功者的故事。
  我们都是普通人,普通人的意思就是,概率这件事是很准的。因此,我们不会买彩票中500万,我们不会成为比尔盖茨或者李嘉诚,我们不会坐飞机掉下来,我们当中很少的人会创业成功,我们之中有30%的人会离婚,我们之中大部分人会活过65岁……
  所以请你在想自己要什么的时候,要得“现实”一点,你说我想要做李嘉诚,抱歉,我帮不上你。成为比尔盖茨或者李嘉诚这种人,是靠命的,看我写的这篇文章绝对不会让你成为他们,即使你成为了他们,也绝对不是我这篇文章的功劳。“王侯将相宁有种乎”但真正当皇帝的只有一个人,王侯将相,人也不多。目标定得高些对于喜欢挑战的人来说有好处,但对于大多数普通人来说,反而比较容易灰心沮丧,很容易就放弃了。
  回过头来说,李嘉诚比你有钱大致50万倍,他比你更快乐么?或许。有没有比你快乐50万倍,一定没有。他比你最多也就快乐一两倍,甚至有可能还不如你快乐。寻找自己想要的东西不是和别人比赛,比谁要得更多更高,比谁的目标更远大。虽然成为李嘉诚这个目标很宏大,但你并不见得会从这个目标以及追求目标的过程当中获得快乐,而且基本上你也做不到。你必须听听你内心的声音,寻找真正能够使你获得快乐的东西,那才是你想要的东西。
  你想要的东西,或者我们把它称之为目标,目标其实并没有高低之分,你不需要因为自己的目标没有别人远大而不好意思,达到自己的目标其实就是成功,成功有大有小,快乐却是一样的。我们追逐成功,其实追逐的是成功带来的快乐,而非成功本身。职业生涯的道路上,我们常常会被攀比的心态蒙住眼睛,忘记了追求的究竟是什么,忘记了是什么能使我们更快乐。
  社会上一夜暴富的新闻很多,这些消息,总会在我们的心里面掀起很多涟漪,涟漪多了就变成惊涛骇浪,心里的惊涛骇浪除了打翻承载你目标的小船,并不会使得你也一夜暴富。“只见贼吃肉,不见贼挨揍。”我们这些普通人既没有当贼的勇气,又缺乏当贼的狠辣绝决,虽然羡慕吃肉,却更害怕挨揍,偶尔看到几个没挨揍的贼就按奈不住,或者心思活动,或者大感不公,真要叫去做贼,却也不敢。
我还是过普通人的日子,要普通人的快乐,至少,晚上睡得着觉。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ipromiseu/archive/2009/11/03/4764444.aspx

posted @ 2010-08-19 22:26 海王 阅读(72) 评论(0) 编辑
 
http://www.quickcamteam.net/software/linux/v4l2-software/luvcview/
posted @ 2010-08-19 13:28 海王 阅读(215) 评论(0) 编辑
 

http://www.linux-cn.com/html/linux/kernel/20070412/1886.shtml

  http://linux.ccidnet.com/art/741/20061116/952655_1.html

Linux内核2.4版中去掉了老版本内核中的静态定时器机制,而只留下动态定时器。相应地在timer_bh()函数中也不再通

过run_old_timers()函数来运行老式的静态定时器。动态定时器与静态定时器这二个概念是相对于Linux内核定时器机

制的可扩展功能而言的,动态定时器是指内核的定时器队列是可以动态变化的,然而就定时器本身而言,二者并无本质的

区别。考虑到静态定时器机制的能力有限,因此Linux内核2.4版中完全去掉了以前的静态定时器机制。

7.6.1 Linux内核对定时器的描述

Linux在include/linux/timer.h头文件中定义了数据结构timer_list来描述一个内核定时器:

struct timer_list { 
struct list_head list; 
unsigned long expires; 
unsigned long data; 
void (*function)(unsigned long); 
};

各数据成员的含义如下:

(1)双向链表元素list:用来将多个定时器连接成一条双向循环队列。

(2)expires:指定定时器到期的时间,这个时间被表示成自系统启动以来的时钟滴答计数(也即时钟节拍数)。当一个

定时器的expires值小于或等于jiffies变量时,我们就说这个定时器已经超时或到期了。在初始化一个定时器后,通常

把它的expires域设置成当前expires变量的当前值加上某个时间间隔值(以时钟滴答次数计)。

(3)函数指针function:指向一个可执行函数。当定时器到期时,内核就执行function所指定的函数。而data域则

被内核用作function函数的调用参数。

内核函数init_timer()用来初始化一个定时器。实际上,这个初始化函数仅仅将结构中的list成员初始化为空。如下所示(include/linux/timer.h):

static inline void init_timer(struct timer_list * timer) 
{ 
timer->list.next = timer->list.prev = NULL; 
}

由于定时器通常被连接在一个双向循环队列中等待执行(此时我们说定时器处于pending状态)。因此函数time_pending()

就可以用list成员是否为空来判断一个定时器是否处于pending状态。如下所示

(include/linux/timer.h): 
static inline int timer_pending (const struct timer_list * timer) 
{ 
return timer->list.next != NULL; 
}

时间比较操作

在定时器应用中经常需要比较两个时间值,以确定timer是否超时,所以Linux内核在timer.h头文件中定义了4个时间

关系比较操作宏。这里我们说时刻a在时刻b之后,就意味着时间值a≥b。Linux强烈推荐用户使用它所定义的下列4个

时间比较操作宏(include/linux/timer.h):

#define time_after(a,b) ((long)(b) - (long)(a) < 0) 
#define time_before(a,b) time_after(b,a) 

#define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0) 
#define time_before_eq(a,b) time_after_eq(b,a)
 
 

7.6.2 动态内核定时器机制的原理

Linux是怎样为其内核定时器机制提供动态扩展能力的呢?其关键就在于“定时器向量”的概念。所谓“定时器向量”

就是指这样一条双向循环定时器队列(对列中的每一个元素都是一个timer_list结构):对列中的所有定时器都在同

一个时刻到期,也即对列中的每一个timer_list结构都具有相同的expires值。显然,可以用一个timer_list结构类型

的指针来表示一个定时器向量。

显然,定时器expires成员的值与jiffies变量的差值决定了一个定时器将在多长时间后到期。在32位系统中,这个时间

差值的最大值应该是0xffffffff。因此如果是基于“定时器向量”基本定义,内核将至少要维护0xffffffff个timer_list

结构类型的指针,这显然是不现实的。

另一方面,从内核本身这个角度看,它所关心的定时器显然不是那些已经过期而被执行过的定时器(这些定时器完全可

以被丢弃),也不是那些要经过很长时间才会到期的定时器,而是那些当前已经到期或者马上就要到期的定时器

(注意!时间间隔是以滴答次数为计数单位的)。

基于上述考虑,并假定一个定时器要经过interval个时钟滴答后才到期(interval=expires-jiffies),则Linux采用

了下列思想来实现其动态内核定时器机制:对于那些0≤interval≤255的定时器,Linux严格按照定时器向量的基本

语义来组织这些定时器,也即Linux内核最关心那些在接下来的255个时钟节拍内就要到期的定时器,因此将它们按

照各自不同的expires值组织成256个定时器向量。而对于那些256≤interval≤0xffffffff的定时器,由于他们离到

期还有一段时间,因此内核并不关心他们,而是将它们以一种扩展的定时器向量语义(或称为“松散的定时器向量语义”)

进行组织。所谓“松散的定时器向量语义”就是指:各定时器的expires值可以互不相同的一个定时器队列。

具体的组织方案可以分为两大部分:

(1)对于内核最关心的、interval值在[0,255]之间的前256个定时器向量,内核是这样组织它们的:这256个定

时器向量被组织在一起组成一个定时器向量数组,并作为数据结构timer_vec_root的一部分,该数据结构定义

在kernel/timer.c文件中,如下述代码段所示:

/* 
* Event timer code 
*/ 
#define TVN_BITS 6 
#define TVR_BITS 8 
#define TVN_SIZE (1 << TVN_BITS) 
#define TVR_SIZE (1 << TVR_BITS) 
#define TVN_MASK (TVN_SIZE - 1) 
#define TVR_MASK (TVR_SIZE - 1) 

struct timer_vec { 
int index; 
struct list_head vec[TVN_SIZE]; 
}; 

struct timer_vec_root { 
int index; 
struct list_head vec[TVR_SIZE]; 
}; 

static struct timer_vec tv5; 
static struct timer_vec tv4; 
static struct timer_vec tv3; 
static struct timer_vec tv2; 
static struct timer_vec_root tv1; 

static struct timer_vec * const tvecs[] = { 
(struct timer_vec *)&tv1, &tv2, &tv3, &tv4, &tv5 
}; 
#define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))
 

基于数据结构timer_vec_root,Linux定义了一个全局变量tv1,以表示内核所关心的前256个定时器向量。这样

内核在处理是否有到期定时器时,它就只从定时器向量数组tv1.vec[256]中的某个定时器向量内进行扫描。

而tv1的index字段则指定当前正在扫描定时器向量数组tv1.vec[256]中的哪一个定时器向量,也即该数组的索引,

其初值为0,最大值为255(以256为模)。每个时钟节拍时index字段都会加1。显然,index字段所指定的定时器

向量tv1.vec[index]中包含了当前时钟节拍内已经到期的所有动态定时器。而定时器向量tv1.vec[index+k]则

包含了接下来第k个时钟节拍时刻将到期的所有动态定时器。当index值又重新变为0时,就意味着内核已经扫描

了tv1变量中的所有256个定时器向量。在这种情况下就必须将那些以松散定时器向量语义来组织的定时器向量补充到tv1中来。

(2)而对于内核不关心的、interval值在[0xff,0xffffffff]之间的定时器,它们的到期紧迫程度也随其interval值

的不同而不同。显然interval值越小,定时器紧迫程度也越高。因此在将它们以松散定时器向量进行组织时也应该区别

对待。通常,定时器的interval值越小,它所处的定时器向量的松散度也就越低(也即向量中的各定时器的expires值

相差越小);而interval值越大,它所处的定时器向量的松散度也就越大(也即向量中的各定时器的expires值相差越大)。

内核规定,对于那些满足条件:0x100≤interval≤0x3fff的定时器,只要表达式(interval>>8)具有相同值的定时

器都将被组织在同一个松散定时器向量中。因此,为组织所有满足条件0x100≤interval≤0x3fff的定时器,就需

要26=64个松散定时器向量。同样地,为方便起见,这64个松散定时器向量也放在一起形成数组,并作为数据结

构timer_vec的一部分。基于数据结构timer_vec,Linux定义了全局变量tv2,来表示这64条松散定时器向量。如

上述代码段所示。

对于那些满足条件0x4000≤interval≤0xfffff的定时器,只要表达式(interval>>8+6)的值相同的定时器都将被

放在同一个松散定时器向量中。同样,要组织所有满足条件0x4000≤interval≤0xfffff的定时器,也需要26=64个

松散定时器向量。类似地,这64个松散定时器向量也可以用一个timer_vec结构来描述,相应地Linux定义了tv3全

局变量来表示这64个松散定时器向量。

对于那些满足条件0x100000≤interval≤0x3ffffff的定时器,只要表达式(interval>>8+6+6)的值相同的定时

器都将被放在同一个松散定时器向量中。同样,要组织所有满足条件0x100000≤interval≤0x3ffffff的定时器,也

需要26=64个松散定时器向量。类似地,这64个松散定时器向量也可以用一个timer_vec结构来描述,相应地Linux

定义了tv4全局变量来表示这64个松散定时器向量。

对于那些满足条件0x4000000≤interval≤0xffffffff的定时器,只要表达式(interval>>8+6+6+6)的值相同的

定时器都将被放在同一个松散定时器向量中。同样,要组织所有满足条件0x4000000≤interval≤0xffffffff的定时器,

也需要26=64个松散定时器向量。类似地,这64个松散定时器向量也可以用一个timer_vec结构来描述,相应地Linux定

义了tv5全局变量来表示这64个松散定时器向量。

最后,为了引用方便,Linux定义了一个指针数组tvecs[],来分别指向tv1、tv2、…、tv5结构变量。如上述代码所示。

7.6.3 内核动态定时器机制的实现

在内核动态定时器机制的实现中,有三个操作时非常重要的:

(1)将一个定时器插入到它应该所处的定时器向量中。

(2)定时器的迁移,也即将一个定时器从它原来所处的定时器向量迁移到另一个定时器向量中。

(3)扫描并执行当前已经到期的定时器。

7.6.3.1 动态定时器机制的初始化

函数init_timervecs()实现对动态定时器机制的初始化。该函数仅被sched_init()初始化例程所调用。动态定时

器机制初始化过程的主要任务就是将tv1、tv2、…、tv5这5个结构变量中的定时器向量指针数组vec[]初始化

为NULL。如下所示(kernel/timer.c):

void init_timervecs (void) 
{ 
int i; 

for (i = 0; i < TVN_SIZE; i++) { 
INIT_LIST_HEAD(tv5.vec + i); 
INIT_LIST_HEAD(tv4.vec + i); 
INIT_LIST_HEAD(tv3.vec + i); 
INIT_LIST_HEAD(tv2.vec + i); 
} 
for (i = 0; i < TVR_SIZE; i++) 
INIT_LIST_HEAD(tv1.vec + i); 
}

上述函数中的宏TVN_SIZE是指timer_vec结构类型中的定时器向量指针数组vec[]的大小,值为64。

宏TVR_SIZE是指timer_vec_root结构类型中的定时器向量数组vec[]的大小,值为256。

 

7.6.3.2 动态定时器的时钟滴答基准timer_jiffies

由于动态定时器是在时钟中断的Bottom Half中被执行的,而从TIMER_BH向量被激活到其timer_bh()函数真正

执行这段时间内可能会有几次时钟中断发生。因此内核必须记住上一次运行定时器机制是什么时候,也即内核必须

保存上一次运行定时器机制时的jiffies值。为此,Linux在kernel/timer.c文件中定义了全局变量timer_jiffies来表

示上一次运行定时器机制时的jiffies值。该变量的定义如下所示:

static unsigned long timer_jiffies;

7.6.3.3 对内核动态定时器链表的保护

由于内核动态定时器链表是一种系统全局共享资源,为了实现对它的互斥访问,Linux定义了专门的自旋锁timerlist_lock

来保护。任何想要访问动态定时器链表的代码段都首先必须先持有该自旋锁,并且在访问结束后释放该自旋锁。其定义

如下(kernel/timer.c):

/* Initialize both explicitly - let's try to have them in the same cache line */ 
spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;

 

7.6.3.4 将一个定时器插入到链表中

函 数add_timer()用来将参数timer指针所指向的定时器插入到一个合适的定时器链表中。它首先调用timer_pending()函

数判断所指 定的定时器是否已经位于在某个定时器向量中等待执行。如果是,则不进行任何操作,只是打印一条内核告警

信息就返回了;如果不是,则调用 internal_add_timer()函数完成实际的插入操作。其源码如下(kernel/timer.c):

void add_timer(struct timer_list *timer) { unsigned long flags; spin_lock_irqsave(&timerlist_lock, flags); if (timer_pending(timer)) goto bug; internal_add_timer(timer); spin_unlock_irqrestore(&timerlist_lock, flags); return; bug: spin_unlock_irqrestore(&timerlist_lock, flags); printk("bug: kernel timer added twice at %p.\n", __builtin_return_address(0)); }

函数internal_add_timer()用于将一个不处于任何定时器向量中的定时器插入到它应该所处的定时器向量中去(根据定

时器的expires值来决定)。如下所示(kernel/timer.c):

static inline void internal_add_timer(struct timer_list *timer) { /* * must be cli-ed when calling this */ unsigned long expires = timer->expires; unsigned long idx = expires - timer_jiffies; struct list_head * vec; if (idx < TVR_SIZE) { int i = expires & TVR_MASK; vec = tv1.vec + i; } else if (idx < 1 << (TVR_BITS + TVN_BITS)) { int i = (expires >> TVR_BITS) & TVN_MASK; vec = tv2.vec + i; } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) { int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK; vec = tv3.vec + i; } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) { int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK; vec = tv4.vec + i; } else if ((signed long) idx < 0) { /* can happen if you add a timer with expires == jiffies, * or you set a timer to go off in the past */ vec = tv1.vec + tv1.index; } else if (idx <= 0xffffffffUL) { int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; vec = tv5.vec + i; } else { /* Can only get here on architectures with 64-bit jiffies */ INIT_LIST_HEAD(&timer->list); return; } /* * Timers are FIFO! */ list_add(&timer->list, vec->prev); }

对该函数的注释如下:

(1)首先,计算定时器的expires值与timer_jiffies的插值(注意!这里应该使用动态定时器自己的时间基准),这个差值

就表示这个定时器相对于上一次运行定时器机制的那个时刻还需要多长时间间隔才到期。局部变量idx保存这个差值。

(2)根据idx的值确定这个定时器应被插入到哪一个定时器向量中。其具体的确定方法我们在7.6.2节已经说过了,这里不再

详述。最后,定时器向量的头部指针vec表示这个定时器应该所处的定时器向量链表头部。

(3)最后,调用list_add()函数将定时器插入到vec指针所指向的定时器队列的尾部。

7.6.3.5 修改一个定时器的expires值

当一个定时器已经被插入到内核动态定时器链表中后,我们还可以修改该定时器的expires值。函数mod_timer()实现这一点。

如下所示(kernel/timer.c):

int mod_timer(struct timer_list *timer, unsigned long expires) { int ret; unsigned long flags; spin_lock_irqsave(&timerlist_lock, flags); timer->expires = expires; ret = detach_timer(timer); internal_add_timer(timer); spin_unlock_irqrestore(&timerlist_lock, flags); return ret; }

该函数首先根据参数expires值更新定时器的expires成员。然后调用detach_timer()函数将该定时器从它原来所属的链表

中删除。最后调用internal_add_timer()函数将该定时器根据它新的expires值重新插入到相应的链表中。

函 数detach_timer()首先调用timer_pending()来判断指定的定时器是否已经处于某个链表中,如果定时器原来就不处于任

何链表中, 则detach_timer()函数什么也不做,直接返回0值,表示失败。否则,就调用list_del()函数将定时器从它原来所

处的链表中摘除。如下 所示(kernel/timer.c):

static inline int detach_timer (struct timer_list *timer) { if (!timer_pending(timer)) return 0; list_del(&timer->list); return 1; }

7.6.3.6 删除一个定时器

函数del_timer()用来将一个定时器从相应的内核定时器队列中删除。该函数实际上是对detach_timer()函数的高层封装。

如下所示(kernel/timer.c):

 

int del_timer(struct timer_list * timer) 
{ 
int ret; 
unsigned long flags; 

spin_lock_irqsave(&timerlist_lock, flags); 
ret = detach_timer(timer); 
timer->list.next = timer->list.prev = NULL; 
spin_unlock_irqrestore(&timerlist_lock, flags); 
return ret; 
}

 

7.6.3.7 定时器迁移操作

由于一个定时器的interval值会随着时间的不断流逝(即jiffies值的不断增大)而不断变小,因此那些原本到期紧迫程度较

低的定时器会随着jiffies值的不断增大而成为既把马上到期的定时器。比如定时器向量tv2.vec[0]中的定时器在经过256个

时钟滴答后会成为未来256个时钟滴答内会到期的定时器。因此,定时器在内核动态定时器链表中的位置也应相应地随着改

变。改变的规则是:当tv1.index重新变为0时(意味着tv1中的256个定时器向量都已被内核扫描一遍了,从而使tv1中的

256个定时器向量变为空),则用tv2.vec[index]定时器向量中的定时器去填充tv1,同时使tv2.index加1(它以64为模)。

当tv2.index重新变为0(意味着tv2中的64个定时器向量都已经被全部填充到tv1中去了,从而使得tv2变为空),则

用tv3.vec[index]定时器向量中的定时器去填充tv2。如此一直类推下去,直到tv5。

函数cascade_timers()完成这种定时器迁移操作,该函数只有一个timer_vec结构类型指针的参数tv。这个函数把把定时

器向量tv->vec[tv->index]中的所有定时器重新填充到上一层定时器向量中去。如下所示(kernel/timer.c):

static inline void cascade_timers(struct timer_vec *tv) 
{ 
/* cascade all the timers from tv up one level */ 
struct list_head *head, *curr, *next; 

head = tv->vec + tv->index; 
curr = head->next; 
/* 
* We are removing _all_ timers from the list, so we don't have to 
* detach them individually, just clear the list afterwards. 
*/ 
while (curr != head) { 
struct timer_list *tmp; 

tmp = list_entry(curr, struct timer_list, list); 
next = curr->next; 
list_del(curr); // not needed 
internal_add_timer(tmp); 
curr = next; 
} 
INIT_LIST_HEAD(head); 
tv->index = (tv->index + 1) & TVN_MASK; 
}

对该函数的注释如下:

(1)首先,用指针head指向定时器头部向量头部的list_head结构。指针curr指向定时器向量中的第一个定时器。

(2)然后,用一个while{}循环来遍历定时器向量tv->vec[tv->index]。由于定时器向量是一个双向循环队列,因此循环

的终止条件是curr=head。对于每一个被扫描的定时器,循环体都先调用list_del()函数把当前定时器从链表中摘除,然后调

用internal_add_timer()函数重新确定该定时器应该被放到哪个定时器向量中去。

(3)当从while{}循环退出后,定时器向量tv->vec[tv->index]中所有的定时器都已被迁移到其它地方(到它们该呆的地

方:-),因此它本身就成为一个空队列。这里我们显示地调用INIT_LIST_HEAD()宏来把定时器向量的表头结构初始化为空。

(4)最后,把tv->index值加1,当然它是以64为模。 以上文章内容均为网络转载或者本站会员原创,"Linux-cn.com不对

文章内容做任何保证。

 

7.6.4.8 扫描并执行当前已经到期的定时器

函数run_timer_list()完成这个功能。如前所述,该函数是被timer_bh()函数所调用的,因此内核定时器是在时钟中

断的Bottom Half中被执行的。记住这一点非常重要。全局变量timer_jiffies表示了内核上一次执行run_timer_list()函

数的时间,因此jiffies与timer_jiffies的差值就表示了自从上一次处理定时器以来,期间一共发生了多少次时钟中断,显

然run_timer_list()函数必须为期间所发生的每一次时钟中断补上定时器服务。该函数的源码如下(kernel/timer.c):

static inline void run_timer_list(void) 
{ 
spin_lock_irq(&timerlist_lock); 
while ((long)(jiffies - timer_jiffies) >= 0) { 
struct list_head *head, *curr; 
if (!tv1.index) { 
int n = 1; 
do { 
cascade_timers(tvecs[n]); 
} while (tvecs[n]->index == 1 && ++n < NOOF_TVECS); 
} 
repeat: 
head = tv1.vec + tv1.index; 
curr = head->next; 
if (curr != head) { 
struct timer_list *timer; 
void (*fn)(unsigned long); 
unsigned long data; 

timer = list_entry(curr, struct timer_list, list); 
fn = timer->function; 
data= timer->data; 

detach_timer(timer); 
timer->list.next = timer->list.prev = NULL; 
timer_enter(timer); 
spin_unlock_irq(&timerlist_lock); 
fn(data); 
spin_lock_irq(&timerlist_lock); 
timer_exit(); 
goto repeat; 
} 
++timer_jiffies; 
tv1.index = (tv1.index + 1) & TVR_MASK; 
} 
spin_unlock_irq(&timerlist_lock); 
}

函数run_timer_list()的执行过程主要就是用一个大while{}循环来为时钟中断执行定时器服务,每一次循环服务一次时钟

中断。因此一共要执行(jiffies-timer_jiffies+1)次循环。循环体所执行的服务步骤如下:

(1)首先,判断tv1.index是否为0,如果为0则需要从tv2中补充定时器到tv1中来。但tv2也可能为空而需要从tv3中补充

定时器,因此用一个do{}while循环来调用cascade_timer()函数来依次视需要从tv2中补充tv1,从tv3中补充tv2、…、

从tv5中补充tv4。显然如果tvi.index=0(2≤i≤5),则对于tvi执行cascade_timers()函数后,tvi.index肯定为1。

反过来讲,如果对tvi执行过cascade_timers()函数后tvi.index不等于1,那么可以肯定在未对tvi执行cascade_timers()函

数之前,tvi.index值肯定不为0,因此这时tvi不需要从tv(i+1)中补充定时器,这时就可以终止do{}while循环。

(2)接下来,就要执行定时器向量tv1.vec[tv1.index]中的所有到期定时器。因此这里用一个goto repeat循环从头到尾

依次扫描整个定时器对列。由于在执行定时器的关联函数时并不需要关CPU中断,所以在用detach_timer()函数把当前定时

器从对列中摘除后,就可以调用spin_unlock_irq()函数进行解锁和开中断,然后在执行完当前定时器的关联函数后重新用

spin_lock_irq()函数加锁和关中断。

(3)当执行完定时器向量tv1.vec[tv1.index]中的所有到期定时器后,tv1.vec[tv1.index]应该是个空队列。至此这一次

定时器服务也就宣告结束。

(4)最后,把timer_jiffies值加1,把tv1.index值加1,当然它的模是256。然后,回到while循环开始下一次定时器服务。


 

 

 

 

 

 


 

posted @ 2010-08-19 12:23 海王 阅读(2685) 评论(0) 编辑
 

http://blog.chinaunix.net/u/26710/showart_387765.html

0 前言
    在Linux下驱动USB摄像头一直不是容易的事情,尽管其内核中就集成了对0V511系列摄像头的支持,开源驱动spca5xx/gspca也提供了对大部分主流摄像头的支持,但还是无法涵盖所有品牌的各种型号的摄像头,尤其是对于国内的中低端用户,很难找到直接可用的Linux下的驱动。
    本文简单介绍了gspca驱动程序、spcagui和spcaview等测试程序的安装过程,并以在gspca中添加对Logitech QuickCam Easy/Cool(快看灵讯版)摄像头的支持为例,给出了在gspca驱动程序中添加新的摄像头支持的一般方法。

1 安装gspca驱动程序
    gspca用于2.6.17以上的内核版本,以前的版本使用spca5xx驱动程序。gspca可直接支持的摄像头列表可见http://mxhaard.free.fr/spca5xx.html。
    (1)安装内核头文件
#uname -r
2.6.20-1.2962.fc6
#arch
i686
#wget http://fedora.fastbull.org/updates/testing/6/i386/kernel-
devel-2.6.20-1.2962.fc6.i686.rpm
#rpm -ivh kernel-devel-2.6.20-1.2962.fc6.i686.rpm
    这样,内核头文件被安装到/usr/src/kernels/2.6.20-1.2962.fc6-i686目录下。
    (2)安装gspca驱动:
#wget http://mxhaard.free.fr/spca50x/Download/gspcav1-
20070508.tar.gz
#tar xfv gspcav1-20070508.tar.gz
#cd gspcav1-20070508
#./gspca_build
    gspca_build是一个自动编译、安装、加载驱动模块的腳本。可以使用命令“depmod -ae”来检查内核模块的依赖关系是否冲突。
    注意,安装好驱动并加载gspca.ko模块后,一般会有/dev/video和/dev/video0等设备文件的存在,否则可能是驱动程序对本机的摄像头的支持有问题。另外,要正常使用摄像头,内核中应有video for linux的支持(Fedora内核一般是默认支持)。
    (3)安装spcagui、spcaview等摄像头测试程序
    实际上,只要正确安装好驱动之后,就可以使用"应用程序->Internet->Kopete"或gnome-netmeeting等程序来测试摄像头是否能正常工作了。当然也可以使用spcagui、spcaview等专门的摄像头工具软件。
    要安装spcagui或spcaview,必须先安装SDL、SDL-devel、SDL_image和SDL_image-devel软件包。然后直接make并make install即可。

2 gspca不能直接支持Logitech QuickCam Easy/Cool(快看灵讯版,046d:08af)
    Logitech的摄像头有个“特点”,一个英文名有好几个中文名,例如快看灵讯版和快看酷讯版,包装盒上都写的是Logitech QuickCam Cool,由于在gspca的摄像头支持列表中看到了Logitech QuickCam Cool,于是买了个灵讯版。
    首先在Windows上试验摄像头效果,插入USB口,显示设备为Logitech QuickCam Easy/Cool,就感觉情况不妙,一看Vendor ID:Product ID是046d:08af,果然不在gspca的摄像头支持列表内。不管怎么样,先到Fedora下试试再说。
#lsusb
Bus 002 Device 001: ID 0000:0000 
Bus 002 Device 003: ID 046d:08af Logitech, Inc.
Bus 001 Device 001: ID 0000:0000 
Bus 004 Device 001: ID 0000:0000 
Bus 003 Device 001: ID 0000:0000
    可见设备ID的确是046d:08af。加载gspca驱动模块后,运行spcagui或者spcaview,提示“No such file or directory.”
    “ls /dev/video*”发现没有任何相应的设备文件,于是手动建立:
#mknod /dev/video0 c 81 0
#ln -s /dev/video0 /dev/video
    之后再运行spcagui或者spcaview,提示“Device not found.”
    在Google上搜了两个晚上,还是没能找到解决问题的办法。看来唯一能找到问题所在并加以解决的办法就是从gspca驱动程序的源代码入手了。

3 使gspca驱动程序支持Logitech QuickCam Easy/Cool
    (1)gspca驱动程序结构简析
    gspca驱动程序的核心代码是gspca_core.c,包括了设备注册、注销、各种操作方法集(定义了所支持的摄像头设备列表,设备检测和初始化,设备打开、参数设置、关闭等各种操作函数)。
    gspca.h是一个核心头文件,它的主要内容有:
    a)定义所支持的Vendor ID号,例如:
#define VENDOR_LOGITECH 0x046d
    b)为所支持的DSP桥接控制芯片型号进行编号,例如:
#define BRIDGE_ZC3XX 12
    c)为所支持的CMOS/CCD图像传感器型号进行编号,例如:
#define SENSOR_HV7131B  2
#define SENSOR_HDCS2020 9
#define SENSOR_HV7131C 12
#define SENSOR_HV7131R 15
#define SENSOR_PAS202 19
#define SENSOR_TAS5130C_VF0250 22
    另外,它还定义了图像格式相关的常量和数据结构(如图像分辨率,色彩空间,调色板等),帧数据结构,摄像头操作方法集等。
    Vimicro,Sonix,PixArt,Sunplus等文件夹中定义了各传感器相关的头文件。
    decoder文件夹中包含了对各种图像格式进行编解码的源代码。

    结论:要驱动一个摄像头,首先要知道它的DSP芯片和CMOS芯片型号。如果摄像头的Vendor ID,DSP芯片,image sensor不在其中,则要定义DSP和sensor芯片的相应头文件,并在gspca.h中添加相应的设备信息,还要把摄像头加入到gspca_core.c的摄像头设备列表中。

    (2)与Logitech QuickCam Easy/Cool相近的摄像头信息列表
Camera Type
Product ID
Bridge DSP
Sensor
Comments(sensor in driver code)
QC IM
08a0
zc030x
HDCS2020
TAS5130C(08a0/a1/a3,08d9/da)
QC IM
08a6
zc030x
HV7131R
HV7131C (08a6/ad, 08d7)
NoteBook Deluxe
08a9
zc0302
HV7131B
HDCS2020 (08a2/a9/ae, 08d8)
QC Image
08a7
zc030x
PAS202

QC for Notebook
08ae
zc030x
PAS202
HDCS2020
QC Cool
08ac
zc030x
PAS202
HV7131B
Communicate STX
08ad
zc0302
TAS5130C
HV7131C
Communicate STX
08d7
vc0302/zc0302
TAS5130C
HV7131C
QC IM/Connect
08d9
zc030x
TAS5130C

QC Messenger
08da
zc030x
TAS5130C

NoteBook Deluxe
08d8
vc0302/zc0302
TAS5130C

QC Easy/Cool
08af
?(zc030x)
?
(HV7131C/HV7131B/TAS5130C/HDCS2020)

    上面是Logitech摄像头产品中与Logitech QuickCam Easy/Cool相近的产品(从Product ID,摄像头英文名,产品价格等判断),摘自http://mxhaard.free.fr/spca5xx.html,其中最后一列的注释是gspca_core.c源文件中给相应型号摄像头定义的CMOS芯片型号,与网页上的列表并不完全一致,我们以驱动程序中定义的为准。
    列出上面的表,主要是为了要推断出Logitech QuickCam Easy/Cool的DSP芯片型号和CMOS传感器型号。从上表可以发现,所有的摄像头都使用了zc030x(包括zc0302)作为DSP控制芯片,因此可以断定,Easy/Cool也使用了这一系列的DSP芯片,在驱动程序中用BRIDGE_ZC3XX表示。而CMOS芯片也无非是HV7131C/HV7131B/TAS5130C/HDCS2020中的一种,我们可以逐一试验。

    (3)在gspca_core.c中添加Logitech QuickCam Easy/Cool相关信息
    由于Logitech QuickCam Easy/Cool的Vendor、DSP型号、CMOS传感器型号在gspca.h中均有定义,也有相关的芯片头文件,因此,只需改动gspca_core.c,把Easy/Cool摄像头的信息加入到其中即可。
以下蓝色部分是添加的相关内容。
    在gspca_core.c中有一个Camera型号列表,如下: enum {
    UnknownCamera = 0, // 0
    IntelPCCameraPro,
    IntelCreateAndShare,
    ......
    PhilipsDMVC1300K,
    LogitechQC_EasyCool, // added by aaron
    LastCamera
};
static struct cam_list clist[] = {
    {UnknownCamera, "Unknown"},
    {IntelPCCameraPro, "Intel PC Camera Pro"},
    {IntelCreateAndShare, "Intel Create and Share"},
    ......
    {PhilipsDMVC1300K,"Philips DMVC 1300K"},
    {LogitechQC_EasyCool,"Logitech QuickCam Easy_Cool"},     //added by aaron
    {-1, NULL}
};
static __devinitdata struct usb_device_id device_table[] = {
    {USB_DEVICE(0x0733, 0x0430)}, /*Intel PC Camera Pro*/
    {USB_DEVICE(0x0733, 0x0401)}, /* Intel Create and Share */
    ......
    {USB_DEVICE(0x0471, 0x0322)}, /* Philips DMVC1300K */
    {USB_DEVICE(0x046d, 0x08af)},
    /* Logitech QuickCam Easy_Cool, added by aaron */
    {USB_DEVICE(0x0000, 0x0000)}, /* MystFromOri Unknow Camera */
    {} /* Terminating entry */
};

static int
gspca_attach_bridge(struct usb_spca50x *spca50x)
{
    /* set the default epadr */
    spca50x->epadr =1;
    switch (spca50x->bridge) {
    ......
    case BRIDGE_ZC3XX:
        spca50x->cameratype = JPGH;
        info("USB GSPCA camera found.(ZC3XX) ");
        memcpy(&spca50x->funct, &fzc3xx, sizeof (struct cam_operation));
        break;
    ...... //other DSP bridges
    default:
        return -ENODEV;
    }
    return 0;
}
    检测摄像头型号: static int
spcaDetectCamera(struct usb_spca50x *spca50x)
{
    struct usb_device *dev = spca50x->dev;
    __u8 fw = 0;
    __u16 vendor;
    __u16 product;
    /* Is it a recognised camera ? */
    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
        vendor = le16_to_cpu(dev->descriptor.idVendor);
        product = le16_to_cpu(dev->descriptor.idProduct);
    #else
        vendor = dev->descriptor.idVendor;
        product = dev->descriptor.idProduct;
    #endif
    switch (vendor) {
    case 0x046d: /* Logitech Labtec */
        switch (product) {
        case 0x08af: //added by aaron
            spca50x->desc = LogitechQC_EasyCool;
            spca50x->bridge = BRIDGE_ZC3XX;
            spca50x->sensor = SENSOR_HV7131B;
            break;
        ......
        case 0x08a0:
            spca50x->desc = QCim;
            spca50x->bridge = BRIDGE_ZC3XX;
            spca50x->sensor = SENSOR_TAS5130CXX;
            break;
        case 0x08a1:
            spca50x->desc = QCimA1;
            spca50x->bridge = BRIDGE_ZC3XX;
            spca50x->sensor = SENSOR_TAS5130CXX;
            break;
        case 0x08a2: // zc302 chips
            spca50x->desc = LabtecPro;
            spca50x->bridge = BRIDGE_ZC3XX;
            spca50x->sensor = SENSOR_HDCS2020;
            break;
        case 0x08a3:
            spca50x->desc = QCchat;
            spca50x->bridge = BRIDGE_ZC3XX;
            spca50x->sensor = SENSOR_TAS5130CXX;
            break;
        case 0x08a6:
            spca50x->desc = LogitechQCim;
            spca50x->bridge = BRIDGE_ZC3XX;
            spca50x->sensor = SENSOR_HV7131C;
            break;
        case 0x08a7:
            spca50x->desc = LogitechQCImage;
            spca50x->bridge = BRIDGE_ZC3XX;
            spca50x->sensor = SENSOR_PAS202;
            break;
        case 0x08d8:
        case 0x08a9:
            spca50x->desc = LogitechNotebookDeluxe;
            spca50x->bridge = BRIDGE_ZC3XX;
            spca50x->sensor = SENSOR_HDCS2020;
            break;
        case 0x08ae:
            spca50x->desc = QuickCamNB;
            spca50x->bridge = BRIDGE_ZC3XX;
            spca50x->sensor = SENSOR_HDCS2020;
            break;
        case 0x08ac:
            spca50x->desc = LogitechQCCool;
            spca50x->bridge = BRIDGE_ZC3XX;
            spca50x->sensor = SENSOR_HV7131B;
            break;
        ......
        default:
            goto error;
        };
        break;

    ...... //other vendors

    return gspca_attach_bridge(spca50x);
    error:
    return -ENODEV; //no camera match
}

static int
spca5xx_probe(struct usb_interface *intf, const struct usb_device_id *id){
    ......
    if ((err_probe = spcaDetectCamera(spca50x)) < 0) {
        err(" Devices not found !! ");
        goto error;
    }
    ......
}
    到此,我们对gspca驱动程序的扩展就算完成了。在函数spcaDetectCamera()中的switch结构中,将我们的摄像头放到第一个case,是为了在探测摄像头时第一个就找到我们的摄像头,提高检测速度。
    需要指出两点,一是在函数spcaDetectCamera()中,我们假定Logitech QC Easy/Cool的CMOS传感器型号为SENSOR_HV7131B,这需要在后续的实验中进行验证;二是spca5xx_probe()函数中,红色代码部分,实际上调用了spcaDetectCamera()函数来探测摄像头,如果出错则报错" Devices not found !! "并退出,由于之前gspca中没有Easy/Cool摄像头的信息,因此,之前即使自己创建了/dev/video0等设备文件,还是会报错“找不到设备”。

    (4)卸载旧的gspca驱动模块,安装新的gspca驱动模块 #rm -f /dev/video*    //删除旧的自己创建的设备节点
#modprobe -rv gspca
#make uninstall
#make clean

#./gspca_build

#ls /dev/video*
lrwxrwxrwx 1 root  root  6 09-22 21:44 /dev/video->video0
crw------- 1 aaronwong root 81, 0 09-22 21:42 /dev/video0
    可见,这次在加载gspca驱动模块后,自动生成了设备文件/dev/video0和/dev/video。
    (5)摄像头试用效果 $spcagui
SpcaGui version: 0.3.5 date: 18 September 2005
video device /dev/video0
Camera found: Logitech QuickCam Easy_Cool
VIDIOCGPICT brightnes=32768 hue=0 color=0 contrast=32768 whiteness=0depth=24 palette=4
Bridge found: ZC301-2
Unable to find a StreamId !!
StreamId: 6 Unknow Camera
try palette 15 depth 12
Available  palette 15
try palette 3 depth 16
Available  palette 3
try palette 4 depth 24
Available  palette 4
try palette 5 depth 32
Available  palette 5
probe size in
Available Resolutions width 640  heigth 480
Available Resolutions width 384  heigth 288
Available Resolutions width 352  heigth 288
Available Resolutions width 320  heigth 240
Available Resolutions width 192  heigth 144
Available Resolutions width 176  heigth 144
grabbing method default MMAP asked
VIDIOCGMBUF size 2457616  frames 2  offets[0]=0 offsets[1]=1228808
......
    截图如下:

    (6)修正CMOS芯片型号信息 #modprobe -v gspca
insmod /lib/modules/2.6.20-1.2962.fc6/kernel/drivers/media/video/v4l1-compat.ko
insmod /lib/modules/2.6.20-1.2962.fc6/kernel/drivers/media/video/v4l2-common.ko
insmod /lib/modules/2.6.20-1.2962.fc6/kernel/drivers/media/video/videodev.ko
insmod /lib/modules/2.6.20-1.2962.fc6/kernel/drivers/usb/media/gspca.ko

#dmesg | grep gspca
/home/aaronwong/webcam/driver/gspcav1-20070508/gspca_core.c: USB GSPCA camera found.(ZC3XX)
/home/aaronwong/webcam/driver/gspcav1-20070508/gspca_core.c: [spca5xx_probe:4109] Camera type JPEG
/home/aaronwong/webcam/driver/gspcav1-20070508/Vimicro/zc3xx.h: [zc3xx_config:515] Sensor ID:2
/home/aaronwong/webcam/driver/gspcav1-20070508/Vimicro/zc3xx.h: [zc3xx_config:597] Find Sensor HV7131R(c)
/home/aaronwong/webcam/driver/gspcav1-20070508/gspca_core.c: [spca5xx_getcapability:1218] maxw 640 maxh 480 minw 176 minh 144
usbcore: registered new interface driver gspca
/home/aaronwong/webcam/driver/gspcav1-20070508/gspca_core.c: gspca driver 01.00.18 registered
    注意红色标出的部分,即使在驱动程序中指定QuickCam Easy/Cool摄像头的CMOS SENSOR类型为SENSOR_HV7131B(或者是SENSOR_HDCS2020等其他类型),在加载gspca.ko模块时,找到的还是HV7131R(c),因此,QuickCam Easy/Cool摄像头的CMOS SENSOR类型应该就是SENSOR_HV7131R或SENSOR_HV7131C。
    在源程序gspca_core.c的spcaDetectCamera()函数的相应部分修改如下: case 0x08af: //added by aaron
            spca50x->desc = LogitechQC_EasyCool;
            spca50x->bridge = BRIDGE_ZC3XX;
            spca50x->sensor = SENSOR_HV7131R; 
                            //SENSOR_HV7131C;
            break; 

    卸载gspca驱动模块,再重新编译安装gspca驱动即可。

    由此也可知,在gspca摄像头驱动中最重要的是要正确识别DSP控制芯片的型号,而CMOS传感器的型号并不是必须的。所以,只要摄像头使用了gspca所支持的DSP控制芯片,就可以很容易地按照上面的方法,添加gspca对新的摄像头的支持。即使使用了别的DSP控制芯片,也可以利用gspca的程序架构,为新的DSP芯片添加头文件等信息,来扩展gspca对更多系列的USB摄像头的支持。
    不管你的摄像头是ANC奥尼,还是环宇飞扬,或是恋影双双,如果你发现它的DSP芯片是gspca所支持的,不妨都来一试,相信你的摄像头也不会让你失望。

本文来自: (www.91linux.com) 详细出处参考:http://www.91linux.com/html/article/media/20090517/16857.html

posted @ 2010-08-19 01:08 海王 阅读(825) 评论(0) 编辑
 

http://weijb0606.blog.163.com/blog/static/131286274201062610734604/

USB Camera driver

其实 问题主要出在:山寨所产摄像头 其驱动不易获得 等所致

解决步骤:

1. 取得摄像头型号 主要是硬件ID 的获取

通过硬件ID精确找到你要的驱动或寻求帮助。

什么是硬件ID呢?

硬件ID是电脑所有硬件的一个编号,所有设备都有如下编号:VEN_1106&DEV_3038,VEN代表硬件厂商,DEV代表产品编号。 USB设备会有如下编号:VID_045E&PID_0039,道理跟上面的是一样的。所有的测试软件都有可能会出错,只有硬件ID是最可靠的,各位只要确认下INF文件包含需要的硬件ID,就保证是可以用的。具体到摄像头,我们需要知道VID和PID。VID/PID是全球USB组织统一分配的代码,VID是代表厂家,PID 是代表产品型号,任何一个USB设备生产商必须注册此两个号码,且注册后不能修改,因此该代码可以作为判断的依据。

如何获得摄像头硬件ID

方法1:
最简单的方法是直接在设备管理器中查看。右键“我的电脑”---管理----“设备管理器”---“图像处理设备”选择任意一个摄像头设备双击,在“详细信息”一栏即可看到下面这个信息:

上面的那段代码表示的意思是:

其中VID_0C45代表松瀚,PID_62C0代表芯片288

方法2:

使用USBVIEW软件查询

下载地址:http://tools.mydrivers.com/soft/287.htm

下面是目前主流摄像头芯片厂家的代码,仅供参考:

VID(厂家代号)
PID(芯片代号)
厂家与芯片型号

VID_0C45
PID_62C0
台湾松瀚288,其中288与288P是同一个代号
USB2.0免驱

VID_0AC8
PID_303B
中星微301H,即303, USB1.1,需要安装驱动

VID_0AC8
PID_3340
中星微334,USB2.0免驱

VID_1781
PID_0306
台湾嘉映308H USB2.0免驱

附VID、PID查询网站
http://www.linux-usb.org/usb.ids

获取VID、PID后,据此下载驱动,然后打开驱动的INF文件,可以找到里面对应设备管理器的硬件ID即可判断驱动是否正确。

以最常见的摄像头为例,由于摄像头厂家众多,驱动非常混乱,各个网站也出现所谓的万能,这个世界有万能的东西吗?让我们相信硬件ID吧,集中市面的硬件ID,因为摄像头的芯片厂家就那么几家,这样就可以让大家可以很方便找到自己所有需要的驱动。

下面列举常见摄像头的VID、PID及对应的解决方案,驱动下载地址

最常见的摄像头硬件ID:VID_0AC8&PID_0302   
VID_0AC8是中芯微的代码,

常见方案如下:
USB\VID_0AC8&PID_303B   301PLH方案 下载地址:

http://drivers.mydrivers.com/search/902-1418-h17139/

USB\VID_0AC8&PID_301B    301B方案 下载地址:

http://drivers.mydrivers.com/drivers/204-81603-VIMICRO-ZC0301PL-301.4.328.07-Win2000-XP-XP-64-Vista-Vista-64/

USB\VID_0AC8&PID_305B    305B方案     http://drivers.mydrivers.com/search/902-1418-h19124/
USB\VID_0AC8&PID_307B    ZS211方案    http://drivers.mydrivers.com/search/902-1418-h28374/
USB\VID_0ac8&PID_0321    VC0321       http://drivers.mydrivers.com/search/902-1418-h24807/
USB\VID_0ac8&PID_0323    VC0323       http://drivers.mydrivers.com/search/902-1418-h24805/
USB\VID_0ac8&PID_0323    ZC0323P      http://drivers.mydrivers.com/search/902-1418-h29222/

USB\VID_0ac8&PID_0328    ZC0326       
USB\VID_0ac8&PID_0326    ZC0326      下载地址: 

http://drivers.mydrivers.com/drivers/260-104356-VIMICRO-VC0326-For-Win98SE-ME-2000-XP/

看到很多朋友找无驱的摄像头驱动,更新一个中星微出的方案

下载地址:
http://drivers.mydrivers.com/search/902-1418-h29045/

支持下列硬件ID:
USB\VID_0ac8&PID_3313
USB\VID_0ac8&PID_0331
USB\VID_0ac8&PID_331B
USB\VID_0ac8&PID_0332
USB\VID_0ac8&PID_332D
USB\VID_0ac8&PID_3330
USB\VID_0ac8&PID_3332
USB\VID_0ac8&PID_3333
USB\VID_0ac8&PID_3340
USB\VID_0ac8&PID_3342
USB\VID_0ac8&PID_3343
USB\VID_0ac8&PID_0336
USB\VID_0ac8&PID_336D
USB\VID_0ac8&PID_3410
USB\VID_0ac8&PID_3420
USB\VID_0ac8&PID_3430
USB\VID_0ac8&PID_3440
USB\VID_0ac8&PID_3000

VID_0C45是台湾松翰电子Sonix出的。

【更新几个比较少见的OEM松瀚方案】下载地址:
USB\VID_0c46&PID_605a  

http://drivers.mydrivers.com/drivers/259-103869-SONiX-SN9C102P-105-110-120-4.31.3.10-For-Win2000-XP/

USB\VID_0c45&PID_8008  下载地址:

http://drivers.mydrivers.com/drivers/259-103870-SONiX-SN9C202-2.18.1.0-For-Win2000-XP/

USB\VID_0C45&PID_600D  下载地址:

http://drivers.mydrivers.com/drivers/205-82011-Chicony-DC-2110(TwinkleCam)-1.0-For-Win98SE-ME-2000-XP/

【SN9C101方案 】  下载地址:http://drivers.mydrivers.com/drivers/204-81784-SONiX-SN9C101-SN9C102-4.20.1.001-For-Win98SE-ME-2000-XP/

USB\VID_0c45&PID_603f    ; SN9C101 + CISVF10
USB\VID_0c45&PID_602a    ; SN9C101 + HV7131 D/E
USB\VID_0c45&PID_602d    ; SN9C101 + HV7131 R
USB\VID_0c45&PID_6009    ; SN9C101 + PAS106
USB\VID_0c45&PID_6005    ; SN9C101 + TAS5110
USB\VID_0c45&PID_6019    ; SN9C101 + OV7630
USB\VID_0c45&PID_6011    ; SN9C101 + OV6650
USB\VID_0c45&PID_6007    ; SN9C101 + TAS5110D

【SN9C102方案 】  下载地址:http://drivers.mydrivers.com/drivers/204-81784-SONiX-SN9C101-SN9C102-4.20.1.001-For-Win98SE-ME-2000-XP/
USB\VID_0c45&PID_602c    ; SN9C102 + OV7630
USB\VID_0c45&PID_6030    ; SN9C102 + MI0343 MI0360 MI0330
USB\VID_0c45&PID_6024    ; SN9C102 + TAS5130
USB\VID_0c45&PID_6025    ; SN9C102 + TAS5130
USB\VID_0c45&PID_6028    ; SN9C102 + PAS202
USB\VID_0c45&PID_6029    ; SN9C102 + PAS106

【SN9C102P方案】  下载地址:http://drivers.mydrivers.com/search/902-1303-h24842/
USB\VID_0c45&PID_6040 ; SN9C102P + MI0360
USB\VID_0c45&PID_607a ; SN9C102P + OV7648
USB\VID_0c45&PID_607c ; SN9C102P + HV7131R
USB\VID_0c45&PID_607e ; SN9C102P + OV7630
USB\VID_0c45&PID_607b ; SN9C102P + OV7660

【SN9C103方案】  下载地址:http://drivers.mydrivers.com/search/902-1303-h24843/
USB\VID_0c45&PID_608e      ;CISVF10
USB\VID_0c45&PID_6083      ;HY7131D/E
USB\VID_0c45&PID_608c      ;HY7131/R
USB\VID_0c45&PID_608f      ;OV7630
USB\VID_0c45&PID_60af      ;PAS202
USB\VID_0c45&PID_60a8      ;PAS106
USB\VID_0c45&PID_6082      ;MI0343,MI0360
USB\VID_0c45&PID_60aa      ;TAS5130
USB\VID_0c45&PID_6025      ;TAS5130

【SN9C105方案】  下载地址:http://drivers.mydrivers.com/search/902-1303-h24842/
USB\VID_0c45&PID_60c0&MI_00    ; SN9C105 + MI0360
USB\VID_0c45&PID_60fa&MI_00    ; SN9C105 + OV7648
USB\VID_0c45&PID_60fc&MI_00    ; SN9C105 + HV7131R
USB\VID_0c45&PID_60fe&MI_00    ; SN9C105 + OV7630
USB\VID_0c45&PID_60fb&MI_00    ; SN9C105 + OV7660
USB\VID_0c45&PID_60f2&MI_00    ; SN9C105 + OV7670
USB\VID_0c45&PID_60ef&MI_00    ; SN9C105 + ICM105C
USB\VID_0c45&PID_60cc&MI_00    ; SN9C105 + HV7131GP
USB\VID_0c45&PID_60ec&MI_00    ; SN9C105 + MO4000
USB\VID_0c45&PID_60c8&MI_00    ; SN9C105 + OM6802
USB\VID_0c45&PID_60c2&MI_00    ; SN9C105 + P1030xC
USB\VID_0c45&PID_60ce&MI_00    ; SN9C105 + SP80708

【SN9C110方案】  下载地址:http://drivers.mydrivers.com/search/902-1303-h24842/
USB\VID_0c45&PID_612e ; SN9C110 + OV7630
USB\VID_0c45&PID_612f ; SN9C110 + ICM105C
USB\VID_0c45&PID_6122 ; SN9C110 + ICM105C
USB\VID_0c45&PID_612a ; SN9C110 + OV7648
USB\VID_0c45&PID_6123 ; SN9C110 + SanyoCCD
USB\VID_0c45&PID_612c ; SN9C110 + MO4000 

【SN9C120方案】  下载地址:http://drivers.mydrivers.com/search/902-1303-h24842/
USB\VID_0c45&PID_6130        ; 120+MI0360/MT9V111/MI0360B
USB\VID_0c45&PID_613a        ; SN9C120 + OV7648
USB\VID_0c45&PID_613c        ; SN9C120 + HV7131R
USB\VID_0c45&PID_613e        ; SN9C120 + OV7630
USB\VID_0c45&PID_6132        ; SN9C120 /SN9C120B+ OV7670
USB\VID_0c45&PID_613b        ; SN9C120 + OV7660
USB\VID_0c45&PID_6138        ; SN9C120 + MO4000
USB\VID_0c45&PID_6108        ; SN9C120 + OM6802
USB\VID_0c45&PID_6148        ; SN9C120B + OM6802
USB\VID_0c45&PID_6102        ; SN9C120 + PO2030N/GC0305
USB\VID_0c45&PID_6142        ; SN9C120B + PO2030N/GC0305
USB\VID_0c45&PID_6143        ; SN9C120B + SP80708
USB\VID_0c45&PID_614c        ; SN9C120B + GC0306

【SN9C128方案】  下载地址:http://drivers.mydrivers.com/search/902-1303-h21430/
USB\VID_0c45&PID_6100 ; MI0360 / MT9V111 / MI0360B
USB\VID_0c45&PID_610a ; OV7648
USB\VID_0c45&PID_610c ; HV7131R
USB\VID_0c45&PID_610e ; OV7630
USB\VID_0c45&PID_610b ; OV7660 

【SN9C201方案 】  下载地址:http://drivers.mydrivers.com/search/902-1303-h21429/
USB\VID_0c45&PID_6240        ; SN9C201 + MI1300
USB\VID_0c45&PID_6242        ; SN9C201 + MI1310
USB\VID_0c45&PID_624e        ; SN9C201 + SOI968
USB\VID_0c45&PID_624f        ; SN9C201 + OV9650
USB\VID_0c45&PID_6243        ; SN9C201 + S5K4AAFX
USB\VID_0c45&PID_624b        ; SN9C201 + CX1332
USB\VID_0c45&PID_627f        ; EEPROM
USB\VID_0c45&PID_6248        ; SN9C201 + OV9655
USB\VID_0c45&PID_624c        ; SN9C201 + MI1320
USB\VID_0c45&PID_6270        ; SN9C201 + MI0360\MT9V111
USB\VID_0c45&PID_627c        ; SN9C201 + HV7131R
USB\VID_0c45&PID_627b        ; SN9C201 + OV7660
USB\VID_0c45&PID_627a        ; SN9C201 + S5K53BEB
USB\VID_0c45&PID_6260        ; SN9C201 + OV7670ISP
USB\VID_0c45&PID_6262        ; SN9C201 + OM6802

【SN9C202方案 】  下载地址:http://drivers.mydrivers.com/search/902-1303-h21429/
USB\VID_0c45&PID_6280&MI_00    ; SN9C202 + MI1300
USB\VID_0c45&PID_6282&MI_00    ; SN9C202 + MI1310
USB\VID_0c45&PID_628e&MI_00    ; SN9C202 + SOI968
USB\VID_0c45&PID_628f&MI_00    ; SN9C202 + OV9650
USB\VID_0c45&PID_6288&MI_00    ; SN9C202 + OV9655
USB\VID_0c45&PID_628a&MI_00    ; SN9C202 + ICM107
USB\VID_0c45&PID_628c&MI_00    ; SN9C202 + MI1320
USB\VID_0c45&PID_62b0&MI_00    ; SN9C202 + MI0360\MT9V111
USB\VID_0c45&PID_62bc&MI_00    ; SN9C202 + HV7131R
USB\VID_0c45&PID_62bb&MI_00    ; SN9C202 + Ov7660
USB\VID_0c45&PID_62ba&MI_00    ; SN9C202 + S5K53BEB
USB\VID_0c45&PID_628b&MI_00    ; SN9C202 + CX1332
USB\VID_0c45&PID_6283&MI_00    ; SN9C202 + S5K4AAFX
USB\VID_0c45&PID_62a0&MI_00    ; SN9C202 + Ov7670ISP
USB\VID_0c45&PID_62a2&MI_00    ; SN9C202 + OM6802

【SN9C255方案】  下载地址:http://drivers.mydrivers.com/search/902-1303-h24844/
USB\VID_0C45&PID_62C0
USB\VID_0C45&PID_62C1
USB\VID_0C45&PID_62E0

【SN9C325方案】  下载地址:http://drivers.mydrivers.com/search/902-1303-h24846/
USB\VID_0c45&PID_612a ; SN9C325 + OV7648 + POx1030xC + SOI768 + PO2030N + OV7660 + OV7670 + HV7131R
USB\VID_0c45&PID_6128 ; SN9C325 + OM6802

应论坛上的朋友提醒,增加一个松瀚电子出的免驱摄像头方案。
【松瀚SNP2UVC】 下载地址:http://drivers.mydrivers.com/search/902-1303-h29223/
USB\VID_0C45&PID_62C0        ;SN9C211/213/230
USB\VID_0C45&PID_6300        ;SN9C216/236
USB\VID_0C45&PID_6310        ;SN9C230C
USB\VID_0C45&PID_62E1        ;SN9C255 non-audio
USB\VID_0C45&PID_62F0        ;SN9C210/233
USB\VID_0C45&PID_62C1        ;SN9C212
USB\VID_0C45&PID_62E0        ;SN9C255
USB\VID_0C45&PID_6301        ;SN9C226
USB\VID_0C45&PID_62F1        ;SN9C253

VID_05A9  OmniVision
USB\VID_05A9&PID_A518    http://drivers.mydrivers.com/drivers/259-103879-OmniVision-OV518-2.1.0.0-For-Win2000-XP/
USB\VID_05A9&PID_A511    http://drivers.mydrivers.com/drivers/259-103878-OmniVision-OV511-2.1.11.28-For-Win2000-XP/
USB\VID_05A9&PID_4519    http://drivers.mydrivers.com/drivers/259-103877-OmniVision-OV530-2.1.0.1-For-Win2000-XP/
USB\VID_05a9&PID_0519    http://drivers.mydrivers.com/drivers/259-103877-OmniVision-OV530-2.1.0.1-For-Win2000-XP/
USB\VID_05a9&PID_0531    http://drivers.mydrivers.com/drivers/259-103876-OmniVision-OV534-2.1.0.1-For-Win2000-XP/
USB\VID_05a9&PID_0550    http://drivers.mydrivers.com/drivers/259-103875-OmniVision-OV550-2.1.0.1-For-Win2000-XP/
USB\VID_05a9&PID_2800    http://drivers.mydrivers.com/drivers/259-103874-OmniVision-2800lus-2.1.0.1-For-Win2000-XP/

VID_1B17  CNLTF
CNLTF A380摄像头方案  下载地址:http://drivers.mydrivers.com/drivers/259-103880-CNLTF-A380-1.2.51.0928-For-Win2000-XP-XP-64-Vista-Vista-64/
硬件ID:
USB\VID_1B17&PID_6100
USB\VID_1B17&PID_6101
USB\VID_1B17&PID_6110
USB\VID_1B17&PID_6111

VID_1871  Aveo 嘉映微电子有限公司
388摄像头方案  下载地址:http://drivers.mydrivers.com/drivers/259-103881-Aveo-388-For-Win2000-XP-XP-64-Vista-Vista-64/
硬件ID:
USB\VID_1871&PID_0306
USB\VID_1871&PID_01f0
USB\VID_1871&PID_56CC

VID_093A   台湾原相科技。
USB\VID_093A&PID_2468
USB\VID_093A&PID_2460
下载地址:http://drivers.mydrivers.com/search/902-1580-h24847/

【原相PAP7501方案】
USB\VID_093A&PID_2700
USB\VID_093A&PID_2800
USB\VID_093A&PID_2801
下载地址:http://drivers.mydrivers.com/search/902-1580-h29232/

VID_093A   原相 PAC7302  
USB\VID_093A&PID_2620
USB\VID_093A&PID_2628
下载地址:http://drivers.mydrivers.com/search/902-1580-h25427/

USB\VID_093a&PID_010e
下载地址:
http://drivers.mydrivers.com/drivers/260-104357-PixArt-MR97310-For-Win98SE-ME-2000-XP/

SiGma Micro
SG310方案 http://drivers.mydrivers.com/drivers/259-103884-SIGMA-MICRO-SG310-1.0.0.0-For-Win2000-XP/
USB\VID_1C4F&PID_3000           
USB\VID_0F35&PID_FAF5             

VID_EB1A   台湾和瑞亚(empia)
USB\VID_EB1A&PID_2710
USB\VID_EB1A&PID_2711
USB\VID_EB1A&PID_2750
USB\VID_EB1A&PID_2751
USB\VID_EB1A&PID_2870
下载地址:
http://drivers.mydrivers.com/search/902-1579-h24833/

eMPIA EM27xx和EM28xx/EM29xx方案摄像头
USB\VID_EB1A&PID_2800
USB\VID_EB1A&PID_2801
USB\VID_EB1A&PID_2820
USB\VID_EB1A&PID_2821
USB\VID_EB1A&PID_2840
USB\VID_EB1A&PID_2841
USB\VID_EB1A&PID_2860
USB\VID_EB1A&PID_2861
USB\VID_EB1A&PID_2870
USB\VID_EB1A&PID_2880
USB\VID_EB1A&PID_2881
USB\VID_EB1A&PID_2710
USB\VID_EB1A&PID_2711
USB\VID_EB1A&PID_2750
USB\VID_EB1A&PID_2751
USB\VID_EB1A&PID_2761
USB\VID_EB1A&PID_2766
USB\VID_EB1A&PID_2901
下载地址:
http://drivers.mydrivers.com/drivers/259-103885-GENESYS-GL860-1.0.11.20-For-Win2000-XP/

VID_05E3  台湾创惟GenesysLogic
USB\VID_05E3&PID_0503
USB\VID_05E3&PID_F191
下载地址:
http://drivers.mydrivers.com/search/902-1632-h29234/

VID_0402  台湾扬智Ali
USB\VID_0402&PID_5602
下载地址:
http://drivers.mydrivers.com/search/902-75-h29235/

VID_06A2  台湾凌越 Topro
USB\VID_06A2&PID_0003
下载地址:
http://drivers.mydrivers.com/search/902-1583-h24884/
PS:凌越 TP6800方案的摄像头有四种芯片组合,4种芯片组合分别是:TP6800+HY7131R;TP6800+MT9V011;TP6800+PAS302;TP6800+EVS350。大家可以测试下驱动那个效果会比较好。

有朋友反映凌越的TP6800方案有些摄像头不能正常工作。再次更新一个凌越TP6801的方案,硬件ID一样也有可能是TP6801的方案。

TP6801方案
USB\VID_06A2&PID_0001
USB\VID_06A2&PID_0003
USB\VID_06A2&PID_6810
下载地址:
http://drivers.mydrivers.com/search/902-1583-h29236/

【爱普泰克网易拍方案】
VID_0553  意法半导体 STMicroelectronics
USB\VID_0553&PID_0200
USB\VID_0553&PID_0201
USB\VID_0553&PID_0202
下载地址:
http://drivers.mydrivers.com/drivers/259-103888-STMicroelectronics-STV680-2.00.0.3-For-Win2000-XP/
早期在国内的爱普泰克网易拍采用过的意法半导体STV0680的芯片方案。

爱普泰克DV5900
USB\VID_08CA&PID_2024
http://drivers.mydrivers.com/search/902-1549-h29240/
芯片实际是凌阳CA536A

台湾凌阳科技Sunplus【代码:VID_04FC】给爱普泰克提供的摄像头方案,采用CA533A方案。
USB\VID_08CA&PID_2010
USB\VID_08CA&PID_2012
USB\VID_08CA&PID_2020
USB\VID_08CA&PID_2022
下载地址:
http://drivers.mydrivers.com/search/902-1549-h29238/

VID_04FC  台湾凌阳科技Sunplus
【凌阳CA533A方案】
USB\VID_03F0&PID_6902
USB\VID_052B&PID_1708
下载地址:
http://drivers.mydrivers.com/search/902-1549-h29238/
【凌阳CA504A方案】
USB\VID_04FC&PID_504A
下载地址:
http://drivers.mydrivers.com/search/902-1549-h29239/

【凌阳CA536A方案】
USB\VID_04FC&PID_5360
下载地址:
http://drivers.mydrivers.com/search/902-1549-h29240/

【凌阳SPCA561方案】
USB\VID_04fc&PID_0561
下载地址:
http://drivers.mydrivers.com/search/902-1549-h21431/

【凌阳Ca522B方案】
USB\VID_04FC&PID_2000
下载地址:
http://drivers.mydrivers.com/search/902-1549-h29241/

【凌阳CA2001方案】
USB\VID_04FC&PID_2001
下载地址:
http://drivers.mydrivers.com/search/902-1549-h29242/

VID_05e1  台湾太欣半导体 Syntek
【Syntek STK013方案】
USB\VID_05e1&PID_0892
下载地址:
http://drivers.mydrivers.com/drivers/259-103942-Syntek-STK013-1.68.88.03-For-Win2000-XP/

【Syntek STK014方案】
USB\VID_05e1&PID_0893
下载地址:
http://drivers.mydrivers.com/drivers/259-103943-Syntek-STK014-For-Win2000-XP/

【Syntek STK016方案】
USB\VID_05e1&PID_0895
下载地址:
http://drivers.mydrivers.com/drivers/259-103944-Syntek-STK016-For-Win2000-XP/

VID_2770  台湾倚强科技
【SQ9120芯片】
USB\VID_2770&PID_9130     
USB\VID_2770&PID_9120
下载地址:
http://drivers.mydrivers.com/drivers/259-103945-SQ-SQ9120-For-Win2000-XP/

【SQ930b芯片】
USB\VID_2770&PID_930B
USB\VID_2770&PID_930C
USB\VID_041E&PID_4038
USB\VID_0471&PID_0329
USB\VID_04F2&PID_A120
USB\VID_04F2&PID_A121
USB\VID_04F2&PID_A122
USB\VID_04F2&PID_A123
USB\VID_04F2&PID_A124
下载地址:
http://drivers.mydrivers.com/drivers/259-103946-SQ-SQ930b-For-Win2000-XP/

USB\VID_2770&PID_9060 倚强SQ9060方案..
下载地址:
http://drivers.mydrivers.com/drivers/260-104358-SQ-SQ9060-For-Win2000-XP/

VID_0595  卓然Zoran公司
USB\VID_0595&PID_4343
下载地址:
http://drivers.mydrivers.com/drivers/259-103947-Zoran-Coach-Digital-Camera-For-Win2000-XP/

【视乐奇摄手星MX-500】
USB\VID_052B&PID_6A02
下载地址:
http://drivers.mydrivers.com/drivers/259-103948--MX-500-4.55.0.0-For-Win2000-XP/

VID_0DDA  台湾矽成积体电路
USB\VID_0DDA&PID_3011
下载地址:
http://drivers.mydrivers.com/drivers/259-103949-ISSI-5.0.1868.1-For-Win2000-XP/

【ICM532A方案】 来自台湾ICM
USB\VID_8751&PID_010F
USB\VID_0923&PID_010F
下载地址:http://drivers.mydrivers.com/drivers/259-103950-ICM-ICM532A-1.2.0.0-For-Win2000-XP/

UPDATA 08/10/21
VID_090C   来自台湾慧荣科技Silicon Motion
USB\VID_090C&PID_B370
USB\VID_090C&PID_B371
下载地址:http://drivers.mydrivers.com/drivers/259-103951-Silicon-Motion-SM370-5.3.5.0-For-Win2000-XP/

VID_058F   来自台湾安国科技
USB\VID_058F&PID_3820
下载地址:http://drivers.mydrivers.com/drivers/259-103952-ONKOK-cam3820-For-Win2000-XP/

VID_102C   来自台湾Etoms
USB\VID_102C&PID_6151
下载地址:http://drivers.mydrivers.com/drivers/259-103953-Etoms-ET151-For-Win2000-XP/

USB\VID_102C&PID_6251 非常常见的IBM Q-CAM摄像头
下载地址:http://drivers.mydrivers.com/drivers/259-103954-Etoms-ET251-For-Win2000-XP/

VID_0733   来自ViewQuest
有出过不少的方案
【VC5100Z】
USB\VID_0733&PID_5100
下载地址:http://drivers.mydrivers.com/drivers/259-103955-ViewQuest-VC5100Z-For-Win2000-XP/
【VC6100Z】
USB\VID_0733&PID_6100
下载地址:http://drivers.mydrivers.com/drivers/259-103956-ViewQuest-VC6100Z-For-Win2000-XP/
【VQ5300Z】
USB\VID_0733&PID_5300
下载地址:http://drivers.mydrivers.com/drivers/259-103957-ViewQuest-VQ5300Z-For-Win2000-XP/

【VQ2210】
USB\VID_0733&PID_2211

下载地址:http://drivers.mydrivers.com/drivers/259-103958-ViewQuest-VQ2210-For-Win2000-XP/

posted @ 2010-08-19 01:00 海王 阅读(542) 评论(0) 编辑
 

http://weijb0606.blog.163.com/blog/static/131286274201063145521107/

Kernel version :2.6.22.6
Crosstool      :arm-linux-gcc-3.4.5
Board          :FS2410

System         :Fedora 8
Source         :gspcav1-20071224、servfox-R1_1_3、spcaview-20061208

Author                   :http://viviwei.cublog.cn

一、移植gspcav1-20071224

gspcav1-20071224下载地址:http://www.slackware.com/~alien/slackbuilds/gspcav1/build/gspcav1-20071224.tar.gz
FS2410开发板上移植的是Linux-2.6.22.6内核,USB及CS8900A均能工作,由于linux-2.6.22.6/drivers/usb 目录下没有 media 目录,故移植步骤如下:
a)  在 linux-2.6.22.6/drivers/usb 目录下新建 media 目录,将gspcav1-20071224.tar.gz copy 到 media  下并解压。为了使media 编译进内核,需修改linux-2.6.22.6/drivers/usb 目录下的Kconfig、Makefile 文件。
[linux@weijing usb]$ pwd
/work/kernel/linux-2.6.22.6/drivers/usb
[linux@weijing usb]$ vi  Kconfig
添加
source "drivers/usb/media/Kconfig"
[linux@weijing usb]$ vi Makefile
添加
obj-$(CONFIG_USB_SPCA5XX)        += media/
b)  为添加 gspcav1-20071224 编译选项,在 media 下新建 Kconfig、Makefile 文件。
[linux@weijing media]$ pwd
/work/kernel/linux-2.6.22.6/drivers/usb/media
[linux@weijing media]$ vi Kconfig
#
# USB Multimedia device configuration
#
comment "USB Multimedia devices"
        depends on USB
config USB_SPCA5XX
        tristate "USB SPCA5XX Sunplus/Vimicro/Sonix jpeg Cameras"
        depends on USB && VIDEO_DEV
        ---help---
          Say Y or M here if you want to use one of these webcams:
          The built-in microphone is enabled by selecting USB Audio support.
          This driver uses the Video For Linux API. You must say Y or M to
          "Video For Linux" (under Character Devices) to use this driver.
          Information on this API and pointers to "v4l" programs may be found
          at <Documentation/video4linux/API.html>.
          To compile this driver as a module, choose M here: the
          module will be called spca5xx.
[linux@weijing media]$ vi Makefile
#
# Makefile for USB Media drivers
#
obj-$(CONFIG_USB_SPCA5XX)   += gspcav1-20071224/
c)  修改 gspcav1-20071224 的 Makefile
[linux@weijing gspcav1-20071224]$ pwd
/work/kernel/linux-2.6.22.6/drivers/usb/media/gspcav1-20071224
[linux@weijing gspcav1-20071224]$ vi Makefile
gspca-objs := gspca_core.o decoder/gspcadecoder.o
obj-$(CONFIG_USB_SPCA5XX) += gspca.o
clean:
        rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c
        rm -rf .tmp_versions
d)  编译内核

(1)Multimedia devices  --->
         Video For Linux
(2) USB support  --->
        Support for Host-side USB
       --- USB Host Controller Drivers   
        OHCI HCD support
(3)--- USB Multimedia devices
     USB SPCA5XX Sunplus/Vimicro/Sonix jpeg Cameras

此时,可能会提示 gspca_core.c 的一些轻微错误,稍作修改即可:
//static const char gspca_version[] = GSPCA_VERSION;
static const char gspca_version[] = "00.60.00";
把新生成的 uImage 烧进开发板,重启,插上中星微芯片的摄像头,命令行出现
# usb 1-1: new full speed USB device using s3c2410-ohci and address 2          
usb 1-1: configuration #1 chosen from 1 choice                                 
drivers/usb/media/gspcav1-20071224/gspca_core.c: USB GSPCA camera found.(ZC3XX)
说明移植的驱动已经能识别设备,设备名所在路径 /dev/video0。
二、servfox
    服务器端程序用是servfox,通过它可以在PC上看到开发板采集来的图像,从这里下载

http://mxhaard.free.fr/spca50x/embedded/Servfox/servfox-R1_1_3.tar.gz
下载,解压,进入其目录,发现没有一个makefile.arm,还有一个makefile.386,将makefile.arm改名为makefile,然后输入命令 make,生成 servfox 可实行文件,copy 到开发板运行之:

# ./servfox -d /dev/video0 -g -s 640x480 -w 7070                               
servfox version: 1.1.3 date: 11:12:2005 (C) mxhaard@magic.fr
wrong spca5xx device                                                           
Waiting .... for connection. CTrl_c to stop !!!!                               
Got connection from 192.168.1.2
三、spcaview
客户端程序使用的是spcaview,下载地址为:

http://mxhaard.free.fr/spca50x/Download/spcaview-20061208.tar.gz
这个程序在PC 上运行,直接解压编译,生成 spcaview 可实行文件,运行如下:

[root@weijing spcaview-20061208]# ./spcaview -g -w 192.168.1.17
Spcaview version: 1.1.7 date: 06:11:2006 (C) mxhaard@magic.fr
ERROR Set default port to 7070
using Server 192.168.1.17 Port 7070
bright 32768 contrast 32768

附件2是在 Fedora 8 下看到的图像。

参考:http://blog.chinaunix.net/u/26710/showart_387765.html

http://blog.chinaunix.net/u/31/showart_692727.html

posted @ 2010-08-19 00:56 海王 阅读(340) 评论(0) 编辑
 

http://weijb0606.blog.163.com/blog/static/131286274201063145356429/

我的摄像头终于出现图像了!

李迟按:本文章不是教程,不是心得总结,而是记录我在做毕业设计过程中遇到的一些问题,以及怎么去解决

(有些还是没有解决)。可能带有牢骚,可能带有某些让人不悦的话。希望大家见谅。

今晚很高兴,捣鼓了几天,郁闷了几天的事,今天解决了一些了。起码我能在linux下看到摄像头的图像了。

提起USB摄像在linux下的使用,无论是百度还是Google,出现的多数是法国人写的一个通用驱动程序,即spca5xx,

我也是找了很久才找到,——因为在网上看到的那个网站已经不能登陆了,就是说不再维护了(这个后来再作说明),所以

找了很久。可惜不能用。因为我make都不通过,出现的错误如下:

make -C /lib/modules/`uname -r`/build SUBDIRS=/usr/local/gspcav1-20071224 CC=cc modules

make[1]: Entering directory `/usr/src/linux-2.6.30.2'

CC [M] /usr/local/gspcav1-20071224/gspca_core.o

/usr/local/gspcav1-20071224/gspca_core.c:54:27: error: asm/semaphore.h: No such file or directory

In file included from /usr/local/gspcav1-20071224/gspca_core.c:845:

/usr/local/gspcav1-20071224/utils/spcausb.h: In function ‘spca5xxRegRead’:

/usr/local/gspcav1-20071224/utils/spcausb.h:95: error: implicit declaration of function ‘info’

/usr/local/gspcav1-20071224/utils/spcausb.h: In function ‘spca_set_interface’:

/usr/local/gspcav1-20071224/utils/spcausb.h:278: error: implicit declaration of function ‘warn’

In file included from /usr/local/gspcav1-20071224/gspca_core.c:853:

/usr/local/gspcav1-20071224/Sunplus-jpeg/sp5xxfw2.h: In function ‘sp5xxfw2_init’:

/usr/local/gspcav1-20071224/Sunplus-jpeg/sp5xxfw2.h:122: error: called object ‘info’ is not a function

/usr/local/gspcav1-20071224/Sunplus-jpeg/sp5xxfw2.h:136: error: called object ‘info’ is not a function

/usr/local/gspcav1-20071224/Sunplus-jpeg/sp5xxfw2.h:141: error: called object ‘info’ is not a function

/usr/local/gspcav1-20071224/Sunplus-jpeg/sp5xxfw2.h:148: error: called object ‘info’ is not a function

/usr/local/gspcav1-20071224/Sunplus-jpeg/sp5xxfw2.h:176: error: called object ‘info’ is not a function

/usr/local/gspcav1-20071224/Sunplus-jpeg/sp5xxfw2.h: In function ‘sp5xxfw2_start’:

/usr/local/gspcav1-20071224/Sunplus-jpeg/sp5xxfw2.h:214: error: called object ‘info’ is not a function

/usr/local/gspcav1-20071224/Sunplus-jpeg/sp5xxfw2.h:230: error: called object ‘info’ is not a function

/usr/local/gspcav1-20071224/gspca_core.c: In function ‘spca5xx_ioctl’:

/usr/local/gspcav1-20071224/gspca_core.c:2463: error: implicit declaration of function ‘video_usercopy’

/usr/local/gspcav1-20071224/gspca_core.c: At top level:

/usr/local/gspcav1-20071224/gspca_core.c:2609: error: unknown field ‘owner’ specified in initializer

/usr/local/gspcav1-20071224/gspca_core.c:2609: warning: initialization from incompatible pointer type

/usr/local/gspcav1-20071224/gspca_core.c:2611: error: unknown field ‘type’ specified in initializer

/usr/local/gspcav1-20071224/gspca_core.c:2615: warning: initialization from incompatible pointer type

/usr/local/gspcav1-20071224/gspca_core.c: In function ‘spca50x_create_sysfs’:

/usr/local/gspcav1-20071224/gspca_core.c:2769: error: implicit declaration of function ‘video_device_create_file’

/usr/local/gspcav1-20071224/gspca_core.c:2780: error: implicit declaration of function ‘video_device_remove_file’

/usr/local/gspcav1-20071224/gspca_core.c: In function ‘spca5xx_probe’:

/usr/local/gspcav1-20071224/gspca_core.c:4301: error: incompatible types in assignment

make[2]: *** [/usr/local/gspcav1-20071224/gspca_core.o] Error 1

make[1]: *** [_module_/usr/local/gspcav1-20071224] Error 2

make[1]: Leaving directory `/usr/src/linux-2.6.30.2'

make: *** [default] Error 2

以我现在的能力,我不能解决,我google过,但得不到好的解决方法。

更重要的是,现在想找一个几年前驱动支持的摄像头很难啊!现在都流行免驱了——根据OS相关理论,这是不成功的,

设备没有驱动哪能访问?他们说的是用户免去安装驱动程序这一步骤,——是这个“免驱”。我买的摄像头不

在spca5xx支持范围之中。我好容易找到一个,是小郭用的,摄像头ID刚好是上述驱动所支持的。当时很兴

奋,心想,万事俱备,只差编译、测试了。可惜,以失败告终。错误如上所述。

我试的几个版本为spca5xx-20060501和gspcav1-20071224,都不行。

在网上找了那么多文章看,但一个也行不通。我不知大家的感受是什么,反正我很郁闷,很无奈。

后来,在插入我买的摄像头时,使用了lsusb,将ID那一行复制到google中,一不小心,发现了一个

好网站:http://linux-uvc.berlios.de/。上面竟然有我摄像头的ID号!!继续研究,发现有UVC这个东东,

我在配置内核时也碰到过,但没有注意,没想到如此有用!后来在一个网站中找到有关使用UVC驱动摄像头的

文章,地址忘了,我也不知是怎么搜索到的。此外还下载一个观看图像的小软件(补充一下:luvcview 或者cheese[debian自带])。

结果成了!可以显示图像了!下面写一下过程:

如果你能在http://linux-uvc.berlios.de/找到你的摄像头的ID,即UVC支持的,那么就可以在linux下使用了。

至于从哪个版本开始内核支持UVC,官方的话是“Linux 2.6.26 and newer includes the Linux UVC driver natively.”

1、查看摄像头ID:

[root@151 dev]# lsusb

Bus 002 Device 013: ID 0ac8:3313 Z-Star Microelectronics Corp.

0xc8:3313在UVC中支持了。

2、插入摄像头后,就可以在/dev/下查看是否有video设备文件:

[root@151 dev]# ls | grep video

video

video0

其中,video是video0的连接。如果没有再现,可能UVC没有配置到内核中,重新配置就可以了

(大致在Device DriversàMultimedia devicesàVideo capture adaptersàV4L USB devices下面)。如果内核配置了,

还是不出现,可以使用modprobe uvcvideo来加载该模块。

3、先看看摄像头的相关信息:

lshal | grep Cam

出现:

info.product = 'Vega USB 2.0 Camera.' (string)

usb_device.product = 'Vega USB 2.0 Camera.' (string)

usb.interface.description = 'Vega USB 2.0 Camera.' (string)

info.product = 'Vega USB 2.0 Camera.' (string)

input.product = 'Vega USB 2.0 Camera.' (string)

info.product = 'Vega USB 2.0 Camera.' (string)

对USB有研究的,就很熟悉这些字段。

再看一下系统能不能识别出摄像头:

[root@151 log]# dmesg | grep Cam

uvcvideo: Found UVC 1.00 device Vega USB 2.0 Camera. (0ac8:3313)

input: Vega USB 2.0 Camera. as /class/input/input6

usb 2-7: Product: Vega USB 2.0 Camera.

uvcvideo: Found UVC 1.00 device Vega USB 2.0 Camera. (0ac8:3313)

input: Vega USB 2.0 Camera. as /class/input/input7

usb 2-7: Product: Vega USB 2.0 Camera.

uvcvideo: Found UVC 1.00 device Vega USB 2.0 Camera. (0ac8:3313)

input: Vega USB 2.0 Camera. as /class/input/input8

usb 2-7: Product: Vega USB 2.0 Camera.

[root@151 ~]# dmesg | grep video

pci 0000:05:00.0: Boot video device

Linux video capture interface: v2.00

usbcore: registered new interface driver uvcvideo

uvcvideo 2-7:1.0: usb_probe_interface

uvcvideo 2-7:1.0: usb_probe_interface - got id

uvcvideo: Found UVC 1.00 device Vega USB 2.0 Camera. (0ac8:3313)

uvcvideo 2-7:1.0: usb_probe_interface

uvcvideo 2-7:1.0: usb_probe_interface - got id

uvcvideo: Found UVC 1.00 device Vega USB 2.0 Camera. (0ac8:3313)

uvcvideo 2-7:1.0: usb_probe_interface

uvcvideo 2-7:1.0: usb_probe_interface - got id

uvcvideo: Found UVC 1.00 device Vega USB 2.0 Camera. (0ac8:3313)

哈哈,识别出来了!可以测试了。

4、我使用的软件是luvcview,这个软件google就可以找到的。安装过程很简单,——make,make install就可以了。(哈哈,这里才说)

下面这个过程是测试过程,从看到图像到结束的过程:

[root@151 dev]# luvcview -d /dev/video0 -f yuv -s 640x480   (直接运行luvcview也可)

uvcview verion 0.1.4

size width: 640 height: 480

Video driver: x11

A window manager is available

video /dev/video0

Stop asked

Clean Up done Quit

[root@151 dev]#

解释命令:

-d 设备名,这里/dev/video或/dev/video0都可以,因为它们都是一个文件

-f 格式,有yuv和jpg两种,后者测试不行

-s 大小,能支持的最大尺度可能由luvcview决定,也可能由摄像头决定,(应该是后者,暂没有研究)

更具体的参见luvcview目录下的README文件。

另外,如果没有插入摄像头,即使modprobe uvcvideo也不会出现/dev/video设备文件;插入摄像头,即使没有modprobe uvcvideo,

也会出现/dev/video设备文件,当然这是我的测试,没有代表性,也没有理论根据的。

注:

1、UVC:USB Video Class

2、gspcav不是不再维护,而是在某一版本开始已经纳入内核了,至于哪个版本(2.6.26),就不太清楚了。特此说明。

3、这次毕业设计所不再编译gspca到内核中了。不支持它,直接使用UVC。

第一张图:红旗6.2,内核2.6.28.8

USB Camera摄像头 - BEYOND ME - BEYOND ME500)this.width=500;" width="500" border="0">

虚拟机FC9,内核2.6.30

USB Camera摄像头 - BEYOND ME - BEYOND ME500)this.width=500;" width="500" border="0">

发表于: 2010-03-19,修改于:

我跟作者经历简直太相似了,起先搞了好几天真是有点摸不着头脑,哈哈!!

posted @ 2010-08-19 00:54 海王 阅读(4795) 评论(0) 编辑
 

http://eatdrinkmanwoman.spaces.live.com/blog/cns!97719476F5BAEDA4!1336.entry

http://weijb0606.blog.163.com/blog/static/131286274201063152423963/

本文所说的摄像头(Webcam),特指USB摄像头。

  在Windows下,摄像头驱动由厂商开发并提供。但在Linux下,因商业利益有限,只有极少厂商愿意提供摄像头驱动支持。这并不妨碍Linux下摄像头的使用——广大第三方志愿者维护着大大小小的驱动。之前做过一个嵌入式皮毛项目,虽然摄像头驱动不关我的事,在好奇心驱使下简要探索了一番。结果是有些胸闷,它们像蜘蛛丝一样杂乱。写本文的动机是想理清一下主线,给后来者提供一点有限的参考,但无法保证下面的文字完全正确。

  常见的摄像头驱动有以下几个系列: OVCam drivers(ov5xx)

  该系列驱动是针对OmniVision OV5xx系列芯片,此类芯片被广泛运用于各种USB摄像头中,在嵌入式开发板上尤其常见。凡是使用了OV511/OV511+/OV518 /OV6620/OV6630/OV7610/OV7620/OV7 620AE等图像传感器的摄像头都可以在该驱动下工作。

  项目主页:http://alpha.dyndns.org/ov511/

  Philips USB Webcam Driver(pwc) 该驱动主要用于Philips及pwc芯片兼容摄像头。由于原开发者与Philips公司签有保密协定,该驱动以二进制形式提供,后来被踢出内核,引起一场口水战:是用户需求重要还是保持内核纯洁重要?所幸后续开发者从原项目上创建了一个新的分支,使得该项目继续存活。

  项目主页:http://www.saillard.org/linux/pwc/

  QuickCam USB camera driver (qc-usb) 该驱动主要用于Logitech公司的QuickCam Express系列和其它兼容型号摄像头。最初由Georg Acher开发,当时命名为qce-ga。Jean-Frederic Clere参考该驱动创建出了第一个Video4Linux兼容驱动。从那开始,不断有开发者加入,使得该驱动逐渐能够支持新的摄像头和芯片。在此期间,该驱动更名为qc-usb,更为广泛地支持其它QuickCam USB摄像头,而不再是局限于Express系列。

  项目主页:http://qce-ga.sourceforge.net/

  QuickCam Messenger & Communicate driver(quickcam) 这是另一个针对QuickCam摄像头的驱动,它仅支持某一些型号,并且与qc-usb驱动不兼容。项目主页:http://home.mag.cx/messenger/

  SPCA webcam driver(gspca/spca5xx) 该系列驱动适用于Sunplus芯片摄像头,也适用于其它芯片,如目前国内山寨摄像头一哥“中星微”(Z-Star)芯片。Michel Xhaard是该项目的维护者,他在60岁左右的时候(大约是2003年)从一种普通常见的驱动入手,进而不断修改开发成一个支持250种以上摄像头的通用驱动。他还写了流媒体服务器spcaserv与客户端spcaview。不少高校所谓的嵌入式无线网络视频传输项目,就是从这两个东西来的。

  项目主页:http://mxhaard.free.fr/spca5xx.html

  Linux UVC driver(uvc) 该驱动适用于符合USB视频类(USB Video Class)规范的摄像头设备,它包括V4L2内核设备驱动和用户空间工具补丁。大多数大容量存储器设备(如优盘)都遵循USB规范,因而仅用一个单一驱动就可以操作它们。与此类似,UVC兼容外设只需要一个通用驱动即可。

  USB摄像头大体上可以二分为UVC cameras和non-UVC cameras。推荐购买UVC cameras。UVC是一个开放的标准,拥有维护良好的驱动,它属于内核代码的一部分。插入摄像头后就可以工作,而无须编译或安装额外的驱动。non- UVC cameras通常情况下不比UVC cameras工作出色,前者的驱动并不遵循通用的协议,需要针对每种摄像头做出单独的处理,这往往需要一个逆向工程的探索过程。

  判断一个摄像头是否属于UVC规范可以使用下面方法:

  1.使用lsusb命令或其它硬件信息查看工具找出摄像头的设备号(Vendor ID)和产品号(Product ID)。如Logitech Quickcam for Notebooks Pro摄像头是046d:08cb;

  2.查找是否有视频类接口信息

  lsusb -d 046d:08cb -v | grep "14 Video"

  如果该摄像头兼容UVC,则会输出类似信息

  bFunctionClass 14 Video

  bInterfaceClass 14 Video

  bInterfaceClass 14 Video

  bInterfaceClass 14 Video

  若无以上信息,则是non-UVC设备。

  项目主页:http://linux-uvc.berlios.de/

  在Linux下摄像头驱动有三种存在形式,内置于内核(within the kernel),做为一个外挂的模块(module),或者是预编译的二进制程序(pre-compiled binary)。

  Linux内核树会不断合并优秀的驱动。从2.4内核起,ov5xx驱动就已经是内核代码的一部分。从2.6.26开始,Linux内核原生包含uvc 驱动。2.6.27内核又吸收进了gspca/spca5xx系列驱动。常见的Linux发行版所配置的内核,一般都已将这些驱动选项打开,而无需用户另外编译。内核的.config文件中有许多配置变量等式,用来说明内核配置的结果。y表示本编译选项对应的内核代码被静态编译进 Linux内核;m表示本编译选项对应的内核代码被编译成模块;n表示不选择此编译选项。

  以Fedora12/boot下的config文件为例

  cat /boot/config-2.6.31.12-174.2.3.fc12.i686 | grep CONFIG_USB_GSPCA

  CONFIG_USB_GSPCA=m

  CONFIG_USB_GSPCA_CONEX=m

  CONFIG_USB_GSPCA_ETOMS=m

  CONFIG_USB_GSPCA_FINEPIX=m

  CONFIG_USB_GSPCA_MARS=m

  CONFIG_USB_GSPCA_MR97310A=m

  CONFIG_USB_GSPCA_OV519=m

  CONFIG_USB_GSPCA_OV534=m

  CONFIG_USB_GSPCA_PAC207=m

  CONFIG_USB_GSPCA_PAC7311=m

  CONFIG_USB_GSPCA_SN9C20X=m

  CONFIG_USB_GSPCA_SN9C20X_EVDEV=y

  CONFIG_USB_GSPCA_SONIXB=m

  CONFIG_USB_GSPCA_SONIXJ=m

  CONFIG_USB_GSPCA_SPCA500=m

  CONFIG_USB_GSPCA_SPCA501=m

  CONFIG_USB_GSPCA_SPCA505=m

  CONFIG_USB_GSPCA_SPCA506=m

  CONFIG_USB_GSPCA_SPCA508=m

  CONFIG_USB_GSPCA_SPCA561=m

  CONFIG_USB_GSPCA_SQ905=m

  CONFIG_USB_GSPCA_SQ905C=m

  CONFIG_USB_GSPCA_STK014=m

  CONFIG_USB_GSPCA_SUNPLUS=m

  CONFIG_USB_GSPCA_T613=m

  CONFIG_USB_GSPCA_TV8532=m

  CONFIG_USB_GSPCA_VC032X=m

  CONFIG_USB_GSPCA_ZC3XX=m

  可以看到gspca系列驱动被编译为模块。当插入摄像头后,使用dmesg命令可以打印出以下信息:

  usb 1-1.2: new full speed USB device using ehci_hcd and address 6

  usb 1-1.2: New USB device found, idVendor=046d, idProduct=08af

  usb 1-1.2: New USB device strings: Mfr=0, Product=0, SerialNumber=0

  usb 1-1.2: configuration #1 chosen from 1 choice

  gspca: probing 046d:08af

  zc3xx: probe 2wr ov vga 0x0000

  zc3xx: probe sensor -> 0011

  zc3xx: Find Sensor HV7131R(c)

  gspca: probe ok

  这说明该摄像头被识别,且自动挂载了gspca系列下的zc3xx驱动。

  如果由于某种原因,已配置的内核中没有包括摄像头驱动,可以重新配置内核选项,用新编译的内核替换原有的旧内核。或者是依据设备号及产品号,直接到对应驱动的项目主页,下载源码进行编译。

  最后总结一下

  如果你想买一个摄像头,推荐买Logitech的,买符合UVC驱动的,可以到这里挑一款。

  如果你已经有了一个摄像头,先插进去看看,Linux对它有没有反应。记录dmesg输出信息,记录lsusb输出设备号,以设备号为关键字上Google搜索。

  参考资源 http://www.tldp.org/HOWTO/Webcam-HOWTO/

  http://www.chineselinuxuniversity.net/courses/kern el/articles/19988.shtml

  http://www.quickcamteam.net/

posted @ 2010-08-19 00:36 海王 阅读(1562) 评论(0) 编辑
 
Copyright © 海王 Powered by: 博客园 模板提供:沪江博客