LonWorks現(xiàn)場(chǎng)總線設(shè)備驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
(2) 設(shè)備標(biāo)識(shí)方式
本文引用地址:http://www.biyoush.com/article/83666.htmLinux設(shè)備由一個(gè)主設(shè)備號(hào)和一個(gè)次設(shè)備號(hào)標(biāo)識(shí)。主設(shè)備號(hào)唯一標(biāo)識(shí)了設(shè)備類型,即設(shè)備驅(qū)動(dòng)程序類型,它是塊設(shè)備表或字符設(shè)備表中相應(yīng)表項(xiàng)的索引。次設(shè)備號(hào)僅由設(shè)備驅(qū)動(dòng)程序解釋,一般用于識(shí)別在若干可能的硬件設(shè)備中,I/O請(qǐng)求所涉及到的那個(gè)設(shè)備。值得一提的是次設(shè)備號(hào)還可以被分成幾個(gè)部分用來(lái)區(qū)分子設(shè)備驅(qū)動(dòng)程序和具體的設(shè)備。
(3) Linux設(shè)備驅(qū)動(dòng)程序組成部分
Linux設(shè)備驅(qū)動(dòng)程序可以分為三個(gè)主要組成部分:
●自動(dòng)配置和初始化子程序。負(fù)責(zé)檢測(cè)所要驅(qū)動(dòng)的硬件設(shè)備是否存在和是否能正常工作。如果該設(shè)備正常,則對(duì)這個(gè)設(shè)備及其相關(guān)的、設(shè)備驅(qū)動(dòng)程序需要的軟硬件進(jìn)行初始化。
● 服務(wù)于I/O請(qǐng)求的子程序。它們主要是對(duì)file_operations結(jié)構(gòu)的各個(gè)入口點(diǎn)的實(shí)現(xiàn)。這部分的實(shí)現(xiàn)支持了文件系統(tǒng)的調(diào)用(如open,close, read等等)。
●中斷服務(wù)子程序。在Linux系統(tǒng)中,并不是直接從中斷向量表中調(diào)用設(shè)備驅(qū)動(dòng)程序的中斷服務(wù)子程序,而是由Linux系統(tǒng)來(lái)接收硬件中斷,再由系統(tǒng)來(lái)調(diào)用中斷服務(wù)子程序。
但是,這三個(gè)部分不是必須在每個(gè)驅(qū)動(dòng)程序中必須具有的。
3.3 LonWorks現(xiàn)場(chǎng)總線網(wǎng)卡驅(qū)動(dòng)程序
研究了Linux的設(shè)備管理以及設(shè)備驅(qū)動(dòng)程序?qū)崿F(xiàn)方法后,我們來(lái)設(shè)計(jì)LonWorks現(xiàn)場(chǎng)總線設(shè)備驅(qū)動(dòng)程序,并對(duì)實(shí)現(xiàn)中的一些關(guān)鍵問(wèn)題進(jìn)行探討。
(1) LonWorks現(xiàn)場(chǎng)總線網(wǎng)卡驅(qū)動(dòng)程序
在驅(qū)動(dòng)程序設(shè)計(jì)和開(kāi)發(fā)中,我們一定要注意的問(wèn)題是機(jī)制(Mechanism)與策略(Policy)的分離。這里所謂的機(jī)制是指我們的驅(qū)動(dòng)程序提供的接口應(yīng)該很忠實(shí)地反映設(shè)備的原始功能(bare function),而與應(yīng)用無(wú)關(guān)。而策略是指一旦這個(gè)設(shè)備驅(qū)動(dòng)程序?yàn)樵O(shè)備機(jī)制提供了相應(yīng)的軟件接口,那么應(yīng)用程序開(kāi)發(fā)人員就能按照特定的方式使用機(jī)制接口。可以說(shuō),在內(nèi)核驅(qū)動(dòng)程序開(kāi)發(fā)過(guò)程中,所設(shè)計(jì)的數(shù)據(jù)結(jié)構(gòu),以及確定的接口命令都是為以后的應(yīng)用策略提供的一種機(jī)制。而如前所述,這種機(jī)制在Unix類系統(tǒng)內(nèi)部是通過(guò)一組固定的入口點(diǎn)來(lái)提供的。由于我們要開(kāi)發(fā)的設(shè)備驅(qū)動(dòng)程序是一個(gè)字符型的設(shè)備,所以接下來(lái)我們首先分析字符型設(shè)備驅(qū)動(dòng)程序中常用的入口點(diǎn):
● open入口點(diǎn)
打開(kāi)設(shè)備準(zhǔn)備I/O操作。對(duì)字符設(shè)備文件進(jìn)行打開(kāi)操作,都會(huì)調(diào)用設(shè)備的open入口點(diǎn)。open子程序必須對(duì)將要進(jìn)行的I/O操作做好必要的準(zhǔn)備工作,如清除緩沖區(qū)等。如果設(shè)備是獨(dú)占的,即同一時(shí)刻只能有一個(gè)程序訪問(wèn)此設(shè)備,則open子程序必須設(shè)置一些標(biāo)志以表示設(shè)備處于忙狀態(tài)。
●release入口點(diǎn)
關(guān)閉一個(gè)設(shè)備。當(dāng)最后一次使用設(shè)備終結(jié)后,調(diào)用release子程序。獨(dú)占設(shè)備必須改變前由open子程序設(shè)置的標(biāo)志,以便設(shè)備可再次被使用。
●read入口點(diǎn)
從設(shè)備上讀數(shù)據(jù)。對(duì)于有緩沖區(qū)的I/O操作,一般是從緩沖區(qū)里讀數(shù)據(jù)。對(duì)字符設(shè)備文件進(jìn)行讀操作將調(diào)用read子程序。
●write入口點(diǎn)
往設(shè)備上寫(xiě)數(shù)據(jù)。對(duì)于有緩沖區(qū)的I/O操作,一般是把數(shù)據(jù)寫(xiě)入緩沖區(qū)里。對(duì)字符設(shè)備文件進(jìn)行寫(xiě)操作將調(diào)用write子程序。
● ioctl入口點(diǎn)
執(zhí)行讀、寫(xiě)之外的一些硬件控制操作。
●poll入口點(diǎn)
把對(duì)許多非阻塞操作的設(shè)備描述符集合起來(lái),等待事件的發(fā)生,以便于集中檢查,看數(shù)據(jù)是否可從設(shè)備讀取或設(shè)備是否可用于寫(xiě)數(shù)據(jù),這樣就做到了所謂的多路復(fù)用。
以上入口點(diǎn)構(gòu)成了設(shè)備驅(qū)動(dòng)程序的三大組成部分中I/O請(qǐng)求的部分,在Linux中它們由file_operations結(jié)構(gòu)來(lái)封裝,并不是所有的字符設(shè)備驅(qū)動(dòng)程序都必須提供以上每一個(gè)入口點(diǎn)的實(shí)現(xiàn),如果設(shè)備驅(qū)動(dòng)程序沒(méi)有提供上述入口點(diǎn)中的某幾個(gè),系統(tǒng)會(huì)用缺省的子程序來(lái)代替。
由上面的描述可見(jiàn),在內(nèi)核設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)中,相應(yīng)的機(jī)制的提供主要是對(duì)設(shè)備入口點(diǎn)的選擇和設(shè)計(jì)。
針對(duì)LonWorks現(xiàn)場(chǎng)總線網(wǎng)卡的特點(diǎn),我們選擇并實(shí)現(xiàn)了五個(gè)入口點(diǎn),即open, release, read,write, ioctl。
對(duì)于open和release入口點(diǎn)由于設(shè)備特點(diǎn),我們只需要控制設(shè)備驅(qū)動(dòng)模塊在使用時(shí),不被異常釋放即可。
接下來(lái),我們將描述以上設(shè)計(jì)實(shí)現(xiàn)中與Linux內(nèi)核相關(guān)的一些調(diào)用和問(wèn)題。
(2) 對(duì)file_operations結(jié)構(gòu)的初始化
file_operations結(jié)構(gòu)是Linux操作系統(tǒng)中用于實(shí)現(xiàn)驅(qū)動(dòng)程序的最重要的數(shù)據(jù)結(jié)構(gòu),我們已經(jīng)在前面提到過(guò),它對(duì)Linux提供I/O請(qǐng)求的子程序的一系列入口點(diǎn)進(jìn)行了封裝。該結(jié)構(gòu)貫穿在整個(gè)驅(qū)動(dòng)程序中,故我們?cè)谖募饔糜騼?nèi)定義了它的一個(gè)變量,并對(duì)本程序中用到的入口點(diǎn)做了初始化,其代碼如下:
struct file_operations lmdev_fops= {
NULL,
lmdev_read,
//把實(shí)現(xiàn)的lmdev_read函數(shù)指針賦給read入口點(diǎn)。
lmdev_write,
//把實(shí)現(xiàn)的lmdev_write函數(shù)指針賦給write入口點(diǎn)。
NULL,
NULL,
lmdev_ioctl,
//把實(shí)現(xiàn)的lmdev_ioctl函數(shù)指針賦給ioctl入口點(diǎn)。
NULL,
lmdev_open,
//把實(shí)現(xiàn)的lmdev_ open函數(shù)指針賦給open入口點(diǎn)。
lmdev_release,
//把實(shí)現(xiàn)的lmdev_release函數(shù)指針賦給release入口點(diǎn)。
NULL,
NULL,
NULL,
NULL,
};
對(duì)于lmdev-*函數(shù)的實(shí)現(xiàn)方法,我們將在后面做詳細(xì)的討論。
評(píng)論