USB摄像头在嵌入式Linux中的应用
2010-06-28周顶辉王艳秋
周顶辉,王艳秋
(辽宁工业大学通信与信息系统,辽宁 锦州 121000)
随着多媒体、网络技术的迅猛发展和后PC机时代的到来,USB摄像头的应用越来越广泛,例如远程监控、视频电话和视频会议等。摄像头由主控芯片和传感芯片组成,主控芯片负责图像采集、压缩以及和主机的通信。我们使用的是市面上常见的一款CMOS摄像头,主控芯片为台湾松翰科技(Sonix)公司的SN9C288CF6-1,传感芯片是ov7620。本文主要介绍USB协议驱动模块的分层结构、驱动程序的实现过程及设备的硬件初始化。
1 USB协议驱动程序的结构
USB设备驱动程序,主要由USB内核控制模块和设备驱动模块两部分构成。USB内核控制模块封装了支持USB主控制器及USB设备驱动的特定API,通过定义一系列的数据结构、宏和函数,来抽象化硬件,使得系统对各种设备的访问都采用统一的形式,做到了硬件无关。设备驱动模块,主要完成USB设备的注册注销、硬件初始化和为上层应用程序提供接口等工作。由于在Linux系统中,已经内置了USB内核控制模块,我们只需要编写设备驱动程序。
2 设备驱动程序的实现流程
2.1 注册和注销驱动设备
Linux USB驱动程序首先要做的,就是把包含设备信息和相关操作的结构体ov7620_driver注册到USB子系统里,该过程是调用usb_register函数来完成的,具体过程如下:
usb_ov7620_init(void)
{......
proc_ov7620_create();//建立PROC设备文件
if(usb_register(&ov7620_driver)<0)//调用usb_register函数完成注册
return-1;
info("ov7620 driver%s registered",version);
return 0;
};
其中ov7620_driver包含了USB摄像头的相关信息,并提供了当摄像头插入拔出时所对应的操作,结构如下:
static struct usb_driver ov7620_driver={
.name="ov7620",
.id_table=device_table,
.probe=ov7620_probe,
.disconnect=ov7620_disconnect
};
probe和disconnect是函数指针。当插入USB摄像头时,调用ov7620_probe()函数,主要用来检测VID和PID,看USB内核控制模块里有没有匹配的驱动,如果有向Linux的视频子系统注册,并将驱动实现的系统调用,挂到内核中:
ov7620_probe(struct usb_interface*intf,const struct usb_device_id*id)
{......
if((err_probe=spcaDetectCamera(ov7620))<0)//具体物理设备查找,匹配厂商号,设备号
{err("Devices not found!!");goto error;}
……
memcpy(ov7620->vdev,&ov7620_template,sizeof(ov7620_template));
//系统调用的挂接,在此将驱动实现的系统调用,挂到内核中
};
当摄像头从USB总线拔掉,设备指针会调用ov7620_disconnect()函数:
static void ov7620_disconnect(struct usb_interface*intf)
{……
if(ov7620->vdev)
video_unregister_device(ov7620->vdev);//注销video设备
};
2.2 上层应用接口模块
当设备插入USB总线时,系统会调用probe函数探测设备并把系统调用挂接到内核。上层应用程序在获取设备句柄以后,可以直接通过系统调用对设备进行操作,如read、write等。作为摄像头驱动不需要输出功能,因此在程序中没有实现write系统调用。数据结构如下:
static struct file_operations ov7620_fops={
.owner=THIS_MODULE,
.open=ov7620_open,//open功能
.release=ov7620_close,//close功能
.read=ov7620_read,//read功能
.mmap=ov7620_mmap,//内存映射功能
.ioctl=ov7620_ioctl,//文件信息获取
};
ov7620_open完成设备的打开和初始化,并初始化解码器模块。其具体实现如下:
static int ov7620_open(struct video_device*vdev,int flags)
{……
err=ov7620_init_source(ov7620);//初始化控制器和传感器芯片
err=ov7620_init_transfert(ov7620);//初始化URB(usb request block)包,启动摄像头,采用同步传输的方式传送数据
};
ov7620_close函数主要完成设备的关闭,ov7620_mmap和ov7620_read是应用程序读取数据的两个接口函数。ov7620_mmap通过remap_page_range函数实现内存映射,ov7620_read通过copy_to_user实现用户空间和内核空间的数据拷贝,只读取其中一帧大小的数据。
2.3 初始化传感器和控制器
在打开设备时,需要对硬件进行初始化。摄像头由两个主要的芯片组成,图像传感器芯片ov7620和桥接芯片SN9C102P。摄像头的结构框图如图1。桥接芯片提供了开放的源代码,里面提供了对传感器控制的接口函数,如sn9c102_i2c_write,sn9c102_i2c_read等。利用提供的接口函数我们就可以对ov7620的寄存器写值,完成传感器的初始化工作和图像采集控制,过程如下:
sn9c102_i2c_write (ov7620->dev,ov7620_sensor_init [i],8)//ov7630_sensor_init是传感器ov7620寄存器结构。
图1 摄像头的结构框图
3 驱动程序的移植和测试
在PC机上搭建交叉编译环境,系统配置为fedora 7,内核2.6.19,安装的交叉编译工具为arm-linux-gcc-3.4.1。编译环境建立以后,还需要配置Makefile文件,完成后只要在终端里执行make命令就可以生成驱动模块文件。然后通过超级终端下载到Te2440开发板上,用insmod命令加载驱动。在开发板上运行servfox,在PC机上通过spcaview就可以看到图像了。
4 结束语
本文对USB摄像头驱动程序的开发过程,进行了简单的介绍,并介绍了Makefile文件的内容。本文程序结构功能相对简单,在此基础上可以扩展出一个视频监控系统,或者进行图像处理方面的研究。
[1]Alessandro Rubini,Jonathan Corbet.Linux设备驱动程序[M].魏永明,骆 钢,姜 君译.北京:中国电力出版社,2002.
[2]刘春成.基于嵌入式Linux的USB摄像头驱动开发[J].计算机工程与设计,2007,(8):2-3.
[3]魏 武,杨坚锐.嵌入式Linux下USB摄像头驱动程序的开发[J].现代电子技术,2006,(11):3-4.
[4]孙天泽,袁文菊,张海峰.嵌入式设计及Linux驱动开发指南—基于ARM9处理器[M].北京:电子工业出版社,2005.