嵌入式單片機(jī)原理第十章_第1頁(yè)
嵌入式單片機(jī)原理第十章_第2頁(yè)
嵌入式單片機(jī)原理第十章_第3頁(yè)
嵌入式單片機(jī)原理第十章_第4頁(yè)
嵌入式單片機(jī)原理第十章_第5頁(yè)
已閱讀5頁(yè),還剩98頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

嵌入式單片機(jī)原理第十章第一頁(yè),共103頁(yè)。一、嵌入式Linux驅(qū)動(dòng)概述

設(shè)備驅(qū)動(dòng)是操作系統(tǒng)內(nèi)核中最接近硬件設(shè)備,是操作系統(tǒng)內(nèi)核和底層硬件設(shè)備之間的接口。也就是說(shuō),操作系統(tǒng)內(nèi)核就是通過(guò)調(diào)用這些接口函數(shù)來(lái)完成對(duì)底層硬件設(shè)備的使用。那么應(yīng)用程序怎樣使用底層的硬件平臺(tái)呢?前面講過(guò),在操作系統(tǒng)和應(yīng)用程序之間也有很多接口函數(shù),這些接口函數(shù)為應(yīng)用程序使用操作系統(tǒng)內(nèi)核提供了窗口,我們稱這些接口函數(shù)為系統(tǒng)調(diào)用。Linux驅(qū)動(dòng)基本原理系統(tǒng)調(diào)用是操作系統(tǒng)內(nèi)核和應(yīng)用程序之間的接口,設(shè)備驅(qū)動(dòng)程序是操作系統(tǒng)內(nèi)核和機(jī)器硬件之間的接口。它們都有一個(gè)共同的特點(diǎn):屏蔽了底層的某個(gè)具體服務(wù)的實(shí)現(xiàn)細(xì)節(jié),比如,系統(tǒng)調(diào)用屏蔽了操作系統(tǒng)內(nèi)核某個(gè)具體功能的實(shí)現(xiàn)細(xì)節(jié),設(shè)備驅(qū)動(dòng)程序則屏蔽了底層硬件設(shè)備的細(xì)節(jié)。第二頁(yè),共103頁(yè)。具體來(lái)說(shuō),在Linux中設(shè)備是被當(dāng)做文件來(lái)進(jìn)行處理的。上層的應(yīng)用程序需要操作硬件時(shí),只需要獲得設(shè)備的文件描述符,然后通過(guò)系統(tǒng)調(diào)用open(),read(),write(),ioctl(),close()等來(lái)操作設(shè)備,這與一般普通的文件操作非常類似。應(yīng)用程序不關(guān)心無(wú)需關(guān)心硬件的細(xì)節(jié)。應(yīng)用程序發(fā)出系統(tǒng)調(diào)用指令后,會(huì)從用戶態(tài)轉(zhuǎn)換為內(nèi)核態(tài),通過(guò)內(nèi)核將系統(tǒng)調(diào)用函數(shù)轉(zhuǎn)換成對(duì)物理設(shè)備的操作。如圖所示了應(yīng)用程序使用底層的設(shè)備接口示意圖,從中可以看出,設(shè)備驅(qū)動(dòng)層起到了承上啟下的作用。一、嵌入式Linux驅(qū)動(dòng)概述Linux驅(qū)動(dòng)基本原理第三頁(yè),共103頁(yè)。常見(jiàn)的驅(qū)動(dòng)程序也是作為內(nèi)核模塊動(dòng)態(tài)加載的,比如聲卡驅(qū)動(dòng)和網(wǎng)卡驅(qū)動(dòng)等,而Linux最基礎(chǔ)的驅(qū)動(dòng),如CPU、PCI總線、TCP/IP協(xié)議、APM(高級(jí)電源管理)、VFS等驅(qū)動(dòng)程序則直接編譯在內(nèi)核文件中。有時(shí)也把內(nèi)核模塊叫做驅(qū)動(dòng)程序,只不過(guò)驅(qū)動(dòng)的內(nèi)容不一定是硬件罷了,比如ext3文件系統(tǒng)的驅(qū)動(dòng)。因此,加載驅(qū)動(dòng)時(shí)就是加載內(nèi)核模塊。

一、嵌入式Linux驅(qū)動(dòng)概述Linux驅(qū)動(dòng)基本原理第四頁(yè),共103頁(yè)。作為程序開(kāi)發(fā)者,從上圖可以看出,處于設(shè)備驅(qū)動(dòng)層的Linux驅(qū)動(dòng)程序?yàn)閼?yīng)用程序提供了訪問(wèn)硬件設(shè)備的編程接口(ApplicationProgrammingInterface,API),它是真?zhèn)€設(shè)備驅(qū)動(dòng)的核心內(nèi)容。驅(qū)動(dòng)程序主要提供以下功能:應(yīng)用程序通過(guò)驅(qū)動(dòng)程序安全有效地訪問(wèn)硬件;驅(qū)動(dòng)程序作為嵌入式系統(tǒng)的中間層軟件,它隱藏了底層的細(xì)節(jié),從而提高了軟件的可移植性和可復(fù)用性;驅(qū)動(dòng)程序文件節(jié)點(diǎn)可以方便地提供訪問(wèn)權(quán)限控制。一、嵌入式Linux驅(qū)動(dòng)概述Linux驅(qū)動(dòng)功能第五頁(yè),共103頁(yè)。從下層驅(qū)動(dòng)開(kāi)發(fā)人員的角度來(lái)看,Linux驅(qū)動(dòng)程序就是通過(guò)直接操控硬件的軟件,來(lái)完成下面的功能:對(duì)設(shè)備初始化和釋放;直接讀寫硬件寄存器來(lái)控制硬件;把數(shù)據(jù)從內(nèi)核傳送到硬件和從硬件讀取數(shù)據(jù);操作設(shè)備緩沖區(qū)設(shè)備;操作輸入、輸出設(shè)備,如鍵盤、打印機(jī)等;讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)和回送應(yīng)用程序請(qǐng)求的數(shù)據(jù);檢測(cè)和處理設(shè)備出現(xiàn)的錯(cuò)誤。一、嵌入式Linux驅(qū)動(dòng)概述Linux驅(qū)動(dòng)功能第六頁(yè),共103頁(yè)。Linux的一個(gè)重要特點(diǎn)就是將所有的設(shè)備都當(dāng)做文件進(jìn)行處理,這一類特殊文件就是設(shè)備文件,它們可以使用前面提到的文件、I/O相關(guān)函數(shù)進(jìn)行操作,這樣就大大方便了對(duì)設(shè)備的處理。它通常在“/dev”下面存在一個(gè)對(duì)應(yīng)的邏輯設(shè)備節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)以文件的形式存在。二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)Linux設(shè)備管理機(jī)制第七頁(yè),共103頁(yè)。Linux系統(tǒng)的設(shè)備文件分為四類:塊設(shè)備文件、字符設(shè)備文件、網(wǎng)絡(luò)設(shè)備文件和雜項(xiàng)設(shè)備文件。塊設(shè)備文件:通常指一些需要以塊(如512字節(jié))的方式寫入的設(shè)備,如IDE硬盤、SCSI硬盤、光驅(qū)等;字符型設(shè)備文件:通常指可以直接讀寫,沒(méi)有緩沖區(qū)的設(shè)備,如并口、虛擬控制臺(tái)等;網(wǎng)絡(luò)設(shè)備文件:通常是指網(wǎng)絡(luò)設(shè)備訪問(wèn)的BSDsocket接口,如網(wǎng)卡等;雜項(xiàng)設(shè)備文件:通常指的是比較特殊的驅(qū)動(dòng)程序,如IIC、USB等。二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)設(shè)備分類第八頁(yè),共103頁(yè)。設(shè)備號(hào)是一個(gè)數(shù)字,它是設(shè)備的標(biāo)志。就如前面所述,一個(gè)設(shè)備文件(也就是設(shè)備節(jié)點(diǎn))可以通過(guò)mknod命令來(lái)創(chuàng)建,其中指定了主設(shè)備號(hào)和次設(shè)備號(hào)。主設(shè)備號(hào)表明某一類設(shè)備,用于標(biāo)識(shí)設(shè)備對(duì)應(yīng)的驅(qū)動(dòng)程序,一般對(duì)應(yīng)著確定的驅(qū)動(dòng)程序,主設(shè)備號(hào)相同的設(shè)備使用相同的驅(qū)動(dòng)程序;次設(shè)備號(hào)一般是用于區(qū)分標(biāo)明不同屬性(例如不同的使用方法,不同的位置,不同的操作等),它標(biāo)志著某個(gè)具體的物理設(shè)備。次設(shè)備號(hào)是一個(gè)8位數(shù),用來(lái)區(qū)分具體設(shè)備的實(shí)例。因此,同一臺(tái)機(jī)器上如果有兩個(gè)相同的設(shè)備,則它們的主設(shè)備號(hào)相同,但第一個(gè)設(shè)備的次設(shè)備號(hào)為0,而第二個(gè)設(shè)備的次設(shè)備號(hào)為1。一般,高字節(jié)為主設(shè)備號(hào)和底字節(jié)為次設(shè)備號(hào)。例如,在系統(tǒng)中的塊設(shè)備IDE硬盤的主設(shè)備號(hào)是3,而多個(gè)IDE硬盤及其各個(gè)分區(qū)分別賦予次設(shè)備號(hào)1、2、3……二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)設(shè)備號(hào)第九頁(yè),共103頁(yè)。Linux設(shè)備的設(shè)備號(hào)由主、次設(shè)備號(hào)構(gòu)成,如果已經(jīng)知道某設(shè)備的主、次設(shè)備號(hào),可以利用MKDEV()宏來(lái)合成設(shè)備號(hào)。該宏定義如下(位于include/linux/kdev_t.h中): #defineMKDEV(ma,mi) ((ma)<<8|(mi))從宏定義可以看出,設(shè)備號(hào)高位存放著設(shè)備的主設(shè)備號(hào),低8位存放著設(shè)備的次設(shè)備號(hào)。如果已知設(shè)備的設(shè)備號(hào),可以利用MAJOR()和MINOR()宏來(lái)將該設(shè)備的主、次設(shè)備號(hào)分離出來(lái)。該宏定義如下: #defineMAJOR(dev) ((dev)>>8) #defineMINOR(dev) ((dev)&0xff)Linux系統(tǒng)下,有關(guān)主設(shè)備號(hào)的分配原則,可以參看Documentation/Device.txt。二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)設(shè)備號(hào)第十頁(yè),共103頁(yè)。Linux驅(qū)動(dòng)程序可以通過(guò)兩種方式集成到內(nèi)核中去:一是將其直接編譯到內(nèi)核;二是將其編寫成模塊,在需要添加某種硬件的時(shí)候,內(nèi)核可以將其調(diào)入。在配置Linux內(nèi)核時(shí),可以選擇“Enableloadablemodulesupport”選項(xiàng),來(lái)支持可加載內(nèi)核模塊。二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)內(nèi)核模塊前一種方法將驅(qū)動(dòng)程序直接寫入內(nèi)核,其優(yōu)點(diǎn)是用戶可以隨時(shí)地進(jìn)行調(diào)用而無(wú)需安裝。但是這樣會(huì)大大增加內(nèi)核占用的空間,導(dǎo)致內(nèi)核體積較大。

第十一頁(yè),共103頁(yè)。后一種方法將驅(qū)動(dòng)程序編寫成模塊供內(nèi)核有選擇性地加載,雖然會(huì)因?yàn)閷ふ因?qū)動(dòng)模塊而增加系統(tǒng)資源的占用和運(yùn)行時(shí)間,但是與龐大的內(nèi)核所消耗的資源相比顯得微不足道。另外,這種可加載的內(nèi)核模塊還可以為軟件開(kāi)發(fā)提供許多便利。當(dāng)用戶需要對(duì)某一硬件驅(qū)動(dòng)程序進(jìn)行開(kāi)發(fā)或者糾錯(cuò)時(shí),用戶可以動(dòng)態(tài)地卸載舊的版本并加載新的版本,但是如果用戶的驅(qū)動(dòng)程序已經(jīng)寫入內(nèi)核,那么必須對(duì)內(nèi)核進(jìn)行重新編譯,并且每次對(duì)修改后的程序進(jìn)行測(cè)試時(shí),都必須重新啟動(dòng)系統(tǒng)。顯然,后者在時(shí)間和精力上花費(fèi)更大。如果將驅(qū)動(dòng)程序視為可加載的內(nèi)核模塊進(jìn)行開(kāi)發(fā)和配置,用戶就可以將硬件驅(qū)動(dòng)程序作為一種獨(dú)立的系統(tǒng)進(jìn)行升級(jí),而不必頻繁地對(duì)內(nèi)核進(jìn)行改動(dòng)了。

二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)內(nèi)核模塊第十二頁(yè),共103頁(yè)。可加載的內(nèi)核模塊通常情況下安裝在系統(tǒng)“/lib/modules”目錄的一個(gè)子目錄下。我們可以通過(guò)通過(guò)模塊加載或者卸載命令來(lái)對(duì)模塊進(jìn)行管理。二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)內(nèi)核模塊常用的模塊相關(guān)命令列表另外,注意Linux2.6內(nèi)核對(duì)可加載內(nèi)核模塊規(guī)定了新的命名方法,使用的是“.ko”擴(kuò)展名,而不是Linux2.4內(nèi)核采用的“.o”擴(kuò)展名。

第十三頁(yè),共103頁(yè)。Linux設(shè)備驅(qū)動(dòng)程序包含中斷處理程序和設(shè)備服務(wù)子程序兩部分:設(shè)備服務(wù)子程序包含了所有與設(shè)備操作相關(guān)的處理代碼。它從面向用戶進(jìn)程的設(shè)備文件系統(tǒng)中接受用戶命令,并對(duì)設(shè)備控制器執(zhí)行操作。這樣,設(shè)備驅(qū)動(dòng)程序屏蔽了設(shè)備的特殊性,使用戶可以像對(duì)待文件一樣操作設(shè)備。設(shè)備控制器需要獲得系統(tǒng)服務(wù)時(shí)有兩種方式:查詢和中斷。因?yàn)長(zhǎng)inux下的設(shè)備驅(qū)動(dòng)程序是內(nèi)核的一部分,在設(shè)備查詢期間系統(tǒng)不能運(yùn)行其他代碼,查詢方式的工作效率比較低,所以只有少數(shù)設(shè)備如軟盤驅(qū)動(dòng)程序采取這種方式,大多設(shè)備以中斷方式向設(shè)備驅(qū)動(dòng)程序發(fā)出輸入/輸出請(qǐng)求。Linux的輸入/輸出系統(tǒng)的各層次結(jié)構(gòu)和功能,如圖:二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)驅(qū)動(dòng)層次結(jié)構(gòu)Linux輸入/輸出系統(tǒng)層次結(jié)構(gòu)和功能

第十四頁(yè),共103頁(yè)。Linux設(shè)備驅(qū)動(dòng)程序與外界的接口可以分為如下三個(gè)部分:驅(qū)動(dòng)程序與操作系統(tǒng)內(nèi)核的接口:這是通過(guò)數(shù)據(jù)結(jié)構(gòu)(在本書后面會(huì)有詳細(xì)介紹)來(lái)完成的。驅(qū)動(dòng)程序與系統(tǒng)引導(dǎo)的接口:這部分利用驅(qū)動(dòng)程序?qū)υO(shè)備進(jìn)行初始化。驅(qū)動(dòng)程序與設(shè)備的接口:這部分描述了驅(qū)動(dòng)程序如何與設(shè)備進(jìn)行交互,這與具體設(shè)備密切相關(guān)。二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)設(shè)備驅(qū)動(dòng)程序與外界接口第十五頁(yè),共103頁(yè)。它們之間的相互關(guān)系如下圖:二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)設(shè)備驅(qū)動(dòng)程序與外界接口第十六頁(yè),共103頁(yè)。二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)設(shè)備驅(qū)動(dòng)程序的特點(diǎn)綜上所述,Linux中的設(shè)備驅(qū)動(dòng)程序有如下特點(diǎn):內(nèi)核代碼 設(shè)備驅(qū)動(dòng)程序是內(nèi)核的一部分,如果驅(qū)動(dòng)程序出錯(cuò),則可能導(dǎo)致系統(tǒng)崩潰。內(nèi)核接口 設(shè)備驅(qū)動(dòng)程序必須為內(nèi)核或者其子系統(tǒng)提供一個(gè)標(biāo)準(zhǔn)接口。比如,一個(gè)終端驅(qū)動(dòng)程序必須為內(nèi)核提供一個(gè)文件I/O接口;一個(gè)SCSI設(shè)備驅(qū)動(dòng)程序應(yīng)該為SCSI子系統(tǒng)提供一個(gè)SCSI設(shè)備接口,同時(shí)SCSI子系統(tǒng)也必須為內(nèi)核提供文件的I/O接口及緩沖區(qū)。內(nèi)核機(jī)制和服務(wù) 設(shè)備驅(qū)動(dòng)程序使用一些標(biāo)準(zhǔn)的內(nèi)核服務(wù),如內(nèi)存分配等??裳b載 大多數(shù)的Linux操作系統(tǒng)設(shè)備驅(qū)動(dòng)程序都可以在需要時(shí)裝載進(jìn)內(nèi)核,在不需要時(shí)從內(nèi)核中卸載??稍O(shè)置 Linux操作系統(tǒng)設(shè)備驅(qū)動(dòng)程序可以集成為內(nèi)核的一部分,并可以根據(jù)需要把其中的某一部分集成到內(nèi)核中,這只需要在系統(tǒng)編譯時(shí)進(jìn)行相應(yīng)的設(shè)置即可。動(dòng)態(tài)性 在系統(tǒng)啟動(dòng)且各個(gè)設(shè)備驅(qū)動(dòng)程序初始化后,驅(qū)動(dòng)程序?qū)⒕S護(hù)其控制的設(shè)備。如果該設(shè)備驅(qū)動(dòng)程序控制的設(shè)備不存在也不影響系統(tǒng)的運(yùn)行,那么此時(shí)的設(shè)備驅(qū)動(dòng)程序只是多占用了一點(diǎn)系統(tǒng)內(nèi)存而已。第十七頁(yè),共103頁(yè)。可裝載 大多數(shù)的Linux操作系統(tǒng)設(shè)備驅(qū)動(dòng)程序都可以在需要時(shí)裝載進(jìn)內(nèi)核,在不需要時(shí)從內(nèi)核中卸載??稍O(shè)置 Linux操作系統(tǒng)設(shè)備驅(qū)動(dòng)程序可以集成為內(nèi)核的一部分,并可以根據(jù)需要把其中的某一部分集成到內(nèi)核中,這只需要在系統(tǒng)編譯時(shí)進(jìn)行相應(yīng)的設(shè)置即可。動(dòng)態(tài)性 在系統(tǒng)啟動(dòng)且各個(gè)設(shè)備驅(qū)動(dòng)程序初始化后,驅(qū)動(dòng)程序?qū)⒕S護(hù)其控制的設(shè)備。如果該設(shè)備驅(qū)動(dòng)程序控制的設(shè)備不存在也不影響系統(tǒng)的運(yùn)行,那么此時(shí)的設(shè)備驅(qū)動(dòng)程序只是多占用了一點(diǎn)系統(tǒng)內(nèi)存而已。二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)設(shè)備驅(qū)動(dòng)程序的特點(diǎn)第十八頁(yè),共103頁(yè)。以往在開(kāi)發(fā)應(yīng)用程序時(shí)都有一個(gè)main函數(shù)作為程序的入口點(diǎn),而在驅(qū)動(dòng)開(kāi)發(fā)時(shí)卻沒(méi)有main函數(shù),模塊在調(diào)用insmod命令時(shí)被加載,此時(shí)的入口點(diǎn)是init_module函數(shù),通常在該函數(shù)中完成設(shè)備的注冊(cè)。同樣,模塊在調(diào)用rmmod函數(shù)時(shí)被卸載,此時(shí)的入口點(diǎn)是cleanup_module函數(shù),在該函數(shù)中完成設(shè)備的卸載。在設(shè)備完成注冊(cè)加載之后,用戶的應(yīng)用程序就可以對(duì)該設(shè)備進(jìn)行一定的操作,如read、write等,而驅(qū)動(dòng)程序就是用于實(shí)現(xiàn)這些操作,在用戶應(yīng)用程序調(diào)用相應(yīng)入口函數(shù)時(shí)執(zhí)行相關(guān)的操作,init_module入口點(diǎn)函數(shù)則不需要完成其他如read、write之類功能。二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)驅(qū)動(dòng)開(kāi)發(fā)流程第十九頁(yè),共103頁(yè)。Linux驅(qū)動(dòng)程序編寫流程如圖:二、設(shè)備驅(qū)動(dòng)的基礎(chǔ)知識(shí)驅(qū)動(dòng)開(kāi)發(fā)流程第二十頁(yè),共103頁(yè)。Linux內(nèi)核是“單內(nèi)核”結(jié)構(gòu),這個(gè)單內(nèi)核由很多模塊構(gòu)成,每個(gè)模塊完成內(nèi)核一部分的功能,比如TCP/IP協(xié)議棧模塊完成網(wǎng)絡(luò)協(xié)議功能,文件系統(tǒng)模塊完成文件管理功能等等。使用模塊的好處是可以根據(jù)用戶的需要隨意裁減Linux系統(tǒng),使得整個(gè)系統(tǒng)恰好適應(yīng)產(chǎn)品的需要。正是具有這樣的特點(diǎn),Linux被廣泛應(yīng)用在嵌入式產(chǎn)品設(shè)計(jì)中。但是這里我們要指出的是Linux內(nèi)核中的模塊機(jī)制不同于微內(nèi)核中的模塊機(jī)制。在微內(nèi)核中,模塊處于用戶空間;而在Linux中,模塊位于內(nèi)核中,用戶可以通過(guò)insmod等工具將一段代碼加入到內(nèi)核中,也可以在不需要它的時(shí)候,調(diào)用rmmod工具將其調(diào)出內(nèi)核。

三、模塊編程模塊與內(nèi)核第二十一頁(yè),共103頁(yè)。內(nèi)核和模塊之間的關(guān)系見(jiàn)圖:三、模塊編程模塊與內(nèi)核第二十二頁(yè),共103頁(yè)。在Linux內(nèi)核中使用模的好處是:模塊化編程的需要,降低開(kāi)發(fā)和維護(hù)成本。增強(qiáng)系統(tǒng)的靈活性,使得修改一些內(nèi)核功能而不必重新編譯內(nèi)核和重啟系統(tǒng)。降低內(nèi)核編程的復(fù)雜性,使入門門檻降低。

三、模塊編程模塊與內(nèi)核在進(jìn)行模塊設(shè)計(jì)的時(shí)候,必須遵循Linux的標(biāo)準(zhǔn),否則無(wú)法通過(guò)Linux的insmod運(yùn)載工具將其加入到內(nèi)核中。簡(jiǎn)單來(lái)說(shuō),一個(gè)最基本的內(nèi)核模塊一般都包含有兩個(gè)函數(shù),一個(gè)是初始化函數(shù)(比如下面例子中hello_init),一個(gè)是卸載函數(shù)(hello_exit),當(dāng)然也可以沒(méi)有任何函數(shù),只是提供一些變量。一般來(lái)說(shuō),模塊代碼中必須具有初始化函數(shù)和卸載函數(shù),除此之外,還可以包含其它函數(shù)。宏module_init和module_exit用于注冊(cè)初始化函數(shù)和卸載函數(shù)。

第二十三頁(yè),共103頁(yè)。首先,新建一個(gè)文件,保存為hello.c,在文件中輸入源碼。三、模塊編程實(shí)例該模塊主要是用來(lái)說(shuō)明Linux內(nèi)核驅(qū)動(dòng)模塊程序的一些基本特點(diǎn)。該內(nèi)核模塊中主要定義了hello_init和hello_exit兩個(gè)函數(shù),并且在文件的后面用module_init和module_exit包含起來(lái)。module_init和module_exit為內(nèi)核特殊的宏,用來(lái)定義模塊被裝載和卸載時(shí)分別調(diào)用的函數(shù)。當(dāng)模塊被裝載進(jìn)內(nèi)核時(shí)將自動(dòng)調(diào)用hello_init函數(shù),當(dāng)該模塊被卸載時(shí)將自動(dòng)調(diào)用hello_exit函數(shù)。最后一行用MODULE_LICENSE宏來(lái)聲明該模塊的許可協(xié)議,該模塊聲明為GPL(GeneralPublicLicense)許可協(xié)議。第二十四頁(yè),共103頁(yè)。該模塊主要是用來(lái)說(shuō)明Linux內(nèi)核驅(qū)動(dòng)模塊程序的一些基本特點(diǎn)。該內(nèi)核模塊中主要定義了hello_init和hello_exit兩個(gè)函數(shù),并且在文件的后面用module_init和module_exit包含起來(lái)。module_init和module_exit為內(nèi)核特殊的宏,用來(lái)定義模塊被裝載和卸載時(shí)分別調(diào)用的函數(shù)。當(dāng)模塊被裝載進(jìn)內(nèi)核時(shí)將自動(dòng)調(diào)用hello_init函數(shù),當(dāng)該模塊被卸載時(shí)將自動(dòng)調(diào)用hello_exit函數(shù)。最后一行用MODULE_LICENSE宏來(lái)聲明該模塊的許可協(xié)議,該模塊聲明為GPL(GeneralPublicLicense)許可協(xié)議。三、模塊編程編寫makefile第二十五頁(yè),共103頁(yè)。為這個(gè)模塊程序?qū)懸粋€(gè)makefile文件,這個(gè)文件是基于PC機(jī)器上的模塊,所以Makefile內(nèi)容如下:

MODFLAGS=-Wall-DMODULE-D__KERNEL__-DLINUX-I/usr/src/linux-2.6.29/include-c–ohello.o:hello.cgcc$(MODFLAGS)$@$<三、模塊編程編寫makefile第二十六頁(yè),共103頁(yè)。程序說(shuō)明:-D__KERNEL__:該參數(shù)告訴編譯器此代碼將在內(nèi)核模塊中運(yùn)行,而不是用戶進(jìn)程。-DMODULE:該參數(shù)告訴編譯器要給出適當(dāng)?shù)膬?nèi)核模塊的定義。-DLINUX:從技術(shù)上講,這個(gè)標(biāo)志不是必要的。但是,如果希望寫一個(gè)比較正規(guī)的內(nèi)核模塊,在多個(gè)操作系統(tǒng)上編譯,這個(gè)標(biāo)志將會(huì)使你感到方便。它可以允許你在獨(dú)立于操作系統(tǒng)的部分進(jìn)行常規(guī)的編譯。另外,此處用-I參數(shù)告訴編譯器使用/usr/src/linux-2.6.29/include目錄下的頭文件,如果不加該參數(shù),則gcc默認(rèn)使用/usr/include下的頭文件,這樣會(huì)產(chǎn)生版本等問(wèn)題,這里不同的版本可能會(huì)不一樣。三、模塊編程編寫makefile第二十七頁(yè),共103頁(yè)。基于ARM的模塊,Makefile內(nèi)容如下: MODFLAGS=-Wall-DMODULE-D__KERNEL__-DLINUX-I/usr/src/linux-2.6.29/include-c–o hello.o:hello.c arm-linux-gcc$(MODFLAGS)$@$<三、模塊編程編寫makefile第二十八頁(yè),共103頁(yè)。(1)insmodhello.o當(dāng)我們使用insmodhello.o命令加載hello模塊時(shí),內(nèi)核至少完成下列幾件任務(wù):將hello.o代碼搬運(yùn)到內(nèi)核中創(chuàng)建structmodule變量,并為相應(yīng)成員變量賦值,其中name為模塊名hello,init函數(shù)指針指向hello_init函數(shù),cleanup函數(shù)指針指向hello_exit函數(shù)執(zhí)行init函數(shù)指針?biāo)赶虻暮瘮?shù),具體命令如下 insmodhello.o三、模塊編程模塊加載第二十九頁(yè),共103頁(yè)。(2)查看模塊查看模塊可以使用lsmod命令,當(dāng)使用lsmod命令時(shí),將會(huì)掃描整個(gè)模塊鏈,并將其信息輸出。三、模塊編程模塊加載(3)rmmodhello如果要將在內(nèi)核中的模塊卸載,使用rmmod命令可以完成這個(gè)工作。具體命令如下:#rmmodhello.o上面刪除模塊命令,將完成下面幾個(gè)任務(wù):執(zhí)行cleanup函數(shù)指針?biāo)赶虻暮瘮?shù),主要是完成清理干凈該模塊在內(nèi)核中的垃圾將hello模塊代碼清除出內(nèi)核將描述hello模塊的變量從鏈表中刪除第三十頁(yè),共103頁(yè)。比較常用信息常常包括:作者、描述、版權(quán)等,可以使用如下宏進(jìn)行定義。

MODULE_AUTHOR("author"); MODULE_DESCRIPTION("thedescription"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("dev");//設(shè)備驅(qū)動(dòng)程序所支持的設(shè)備。比較常用的Freelicense有"GPL","GPLv2","GPLandadditionalrights","DualBSD/GPL","DualMPL/GPL"。

三、模塊編程模塊其他信息第三十一頁(yè),共103頁(yè)。用戶空間的應(yīng)用程序可以接受用戶的參數(shù),那么將模塊辦運(yùn)到內(nèi)核中時(shí),也是可以帶進(jìn)參數(shù)的,只是方式有些不同而已。相關(guān)的宏主要有:

MODULE_PARM(var,type); MODULE_PARM_DESC(var,"thedescriptionofthevar");

模塊參數(shù)的類型(即MODULE_PARM中的type)有一下幾種:

bbyte(unsignedchar) hshort iint llong sstring(char*)這些參數(shù)最好有默認(rèn)值,如果有些必要參數(shù)用戶沒(méi)有設(shè)置可以通過(guò)在module_init指定的init函數(shù)返回負(fù)值來(lái)拒絕模塊的加載。LKM還支持?jǐn)?shù)組類型的模塊,如果在類型符號(hào)前加上數(shù)字n則表示最大程度為n的數(shù)組,用“-”隔開(kāi)的數(shù)字分別代表最小和最大的數(shù)組長(zhǎng)度。三、模塊編程模塊參數(shù)第三十二頁(yè),共103頁(yè)。例如如下參數(shù):

MODULE_PARM(var,"4i");//最大長(zhǎng)度為4的整形數(shù)組

MODULE_PARM(var,"2-6i");//最小長(zhǎng)度為2,最大長(zhǎng)度為6的整形數(shù)組使用insmod傳入?yún)?shù):

insmodvariable=value[,value2...]...注:value可以用引號(hào)括起來(lái),也可以不用。但是有一點(diǎn)“=”前后不能留有空格,并且value中也不能有空格。三、模塊編程模塊參數(shù)第三十三頁(yè),共103頁(yè)。編寫Linux字符設(shè)備驅(qū)動(dòng)程序需要熟悉三個(gè)重要的數(shù)據(jù)結(jié)構(gòu):(文件操作)、file(文件)和inode(節(jié)點(diǎn))。這三個(gè)數(shù)據(jù)結(jié)構(gòu)被定義在“include/linux/fs.h”文件中,是編寫字符設(shè)備驅(qū)動(dòng)時(shí)經(jīng)常用到的。由于用戶進(jìn)程是通過(guò)設(shè)備文件同硬件打交道,對(duì)設(shè)備文件的操作方式Linux同樣也做出了一系列的規(guī)范。四、字符設(shè)備驅(qū)動(dòng)相關(guān)數(shù)據(jù)結(jié)構(gòu)第三十四頁(yè),共103頁(yè)。首先,我們來(lái)了解一個(gè)非常重要的數(shù)據(jù)結(jié)構(gòu):,它存儲(chǔ)驅(qū)動(dòng)內(nèi)核模塊提供的對(duì)設(shè)備進(jìn)行這種操作的函數(shù)指針,也就是設(shè)備驅(qū)動(dòng)程序的入口點(diǎn)。它是一個(gè)在<linux/fs.h>中定義的structfile結(jié)構(gòu),這是一個(gè)內(nèi)核結(jié)構(gòu),不會(huì)出現(xiàn)在用戶空間的程序中,它定義了常見(jiàn)文件I/O函數(shù)的入口。四、字符設(shè)備驅(qū)動(dòng)第三十五頁(yè),共103頁(yè)。在2.6內(nèi)核版本中的具體定義如下: struct{ structmodule*owner; loff_t(*llseek)(structfile*,loff_t,int); ssize_t(*read)(structfile*,char__user*,size_t,loff_t*); ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*); ssize_t(*aio_read)(structkiocb*,conststructiovec*,unsignedlong,loff_t); ssize_t(*aio_write)(structkiocb*,conststructiovec*,unsignedlong,loff_t); int(*readdir)(structfile*,void*,filldir_t); unsignedint(*poll)(structfile*,structpoll_table_struct*); int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong); int(*mmap)(structfile*,structvm_area_struct*);

int(*open)(structinode*,structfile*); int(*flush)(structfile*,fl_owner_tid); int(*release)(structinode*,structfile*); int(*fsync)(structfile*,structdentry*,intdatasync); int(*aio_fsync)(structkiocb*,intdatasync); int(*fasync)(int,structfile*,int); int(*lock)(structfile*,int,struct*); ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int); unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong); int(*check_flags)(int); int(*dir_notify)(structfile*filp,unsignedlongarg); int(*flock)(structfile*,int,struct*); };四、字符設(shè)備驅(qū)動(dòng)第三十六頁(yè),共103頁(yè)。structmodule*owner;該成員是結(jié)構(gòu)中唯一一個(gè)不是聲明操作的成員,它是一個(gè)指向擁有這個(gè)模塊的指針,該成員用來(lái)在它的操作還在使用是不允許卸載該模塊,通常情況下都被簡(jiǎn)單初始化為THIS_MODULE。loff_t(*llseek)(structfile*,loff_t,int);方法llseek用來(lái)修改一個(gè)文件的當(dāng)前讀寫位置,并將新位置做為(正的)返回值返回。出錯(cuò)時(shí)返回一個(gè)負(fù)的返回值。如果驅(qū)動(dòng)程序沒(méi)有設(shè)置這個(gè)函數(shù),相對(duì)與文件尾的定位操作失敗,其他定位操作修改file結(jié)構(gòu)(在“file結(jié)構(gòu)”中介紹)中的位置計(jì)數(shù)器,并成功返回。四、字符設(shè)備驅(qū)動(dòng)第三十七頁(yè),共103頁(yè)。ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);用來(lái)從設(shè)備中讀取數(shù)據(jù)。當(dāng)其為NULL指針時(shí)將引起read系統(tǒng)調(diào)用返回-EINVAL(“非法參數(shù)”)。函數(shù)返回一個(gè)非負(fù)值表示成功的讀取了多少字節(jié)。其中ssize_t為int或者long型,和平臺(tái)有關(guān)。_user用來(lái)聲明為用戶空間。ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);向設(shè)備發(fā)送數(shù)據(jù)。如果沒(méi)有這個(gè)函數(shù),write系統(tǒng)調(diào)用向調(diào)用程序返回一個(gè)-EINVAL。注意。如果返回值非負(fù),它就表示成功地寫入的字節(jié)數(shù)。四、字符設(shè)備驅(qū)動(dòng)第三十八頁(yè),共103頁(yè)。ssize_t(*aio_read)(structkiocb*,conststructiovec*,unsignedlong,loff_t);該操作用來(lái)初始化一個(gè)異步的讀操作,即當(dāng)一個(gè)讀操作還沒(méi)有完成時(shí)也許這個(gè)函數(shù)已經(jīng)返回。當(dāng)該操作為空時(shí),它將由read(同步)操作代替。ssize_t(*aio_write)(structkiocb*,conststructiovec*,unsignedlong,loff_t);該操作用來(lái)初始化一個(gè)異步寫操作,當(dāng)該操作為空時(shí),調(diào)用write操作。int(*readdir)(structfile*,void*,filldir_t);對(duì)于設(shè)備節(jié)點(diǎn)來(lái)說(shuō),這個(gè)字段應(yīng)該為NULL;它僅用于目錄。四、字符設(shè)備驅(qū)動(dòng)第三十九頁(yè),共103頁(yè)。unsignedint(*poll)(structfile*,structpoll_table_struct*);該操作用來(lái)查詢一個(gè)或者多個(gè)文件描述符的讀寫是否會(huì)阻塞。Poll方法返回一位掩碼用來(lái)指示是否非阻塞的讀或?qū)懯强赡艿模⑶姨峁┙o內(nèi)核信息涌來(lái)時(shí)調(diào)用進(jìn)程sleep直到I/O端口變?yōu)榭捎?。如果一個(gè)設(shè)備驅(qū)動(dòng)的Poll方法為空,則設(shè)備默認(rèn)為不可阻塞的可讀和可寫操作。int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);系統(tǒng)調(diào)用ioctl提供一中調(diào)用設(shè)備相關(guān)命令的方法(如軟盤的格式化一個(gè)磁道,這既不是讀操作也不是寫操作)。另外,內(nèi)核還識(shí)別一部分ioctl命令,而不必調(diào)用fops表中的ioctl。如果設(shè)備不提供ioctl入口點(diǎn),對(duì)于任何內(nèi)核沒(méi)有定義的請(qǐng)求,ioctl系統(tǒng)調(diào)用將返回-EINVAL。當(dāng)調(diào)用成功時(shí),返回給調(diào)用程序一個(gè)非負(fù)返回值。四、字符設(shè)備驅(qū)動(dòng)第四十頁(yè),共103頁(yè)。int(*mmap)(structfile*,structvm_area_struct*);mmap用來(lái)將設(shè)備內(nèi)存映射到進(jìn)程內(nèi)存中。如果設(shè)備不支持這個(gè)方法,mmap系統(tǒng)調(diào)用將返回-ENODEV錯(cuò)誤信息。int(*open)(structinode*,structfile*);盡管這總是操作在設(shè)備節(jié)點(diǎn)上的第一個(gè)操作,然而并不要求驅(qū)動(dòng)程序一定要聲明這個(gè)方法。如果該項(xiàng)為NULL,設(shè)備的打開(kāi)操作永遠(yuǎn)成功,但系統(tǒng)不會(huì)通知你的驅(qū)動(dòng)程序。 int(*flush)(structfile*,fl_owner_tid);該操作用來(lái)執(zhí)行和等待設(shè)備未完成的操作,目前該方法很少使用,不過(guò)SCSI磁帶驅(qū)動(dòng)使用了它,用來(lái)確保所有寫的數(shù)據(jù)在設(shè)備關(guān)閉前已經(jīng)寫到磁帶上。如果flush為空,內(nèi)核簡(jiǎn)單地忽略應(yīng)用程序的請(qǐng)求。四、字符設(shè)備驅(qū)動(dòng)第四十一頁(yè),共103頁(yè)。int(*release)(structinode*,structfile*);當(dāng)節(jié)點(diǎn)被關(guān)閉時(shí)調(diào)用這個(gè)操作。與open相仿,release也可以沒(méi)有。在2.0和更早的核心中,close系統(tǒng)調(diào)用從不失敗。int(*fsync)(structfile*,structdentry*,intdatasync);刷新設(shè)備。如果驅(qū)動(dòng)程序不支持,fsync系統(tǒng)調(diào)用返回-EINVAL。int(*fasync)(int,structfile*,int);這個(gè)操作用來(lái)通知設(shè)備它的FASYNC標(biāo)志的變化。如果設(shè)備不支持異步觸發(fā),該字段可以是NULL。四、字符設(shè)備驅(qū)動(dòng)第四十二頁(yè),共103頁(yè)。int(*aio_fsync)(structkiocb*,intdatasync);該操作為fsync的異步版本。int(*lock)(structfile*,int,struct*);該操作用來(lái)對(duì)文件實(shí)行加鎖,加鎖對(duì)常規(guī)文件是必不可少的特性,但是設(shè)備驅(qū)動(dòng)很少有實(shí)現(xiàn)該操作的。ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);該操作用來(lái)由內(nèi)核調(diào)用來(lái)發(fā)送數(shù)據(jù),一次一頁(yè)到對(duì)應(yīng)的文件。設(shè)備驅(qū)動(dòng)程序?qū)嶋H上不實(shí)現(xiàn)sendpage方法。四、字符設(shè)備驅(qū)動(dòng)第四十三頁(yè),共103頁(yè)。unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);該操作用來(lái)在進(jìn)程地址空間找一個(gè)合適的位置來(lái)映射在底層設(shè)備上的內(nèi)存段中。該方法是使驅(qū)動(dòng)能強(qiáng)制滿足特殊設(shè)備的對(duì)齊請(qǐng)求。通常情況下,該方法設(shè)置為空。int(*check_flags)(int);該操作循序模塊檢查傳遞給fnctl(F_SETFL…)調(diào)用的標(biāo)志。通常情況下該方法設(shè)置為空。四、字符設(shè)備驅(qū)動(dòng)第四十四頁(yè),共103頁(yè)。int(*dir_notify)(structfile*filp,unsignedlongarg);該操作只對(duì)文件系統(tǒng)有用,該方法在應(yīng)用程序使用fcntl函數(shù)來(lái)請(qǐng)求目錄改變通知時(shí)調(diào)用。設(shè)備驅(qū)動(dòng)程序不需要實(shí)現(xiàn)dir_notify方法。int(*flock)(structfile*,int,struct*);該操作用來(lái)對(duì)文件設(shè)備加鎖,但是基本上沒(méi)有驅(qū)動(dòng)程序?qū)崿F(xiàn)此操作。四、字符設(shè)備驅(qū)動(dòng)第四十五頁(yè),共103頁(yè)。結(jié)構(gòu)體的確包含了很多操作,但是基本上用到的不多。例如Linux中斷實(shí)例中的文件操作定義如下:

staticstructkey_fops { owner:THIS_MODULE, read: key_read, open:key_open, release:key_release, };從中我們可以看出,該設(shè)備驅(qū)動(dòng)模塊只實(shí)現(xiàn)了read、open和release三個(gè)操作,這三個(gè)操作所對(duì)應(yīng)的實(shí)現(xiàn)函數(shù)分別是:key_read、key_open和key_release,其它操作都沒(méi)有實(shí)現(xiàn)。四、字符設(shè)備驅(qū)動(dòng)第四十六頁(yè),共103頁(yè)。file結(jié)構(gòu),即文件結(jié)構(gòu),它不同于應(yīng)用程序空間的FILE指針,F(xiàn)ILE指針定義了在C庫(kù)中而不會(huì)出現(xiàn)在內(nèi)核代碼中,而structfile只出現(xiàn)在內(nèi)核代碼中,從不出現(xiàn)在用戶程序中。

file四、字符設(shè)備驅(qū)動(dòng)第四十七頁(yè),共103頁(yè)。file結(jié)構(gòu)體在Linux2.6版本的內(nèi)核中的定義如下: structfile{ structlist_headfu_list; structdentry *f_dentry; structvfsmount *f_vfsmnt; conststruct*f_op; atomic_long_tf_count; unsignedintf_flags; fmode_tf_mode; int f_error; loff_tf_pos; structfown_structf_owner; unsignedintf_uid,f_gid; structf_ra; u64f_version;file四、字符設(shè)備驅(qū)動(dòng)第四十八頁(yè),共103頁(yè)。#ifdefCONFIG_SECURITY void*f_security; #endif/*neededforttydriver,andmaybeothers*/void*private_data;

#ifdefCONFIG_EPOLL/*Usedbyfs/eventpoll.ctolinkallthehookstothisfile*/structlist_headf_ep_links;spinlock_tf_ep_lock;#endif/*#ifdefCONFIG_EPOLL*/structaddress_space*f_mapping;#ifdefCONFIG_DEBUG_WRITECOUNTunsignedlongf_mnt_write_state;#endif};file四、字符設(shè)備驅(qū)動(dòng)第四十九頁(yè),共103頁(yè)。structdentry*f_dentry;該成員是文件對(duì)應(yīng)的目錄項(xiàng)結(jié)構(gòu)。除了使用flip->f_dentry->d_inode的方法訪問(wèn)索引節(jié)點(diǎn)結(jié)構(gòu)外,設(shè)備驅(qū)動(dòng)開(kāi)發(fā)人員一般無(wú)需關(guān)心dentry結(jié)構(gòu)。conststruct*f_op;該成員定義與文件有關(guān)聯(lián)的操作集合,也就是前面中介紹的文件操作。內(nèi)核在執(zhí)行open操作時(shí)對(duì)這個(gè)指針賦值,以后需要處理這些操作時(shí)就讀這個(gè)指針。unsignedintf_flags;該成員為文件標(biāo)志,如O_RDONLY(只讀)、O_NONBLOCK(非阻塞)和O_SYNC(同步)。驅(qū)動(dòng)程序應(yīng)該檢查O_NONBLOCK標(biāo)志判斷是否為非阻塞操作請(qǐng)求。這里注意,讀寫權(quán)限通過(guò)f_mode成員檢查而不是f_flags。file四、字符設(shè)備驅(qū)動(dòng)第五十頁(yè),共103頁(yè)。fmode_tf_mode;該成員用來(lái)確定文件是可讀的,可寫的或者可讀可寫的,通過(guò)位FMODE_READ和FMODE_WRITE實(shí)現(xiàn)。loff_tf_pos;該成員用來(lái)確定當(dāng)前的讀寫位置。如果需要知道當(dāng)前在文件中的位置,驅(qū)動(dòng)程序可以讀該值,但是不應(yīng)該改變?cè)撝怠oid*private_data;該成員是跨系統(tǒng)調(diào)用時(shí)保存狀態(tài)信息非常有用的資源。驅(qū)動(dòng)程序可以用該字段指向已分配的數(shù)據(jù),但一定要在內(nèi)核銷毀file結(jié)構(gòu)前在release方法中釋放內(nèi)存。file四、字符設(shè)備驅(qū)動(dòng)第五十一頁(yè),共103頁(yè)。file文件結(jié)構(gòu)代表一個(gè)打開(kāi)的文件描述符,它不是專門給驅(qū)動(dòng)程序使用,系統(tǒng)中每個(gè)打開(kāi)的文件在內(nèi)核中都有一個(gè)關(guān)聯(lián)的structfile。它由內(nèi)核在open時(shí)創(chuàng)建,并傳遞給文件上操作的任何函數(shù),直達(dá)最后關(guān)閉。當(dāng)文件的所有實(shí)例都關(guān)閉后,內(nèi)核釋放該數(shù)據(jù)結(jié)構(gòu)。file四、字符設(shè)備驅(qū)動(dòng)第五十二頁(yè),共103頁(yè)。內(nèi)核中inode(節(jié)點(diǎn))結(jié)構(gòu)表示具體的文件,而用file結(jié)構(gòu)表示打開(kāi)的文件描述符。對(duì)于單個(gè)文件,可能會(huì)有許多個(gè)表示打開(kāi)的文件描述符file結(jié)構(gòu),但是它們都是指向單個(gè)的inode結(jié)構(gòu),所以file結(jié)構(gòu)和inode結(jié)構(gòu)是不同的。inode結(jié)構(gòu)中包含了大量有關(guān)文件的信息,但通常情況下對(duì)設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)有用的成員有下面兩個(gè): dev_ti_rdev;該成員表示設(shè)備文件的inode結(jié)構(gòu),它包含了真正的設(shè)備編號(hào)。 structcdev*i_cdev;該成員表示字符設(shè)備內(nèi)核的內(nèi)部結(jié)構(gòu),當(dāng)inode指向一個(gè)字符設(shè)備文件時(shí),該成員包含了指向structcdev結(jié)構(gòu)的指針,其中cdev結(jié)構(gòu)是字符設(shè)備結(jié)構(gòu)體。inode四、字符設(shè)備驅(qū)動(dòng)第五十三頁(yè),共103頁(yè)。在fs/devices.c文件中,會(huì)有如下一全局變量定義: staticstructdevice_structchrdevs[MAX_CHRDEV];實(shí)際上全局?jǐn)?shù)組chrdevs是所有字符設(shè)備管理的入口,數(shù)組的下標(biāo)為具體某個(gè)字符設(shè)備的設(shè)備號(hào),每個(gè)數(shù)組元素描述了具體設(shè)備的設(shè)備驅(qū)動(dòng)。Chrdevs向量表中的每一個(gè)條目,一個(gè)device_struct數(shù)據(jù)結(jié)構(gòu),包括兩個(gè)元素:一個(gè)登記的設(shè)備驅(qū)動(dòng)程序的名稱的指針和一個(gè)指向一組文件操作的指針。這塊文件操作本身位于這個(gè)設(shè)備的字符設(shè)備驅(qū)動(dòng)程序中,每一個(gè)都處理特定的文件操作比如打開(kāi)、讀、寫和關(guān)閉。device_struct四、字符設(shè)備驅(qū)動(dòng)第五十四頁(yè),共103頁(yè)。編寫一個(gè)字符設(shè)備驅(qū)動(dòng),主要是下面幾步:編寫硬件接口函數(shù)建立文件系統(tǒng)與設(shè)備驅(qū)動(dòng)程序的接口變量,類型為struct結(jié)構(gòu)體,并初始化該變量注冊(cè)設(shè)備到chrdevs全局?jǐn)?shù)組中以模塊方式編譯驅(qū)動(dòng)源碼,并將其加載到內(nèi)核中創(chuàng)建設(shè)備節(jié)點(diǎn)編寫應(yīng)用程序訪問(wèn)底層設(shè)備字符設(shè)備驅(qū)動(dòng)開(kāi)發(fā)流程四、字符設(shè)備驅(qū)動(dòng)第五十五頁(yè),共103頁(yè)。其流程圖如下:字符設(shè)備驅(qū)動(dòng)開(kāi)發(fā)流程四、字符設(shè)備驅(qū)動(dòng)第五十六頁(yè),共103頁(yè)。編寫硬件接口函數(shù)是設(shè)備驅(qū)動(dòng)的主要工作,也是重點(diǎn)和難點(diǎn)。做這部分工作最核心的是要掌握硬件的工作原理,從本質(zhì)上來(lái)說(shuō),這部分的內(nèi)容就是前面接口部分的內(nèi)容,所以基于操作系統(tǒng)的驅(qū)動(dòng)程序設(shè)計(jì)就是在無(wú)操作系統(tǒng)下的硬件接口函數(shù)加上操作系統(tǒng)的外套而已。編寫硬件接口函數(shù)四、字符設(shè)備驅(qū)動(dòng)第五十七頁(yè),共103頁(yè)。設(shè)備要使用必須首先打開(kāi)設(shè)備,在Linux中,打開(kāi)設(shè)備使用open函數(shù):函數(shù)原型: int(*open)(structinode*inode,structfile*file)參數(shù): inode:節(jié)點(diǎn) file:文件返回值:如果成功返回該設(shè)備的句柄頭文件:#include<linux/fs.h>打開(kāi)設(shè)備:open函數(shù)四、字符設(shè)備驅(qū)動(dòng)第五十八頁(yè),共103頁(yè)。對(duì)于不同的設(shè)備來(lái)說(shuō),open函數(shù)完成的功能也各不相同,但通常來(lái)說(shuō)要完成如下幾件工作:增加設(shè)備使用計(jì)數(shù)器:如果同一設(shè)備可以被多個(gè)應(yīng)用程序同時(shí)打開(kāi)使用,則其中任一進(jìn)程想要關(guān)閉該設(shè)備時(shí),必須確保其它設(shè)備沒(méi)有使用該設(shè)備。模塊計(jì)數(shù)器相關(guān)宏可以這個(gè)功能。 MOD_INC_USE_COUNT:計(jì)數(shù)器加一 MOD_DEC_USE_COUNT:計(jì)數(shù)器減一 MOD_IN_USE:計(jì)數(shù)器非零時(shí)返回真檢查特定設(shè)備的特殊情況初始化設(shè)備完成其它功能打開(kāi)設(shè)備:open函數(shù)四、字符設(shè)備驅(qū)動(dòng)第五十九頁(yè),共103頁(yè)。當(dāng)一個(gè)進(jìn)程不使用由它打開(kāi)的設(shè)備時(shí),可以將其釋放,釋放函數(shù)的接口原型為realse,完成下面幾個(gè)任務(wù):遞減計(jì)數(shù)器如果沒(méi)有進(jìn)程使用該設(shè)備,則將該設(shè)備關(guān)閉如果在打開(kāi)該設(shè)備時(shí)申請(qǐng)了堆中的內(nèi)存,則釋放該內(nèi)存釋放設(shè)備:release函數(shù)四、字符設(shè)備驅(qū)動(dòng)第六十頁(yè),共103頁(yè)。在打開(kāi)設(shè)備或釋放設(shè)備時(shí),有時(shí)會(huì)申請(qǐng)內(nèi)存或釋放內(nèi)存,由于設(shè)備驅(qū)動(dòng)位于內(nèi)核,我們必須使用基于內(nèi)核內(nèi)存的函數(shù),而不能使用malloc()和free()函數(shù)來(lái)獲得內(nèi)存或者釋放內(nèi)存。kmalloc函數(shù)函數(shù)原型: void*kmalloc(unsignedintlen,intflags)操縱內(nèi)存:kmalloc和kfree等函數(shù)四、字符設(shè)備驅(qū)動(dòng)第六十一頁(yè),共103頁(yè)。參數(shù):len:申請(qǐng)內(nèi)存大?。ㄒ宰止?jié)為單位)flags: GFP_KERNEL:分配內(nèi)核內(nèi)存時(shí)通常使用該參數(shù),但可 能會(huì)引起睡眠 GFP_BUFFER:用于管理緩沖區(qū)高速緩存 GFP_ATOMIC:為中斷處理程序或其它運(yùn)行于進(jìn)程上下 文之外的代碼分配內(nèi)存,不會(huì)引起睡眠 GFP_DMA:分配DMA內(nèi)存 GFP_HIGHUSER:優(yōu)先高端內(nèi)存分配 GFP_HIGHMEM:從高端內(nèi)存區(qū)分配 GFP_USER:用戶分配內(nèi)存返回值:成功:分配的內(nèi)核內(nèi)存地址錯(cuò)誤:-EFAULT頭文件:#include<linux/malloc.h>操縱內(nèi)存:kmalloc和kfree等函數(shù)四、字符設(shè)備驅(qū)動(dòng)第六十二頁(yè),共103頁(yè)。函數(shù)原型: voidkfree(void*ptr)參數(shù): ptr:要釋放的內(nèi)存指針?lè)祷刂担撼晒Γ簾o(wú)返回值錯(cuò)誤:-EFAULT頭文件:#include<linux/malloc.h>kfree函數(shù)四、字符設(shè)備驅(qū)動(dòng)第六十三頁(yè),共103頁(yè)。函數(shù)原型: ssize_t(*read)(structfile*file,char*buff,size_tcount,loff_t*offp)參數(shù):file:文件指針buff:指向用戶緩沖區(qū),即將內(nèi)核數(shù)據(jù)存放的目的地址count:要讀取的數(shù)據(jù)長(zhǎng)度offp:讀指針位置返回值: 如果成功返回讀取的字節(jié)數(shù)頭文件:#include<linux/fs.h>read函數(shù)四、字符設(shè)備驅(qū)動(dòng)第六十四頁(yè),共103頁(yè)。函數(shù)原型:

ssize_t(*write)(structfile*file,constchar*buffer,size_tcount,loff_t*ppos)參數(shù):file:文件指針buff:指向用戶緩沖區(qū),即要讀取的數(shù)據(jù)源地址count:要讀取的數(shù)據(jù)長(zhǎng)度offp:讀指針位置返回值: 如果成功返回寫入的字節(jié)數(shù)頭文件:#include<linux/fs.h>write函數(shù)四、字符設(shè)備驅(qū)動(dòng)第六十五頁(yè),共103頁(yè)。函數(shù)原型:

unsignedlongcopy_to_user(void*to,constvoid*from,unsignedlongcount) unsignedlongcopy_from_user(void*to,constvoid*from,unsignedlongcount)參數(shù):to:指向目的緩沖區(qū)地址from:指向數(shù)據(jù)源緩沖區(qū)地址count:傳輸?shù)臄?shù)據(jù)長(zhǎng)度返回值:如果成功返回傳輸字節(jié)數(shù)頭文件:#include<linux/fs.h>copy_from_user/copy_to_user函數(shù)四、字符設(shè)備驅(qū)動(dòng)第六十六頁(yè),共103頁(yè)。設(shè)備驅(qū)動(dòng)程序的格式如下,比方說(shuō)要得到watchdog_open函數(shù),可定義如下: staticstructwatchdog_fops={ open: watchdog_open, release: watchdog_release, write: watchdog_write, };這樣open函數(shù)指針指向watchdog_open函數(shù),release函數(shù)指針指向watchdog_release函數(shù),write函數(shù)指針指向watchdog_write函數(shù)。建立文件系統(tǒng)與設(shè)備驅(qū)動(dòng)程序的接口定義四、字符設(shè)備驅(qū)動(dòng)第六十七頁(yè),共103頁(yè)。設(shè)備注冊(cè)使用函數(shù)register_chrdev,該函數(shù)執(zhí)行后將設(shè)備在chrdevs[]數(shù)組中進(jìn)行登記,如果用戶要注銷設(shè)備(即將設(shè)備從chrdevs[]數(shù)組中刪除),可以調(diào)用unregister_chrdev函數(shù)。注冊(cè)/注銷設(shè)備四、字符設(shè)備驅(qū)動(dòng)第六十八頁(yè),共103頁(yè)。函數(shù)原型:

intregister_chrdev(unsignedintmajor,constchar*name,struct*fops)參數(shù):major:設(shè)備驅(qū)動(dòng)程序向系統(tǒng)申請(qǐng)的主設(shè)備號(hào),如果為0則動(dòng)態(tài)分配一個(gè)主設(shè)備號(hào)name:設(shè)備名fops:指向文件系統(tǒng)與設(shè)備驅(qū)動(dòng)程序的接口變量返回值:成功:返回分配設(shè)備的主設(shè)備號(hào),可以在/proc/devices文件中查詢到出錯(cuò):返回-1頭文件:#include<linux/fs.h>register_chrdev函數(shù)四、字符設(shè)備驅(qū)動(dòng)第六十九頁(yè),共103頁(yè)。函數(shù)原型:

intunregister_chrdev(unsignedintmajor,constchar*name)參數(shù):major:設(shè)備驅(qū)動(dòng)程序向系統(tǒng)申請(qǐng)的主設(shè)備號(hào),如果為0則動(dòng)態(tài)分配一個(gè)主設(shè)備號(hào)name:設(shè)備名fops:指向文件系統(tǒng)與設(shè)備驅(qū)動(dòng)程序的接口變量返回值:成功:返回值0出錯(cuò):返回值-1頭文件:#include<linux/fs.h>unregister_chrdev函數(shù)四、字符設(shè)備驅(qū)動(dòng)第七十頁(yè),共103頁(yè)。如果以模塊的方式進(jìn)行編譯,則編寫Makefie,內(nèi)容如下:

CROSS=arm-linux- MODFLAGS=-Wall-DMODULE-D__KERNEL__-DLINUX\ -I/root/Myjob/s3c2440_kernel2.4.18_rel/include-c–o watchdog.o:watchdog.c $(CROSS)gcc $(MODFLAGS)$@$< clean: rm-rfwatchdog.o 只需make后生成watchdog.o文件,調(diào)用insmod命令進(jìn)行加載:

insmodwatchdog.o模塊編譯并加載四、字符設(shè)備驅(qū)動(dòng)第七十一頁(yè),共103頁(yè)。到上一步為止,我們已經(jīng)完整編寫了看門狗設(shè)備驅(qū)動(dòng),并將其代碼搬運(yùn)到內(nèi)核中,下面就可以以文件的方式來(lái)訪問(wèn)這些底層接口函數(shù)。所以我們必須創(chuàng)建設(shè)備文件,并將其和內(nèi)核中的設(shè)備驅(qū)動(dòng)關(guān)聯(lián)到一起,這樣用戶就可以在用戶空間中通過(guò)訪問(wèn)設(shè)備文件來(lái)控制底層硬件工作的目的。創(chuàng)建設(shè)備節(jié)點(diǎn)格式為: mknod設(shè)備名設(shè)備類型主設(shè)備號(hào)次設(shè)備號(hào)因此創(chuàng)建看門狗設(shè)備文件: mknod/dev/watchdogc2340創(chuàng)建設(shè)備節(jié)點(diǎn)四、字符設(shè)備驅(qū)動(dòng)第七十二頁(yè),共103頁(yè)。1、ioctl基本概念ioctl是設(shè)備驅(qū)動(dòng)程序中對(duì)設(shè)備的I/O通道進(jìn)行管理的函數(shù)。所謂對(duì)I/O通道進(jìn)行管理,就是對(duì)設(shè)備的一些特性進(jìn)行控制,例如串口的傳輸波特率、馬達(dá)的轉(zhuǎn)速等等。ioctl函數(shù)調(diào)用形式如下:

intioctl(intfd,indcmd,…);其中fd就是用戶程序打開(kāi)設(shè)備時(shí)使用open函數(shù)返回的文件標(biāo)示符,cmd就是用戶程序?qū)υO(shè)備的控制命令,至于后面的省略號(hào),那是一些補(bǔ)充參數(shù),一般最多一個(gè),有或沒(méi)有是和cmd的意義相關(guān)的。字符設(shè)備驅(qū)動(dòng)擴(kuò)展操作四、字符設(shè)備驅(qū)動(dòng)第七十三頁(yè),共103頁(yè)。2、構(gòu)建命令碼在驅(qū)動(dòng)程序中實(shí)現(xiàn)的ioctl函數(shù)體內(nèi),實(shí)際上有一個(gè)switch{case}結(jié)構(gòu),每一個(gè)case對(duì)應(yīng)一個(gè)命令碼,做出一些相應(yīng)的操作。怎么實(shí)現(xiàn)這些操作,程序員可以根據(jù)設(shè)備來(lái)進(jìn)行具體編寫。但是命令碼是如何組織的呢?這很關(guān)鍵。因?yàn)樵趇octl中命令碼是唯一聯(lián)系用戶程序命令和驅(qū)動(dòng)程序支持的途徑。

字符設(shè)備驅(qū)動(dòng)擴(kuò)展操作四、字符設(shè)備驅(qū)動(dòng)第七十四頁(yè),共103頁(yè)。命令碼的組織是有一些講究的,因?yàn)橐欢ㄒ龅矫詈驮O(shè)備是一一對(duì)應(yīng)的,這樣才不會(huì)將正確的命令發(fā)給錯(cuò)誤的設(shè)備,或者是把錯(cuò)誤的命令發(fā)給正確的設(shè)備,或者是把錯(cuò)誤的命令發(fā)給錯(cuò)誤的設(shè)備。這些錯(cuò)誤都會(huì)導(dǎo)致不可預(yù)料的事情發(fā)生,而當(dāng)程序員發(fā)現(xiàn)了這些奇怪的事情的時(shí)候,再來(lái)調(diào)試程序查找錯(cuò)誤,那將是非常困難的事情。字符設(shè)備驅(qū)動(dòng)擴(kuò)展操作四、字符設(shè)備驅(qū)動(dòng)第七十五頁(yè),共103頁(yè)。可以看出,一個(gè)命令碼實(shí)質(zhì)上是一個(gè)整數(shù)形式的命令。但是命令碼非常的不直觀,所以LinuxKernel中提供了一些宏,這些宏可根據(jù)便于理解的字符串生成命令碼,或者是從命令碼得到一些用戶可以理解的字符串以標(biāo)明這個(gè)命令對(duì)應(yīng)的設(shè)備類型、設(shè)備序列號(hào)、數(shù)據(jù)傳送方向和數(shù)據(jù)傳輸尺寸。

在Linux內(nèi)核中命令碼采用如下表定義方式:字符設(shè)備驅(qū)動(dòng)擴(kuò)展操作四、字符設(shè)備驅(qū)動(dòng)第七十六頁(yè),共103頁(yè)。具體相關(guān)的宏如下:

//include/ioctl.h #define_IOC(dir,type,nr,size)\ (((dir)<<_IOC_DIRSHIFT)|\ ((type)<<_IOC_TYPESHIFT)|\ ((nr)<<_IOC_NRSHIFT)|\ ((size)<<_IOC_SIZESHIFT)) /*usedtocreatenumbers*/ #define_IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) #define_IOR(type,nr,size _IOC(_IOC_READ,(type),(nr),sizeof(size)) #define_IOW(type,nr,size _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) #define_IOWR(type,nr,size)_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) 其中_IO宏用于生成沒(méi)有傳輸方向的命令碼,_IOR宏用于生成讀命令碼,_IOW宏用于生成寫命令碼,_IOWR宏用于生成雙向傳輸?shù)拿畲a。字符設(shè)備驅(qū)動(dòng)擴(kuò)展操作四、字符設(shè)備驅(qū)動(dòng)第七十七頁(yè),共103頁(yè)。1.net_device數(shù)據(jù)結(jié)構(gòu)在Linux系統(tǒng)中,描述網(wǎng)絡(luò)設(shè)備的數(shù)據(jù)結(jié)構(gòu)為structnet_device,該結(jié)構(gòu)體定義文件位于include/linux/netdevice.h文件中,是網(wǎng)絡(luò)驅(qū)動(dòng)程序?qū)幼詈诵牡囊粋€(gè)結(jié)構(gòu)體,值得讀者細(xì)細(xì)品位,但并不要求大家記住其中的每個(gè)細(xì)節(jié)。

五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)基本概念第七十八頁(yè),共103頁(yè)。(1)全局信息全局信息的成員主要是設(shè)備名稱、設(shè)備狀態(tài)、下一設(shè)備指針和初始函數(shù)等。下面我們?cè)敿?xì)介紹這幾個(gè)成員變量。設(shè)備名稱全局信息的第一個(gè)成員是設(shè)備的名稱,在net_device結(jié)構(gòu)體中定義為: char name[IFNAMSIZ];注:順便提一下,配置網(wǎng)絡(luò)IP地址經(jīng)常使用的一條命令:

ifconfigeth0192.168.0.213此處eth0就為第一塊網(wǎng)卡的設(shè)備名稱。通常在給name賦值時(shí)為0(NULL字符)或空格,如果這樣,register_netdev將給它分配名字ethn,n取合適的值,如第一塊網(wǎng)卡就為eth0,第二塊網(wǎng)卡取名為eth1,依次類推。五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)net_device數(shù)據(jù)結(jié)構(gòu)第七十九頁(yè),共103頁(yè)。設(shè)備狀態(tài)接下來(lái)很重要的成員是設(shè)備狀態(tài),該成員定義如下: unsignedlongstate;這個(gè)成員包含許多標(biāo)志,其實(shí)驅(qū)動(dòng)程序通常無(wú)需直接操作這些標(biāo)志,它可以通過(guò)內(nèi)核提供的一組工具函數(shù)來(lái)訪問(wèn)。下一設(shè)備指針這個(gè)成員也很重要,在net_device結(jié)構(gòu)體中定義如下: structnet_device *next;該成員表示全局鏈表下一個(gè)設(shè)備的指針,因?yàn)樗械木W(wǎng)絡(luò)設(shè)備都可以通過(guò)next指針連接成一條鏈。值得注意的是驅(qū)動(dòng)程序不應(yīng)該修改這個(gè)成員。五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)net_device數(shù)據(jù)結(jié)構(gòu)第八十頁(yè),共103頁(yè)。初始化函數(shù)如果該指針被設(shè)置,則register_netdev()將調(diào)用該函數(shù)完成對(duì)net_device結(jié)構(gòu)的初始化。init函數(shù)指針指向網(wǎng)卡。該函數(shù)定義格式為: int(*init)(structnet_device*dev);但是現(xiàn)在很多網(wǎng)絡(luò)驅(qū)動(dòng)程序不再使用這個(gè)函數(shù),它們通常在注冊(cè)接口前就直接完成初始化工作。五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)net_device數(shù)據(jù)結(jié)構(gòu)第八十一頁(yè),共103頁(yè)。(2)硬件信息硬件信息都是跟底層硬件相關(guān)的。主要的成員如下:內(nèi)存起始和中止地址這些成員網(wǎng)絡(luò)數(shù)據(jù)包傳輸和接收數(shù)據(jù)的內(nèi)存起始地址和中止地址。其中,mem成員用于傳輸內(nèi)存,rmem成員用于接收內(nèi)存。其定義如下:

unsignedlong rmem_end; /*shmem"recv"end */ unsignedlong rmem_start; /*shmem"recv"start */ unsignedlong mem_end; /*sharedmemend */ unsignedlong mem_start; /*sharedmemstart */五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)net_device數(shù)據(jù)結(jié)構(gòu)第八十二頁(yè),共103頁(yè)。網(wǎng)絡(luò)I/O基地址不同的目標(biāo)板一般使用的I/O口一般都不盡相同,因此網(wǎng)絡(luò)接口的I/O基地址的設(shè)置和具體的網(wǎng)絡(luò)硬件連接密切相關(guān)。這個(gè)成員的具體定義為: unsignedlongbase_addr; /*deviceI/Oaddress */網(wǎng)絡(luò)設(shè)備中斷號(hào)跟網(wǎng)絡(luò)I/O基地址一樣,但不同的是這個(gè)中斷號(hào)一般可以統(tǒng)一,但它也和具體的網(wǎng)絡(luò)硬件連接密切相關(guān)。其定義為:

unsignedint irq; /*deviceIRQnumber */五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)net_device數(shù)據(jù)結(jié)構(gòu)第八十三頁(yè),共103頁(yè)。網(wǎng)絡(luò)端口對(duì)于網(wǎng)絡(luò)很重要的成員還有網(wǎng)絡(luò)端口,net_device結(jié)構(gòu)體中定義端口的成員如下: unsignedcharif_port; /*SelectableAUI,TP,..*/它用于指定多端口設(shè)備上使用哪個(gè)端口。完整的的已知端口類型在<linux/netdevice.h>中定義。DMA通道這個(gè)成員為設(shè)備分配的DMA通道。該成員只對(duì)某些總線有用,比如ISA。該成員定義如下:

unsignedchardma; /*DMAchannel */五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)net_device數(shù)據(jù)結(jié)構(gòu)第八十四頁(yè),共103頁(yè)。(3)接口信息這類成員不是每種網(wǎng)卡都必須的,如果是以太網(wǎng)卡,大部分接口信息可由ether_setup()函數(shù)正確設(shè)置。在net_device結(jié)構(gòu)體中相關(guān)的成員如下:最大傳輸單元這個(gè)成員用于設(shè)置最大傳輸單元。該值的設(shè)定和數(shù)據(jù)鏈路層使用的幀類型密切相關(guān),如果為以太幀,則MTU設(shè)置為1500個(gè)octet。其定義如下: unsignedmtu; /*interfaceMTUvalue*/五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)net_device數(shù)據(jù)結(jié)構(gòu)第八十五頁(yè),共103頁(yè)。接口硬件類型type成員用于指定接口的硬件類型。以太網(wǎng)中,ARP使用type成員判斷接口所支持的硬件地址類型。已知的硬件地址類型定義在<linux/if_arp.h>中定義。以太網(wǎng)接口類型時(shí),type應(yīng)設(shè)置為ARPHRD_ETHER。其定義如下:

unsignedshorttype;/*interfacehardwaretype */硬件頭長(zhǎng)度這個(gè)成員用于定義硬件頭的長(zhǎng)度。對(duì)以太網(wǎng)接口,一般該成員應(yīng)該被賦值為14(ETH_HLEN),其定義一般如下:

unsignedshorthard_header_len;/*hardwarehdrlength */五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)net_device數(shù)據(jù)結(jié)構(gòu)第八十六頁(yè),共103頁(yè)。MAC地址這個(gè)成員是網(wǎng)絡(luò)驅(qū)動(dòng)最重要的幾個(gè)變量。該成員指定網(wǎng)卡設(shè)備的硬件地址(MAC地址),以太網(wǎng)地址長(zhǎng)為六個(gè)八元組(我們是指接口板的硬件標(biāo)志),播送地址由六個(gè)0xff八元組組成;ether_setup負(fù)責(zé)這些值的正確設(shè)置。另一方面,設(shè)備地址必須以設(shè)備特定的方式從接口板中讀出,驅(qū)動(dòng)程序應(yīng)把它復(fù)制到dev_addr。這個(gè)硬件地址用來(lái)在把包交給驅(qū)動(dòng)程序傳送前產(chǎn)生正確的以太網(wǎng)包頭。其定義如下: unsignedchardev_addr[MAX_ADDR_LEN];/*hwaddress*/接口地址簇這個(gè)成員變量,接口并不常查看這個(gè)域或者向其賦值,通常為AF_INET。其定義如下: unsignedshortfamily;五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)net_device數(shù)據(jù)結(jié)構(gòu)第八十七頁(yè),共103頁(yè)。地址相關(guān)跟地址相關(guān)的成員很多,比較重要的是以下三個(gè)。這三個(gè)成員分別描述了網(wǎng)卡接口的三個(gè)重要地址:接口地址,播送地址,及網(wǎng)絡(luò)掩碼。這些值是協(xié)議特定的(既它們是“協(xié)議地址”);如果dev->family是INET,則它們?yōu)镮P地址。這些域由ifconfig賦值,對(duì)驅(qū)動(dòng)程序是只讀的。它們一般定義為: unsignedlongpa_addr; unsignedlongpa_brdaddr; unsignedlongpa_mask;接口標(biāo)志跟接口有關(guān)的標(biāo)志位,對(duì)于這些標(biāo)志,有些由核心管理,有些則是在初始化時(shí)由接口設(shè)置,以確認(rèn)接口的能力。常用的定義格式為: unsignedshortflags;五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)net_device數(shù)據(jù)結(jié)構(gòu)第八十八頁(yè),共103頁(yè)。與字符設(shè)備和塊設(shè)備的情況一樣,每個(gè)網(wǎng)絡(luò)設(shè)備要聲明在其上操作的函數(shù)??梢栽诰W(wǎng)絡(luò)接口上進(jìn)行的操作列在下面。一些操作可以留為NULL,還有一些通常不去動(dòng)它們,因?yàn)閑ther_setup給它們分配合適的方法。一個(gè)網(wǎng)絡(luò)接口的設(shè)備方法可以分為兩類:基本的和可選的。基本的包括那些為訪問(wèn)接口所需要的;可選的方法實(shí)現(xiàn)一些并不嚴(yán)格要求的高級(jí)功能。五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)設(shè)備方法第八十九頁(yè),共103頁(yè)。open接口這個(gè)方法是打開(kāi)硬件接口。只要ifconfig激活一個(gè)接口,它就被打開(kāi)了。open方法要注冊(cè)它需要的所有資源(I/O端口,IRQ,DMA,等),打開(kāi)硬件,增加模塊的使用計(jì)數(shù)。其格式如下: int(*open)(structdevice*dev);stop接口跟open方法堆成的是stop接口,即終止接口。接口在關(guān)閉時(shí)就終止了;在打開(kāi)時(shí)進(jìn)行的操作應(yīng)被保留。其格式如下: int(*stop)(structdevice*dev);五、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)設(shè)備方法第九十頁(yè),共103頁(yè)。硬件開(kāi)始接口這個(gè)方法請(qǐng)求一個(gè)包的傳送。這個(gè)包含在一個(gè)套接字緩沖區(qū)結(jié)構(gòu)(sk_buff)中。套接字緩沖區(qū)在下面介紹。

int(*hard_start_xmit)(s

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論