周頂輝,王艷秋
(遼寧工業(yè)大學(xué)通信與信息系統(tǒng),遼寧 錦州 121000)
隨著多媒體、網(wǎng)絡(luò)技術(shù)的迅猛發(fā)展和后PC機時代的到來,USB攝像頭的應(yīng)用越來越廣泛,例如遠程監(jiān)控、視頻電話和視頻會議等。攝像頭由主控芯片和傳感芯片組成,主控芯片負責圖像采集、壓縮以及和主機的通信。我們使用的是市面上常見的一款CMOS攝像頭,主控芯片為臺灣松翰科技(Sonix)公司的SN9C288CF6-1,傳感芯片是ov7620。本文主要介紹USB協(xié)議驅(qū)動模塊的分層結(jié)構(gòu)、驅(qū)動程序的實現(xiàn)過程及設(shè)備的硬件初始化。
USB設(shè)備驅(qū)動程序,主要由USB內(nèi)核控制模塊和設(shè)備驅(qū)動模塊兩部分構(gòu)成。USB內(nèi)核控制模塊封裝了支持USB主控制器及USB設(shè)備驅(qū)動的特定API,通過定義一系列的數(shù)據(jù)結(jié)構(gòu)、宏和函數(shù),來抽象化硬件,使得系統(tǒng)對各種設(shè)備的訪問都采用統(tǒng)一的形式,做到了硬件無關(guān)。設(shè)備驅(qū)動模塊,主要完成USB設(shè)備的注冊注銷、硬件初始化和為上層應(yīng)用程序提供接口等工作。由于在Linux系統(tǒng)中,已經(jīng)內(nèi)置了USB內(nèi)核控制模塊,我們只需要編寫設(shè)備驅(qū)動程序。
Linux USB驅(qū)動程序首先要做的,就是把包含設(shè)備信息和相關(guān)操作的結(jié)構(gòu)體ov7620_driver注冊到USB子系統(tǒng)里,該過程是調(diào)用usb_register函數(shù)來完成的,具體過程如下:
usb_ov7620_init(void)
{......
proc_ov7620_create();//建立PROC設(shè)備文件
if(usb_register(&ov7620_driver)<0)//調(diào)用usb_register函數(shù)完成注冊
return-1;
info("ov7620 driver%s registered",version);
return 0;
};
其中ov7620_driver包含了USB攝像頭的相關(guān)信息,并提供了當攝像頭插入拔出時所對應(yīng)的操作,結(jié)構(gòu)如下:
static struct usb_driver ov7620_driver={
.name="ov7620",
.id_table=device_table,
.probe=ov7620_probe,
.disconnect=ov7620_disconnect
};
probe和disconnect是函數(shù)指針。當插入USB攝像頭時,調(diào)用ov7620_probe()函數(shù),主要用來檢測VID和PID,看USB內(nèi)核控制模塊里有沒有匹配的驅(qū)動,如果有向Linux的視頻子系統(tǒng)注冊,并將驅(qū)動實現(xiàn)的系統(tǒng)調(diào)用,掛到內(nèi)核中:
ov7620_probe(struct usb_interface*intf,const struct usb_device_id*id)
{......
if((err_probe=spcaDetectCamera(ov7620))<0)//具體物理設(shè)備查找,匹配廠商號,設(shè)備號
{err("Devices not found!!");goto error;}
……
memcpy(ov7620->vdev,&ov7620_template,sizeof(ov7620_template));
//系統(tǒng)調(diào)用的掛接,在此將驅(qū)動實現(xiàn)的系統(tǒng)調(diào)用,掛到內(nèi)核中
};
當攝像頭從USB總線拔掉,設(shè)備指針會調(diào)用ov7620_disconnect()函數(shù):
static void ov7620_disconnect(struct usb_interface*intf)
{……
if(ov7620->vdev)
video_unregister_device(ov7620->vdev);//注銷video設(shè)備
};
當設(shè)備插入USB總線時,系統(tǒng)會調(diào)用probe函數(shù)探測設(shè)備并把系統(tǒng)調(diào)用掛接到內(nèi)核。上層應(yīng)用程序在獲取設(shè)備句柄以后,可以直接通過系統(tǒng)調(diào)用對設(shè)備進行操作,如read、write等。作為攝像頭驅(qū)動不需要輸出功能,因此在程序中沒有實現(xiàn)write系統(tǒng)調(diào)用。數(shù)據(jù)結(jié)構(gòu)如下:
static struct file_operations ov7620_fops={
.owner=THIS_MODULE,
.open=ov7620_open,//open功能
.release=ov7620_close,//close功能
.read=ov7620_read,//read功能
.mmap=ov7620_mmap,//內(nèi)存映射功能
.ioctl=ov7620_ioctl,//文件信息獲取
};
ov7620_open完成設(shè)備的打開和初始化,并初始化解碼器模塊。其具體實現(xiàn)如下:
static int ov7620_open(struct video_device*vdev,int flags)
{……
err=ov7620_init_source(ov7620);//初始化控制器和傳感器芯片
err=ov7620_init_transfert(ov7620);//初始化URB(usb request block)包,啟動攝像頭,采用同步傳輸?shù)姆绞絺魉蛿?shù)據(jù)
};
ov7620_close函數(shù)主要完成設(shè)備的關(guān)閉,ov7620_mmap和ov7620_read是應(yīng)用程序讀取數(shù)據(jù)的兩個接口函數(shù)。ov7620_mmap通過remap_page_range函數(shù)實現(xiàn)內(nèi)存映射,ov7620_read通過copy_to_user實現(xiàn)用戶空間和內(nèi)核空間的數(shù)據(jù)拷貝,只讀取其中一幀大小的數(shù)據(jù)。
在打開設(shè)備時,需要對硬件進行初始化。攝像頭由兩個主要的芯片組成,圖像傳感器芯片ov7620和橋接芯片SN9C102P。攝像頭的結(jié)構(gòu)框圖如圖1。橋接芯片提供了開放的源代碼,里面提供了對傳感器控制的接口函數(shù),如sn9c102_i2c_write,sn9c102_i2c_read等。利用提供的接口函數(shù)我們就可以對ov7620的寄存器寫值,完成傳感器的初始化工作和圖像采集控制,過程如下:
sn9c102_i2c_write (ov7620->dev,ov7620_sensor_init [i],8)//ov7630_sensor_init是傳感器ov7620寄存器結(jié)構(gòu)。
圖1 攝像頭的結(jié)構(gòu)框圖
在PC機上搭建交叉編譯環(huán)境,系統(tǒng)配置為fedora 7,內(nèi)核2.6.19,安裝的交叉編譯工具為arm-linux-gcc-3.4.1。編譯環(huán)境建立以后,還需要配置Makefile文件,完成后只要在終端里執(zhí)行make命令就可以生成驅(qū)動模塊文件。然后通過超級終端下載到Te2440開發(fā)板上,用insmod命令加載驅(qū)動。在開發(fā)板上運行servfox,在PC機上通過spcaview就可以看到圖像了。
本文對USB攝像頭驅(qū)動程序的開發(fā)過程,進行了簡單的介紹,并介紹了Makefile文件的內(nèi)容。本文程序結(jié)構(gòu)功能相對簡單,在此基礎(chǔ)上可以擴展出一個視頻監(jiān)控系統(tǒng),或者進行圖像處理方面的研究。
[1]Alessandro Rubini,Jonathan Corbet.Linux設(shè)備驅(qū)動程序[M].魏永明,駱 鋼,姜 君譯.北京:中國電力出版社,2002.
[2]劉春成.基于嵌入式Linux的USB攝像頭驅(qū)動開發(fā)[J].計算機工程與設(shè)計,2007,(8):2-3.
[3]魏 武,楊堅銳.嵌入式Linux下USB攝像頭驅(qū)動程序的開發(fā)[J].現(xiàn)代電子技術(shù),2006,(11):3-4.
[4]孫天澤,袁文菊,張海峰.嵌入式設(shè)計及Linux驅(qū)動開發(fā)指南—基于ARM9處理器[M].北京:電子工業(yè)出版社,2005.