在linux中添加对自己摄像头的驱动支持

  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所支持的,不妨都来一试,相信你的摄像头也不会让你失望。
[注1]如需转载,请注明出处。
[注2]您可以使用该链接使用这篇文章: http://blog.chinaunix.net/u/26710/showart_387765.html

你可能感兴趣的:(数据结构,linux,struct,image,interface,CAM)