【正文】
eans of a set of standardized calls that are independent of the specific driver。Linux內(nèi)核保留有大量的復(fù)雜代碼,通常設(shè)備驅(qū)動提供了一個門路,使硬件特殊的一部分響應(yīng)定義好的內(nèi)部編程接口,它們完全隱藏了設(shè)備工作的細(xì)節(jié)。用戶的活動通過一套標(biāo)準(zhǔn)化來進(jìn)行,設(shè)備驅(qū)動就是將這些調(diào)用映射到作用于實際硬件和設(shè)備相關(guān)的操作上。 mapping those calls to devicespecific operations that act on real hardware is then the role of the device driver.This thesis firstly introduces the fundamental knowledge about design of linux device driver, which generally includes the development procedure, kernel, and characteristic of linux. Meanwhile, the categorization of linux device, elemental terminology of exploiting network interface card driver, and loading and unloading the driver module are also mentioned in this thesis. Secondly, this thesis also presents both the hardware and software environment of the driver development, and the requirement specification of driver development are elaborated here. Thirdly, bined with the driver of ARM, this thesis discusses the design and realization of the network interface card driver in theory, especially makes more detailed discussions step by step, such as loading the driver module, initialization of the device, starting and stopping of the device, transmission and receiving of data, information statistics, unloading the driver module, etc. Allocating IP addresses and subnet masks differentiating network and host, through construction of TCP/IP network in Linux. Configuring host39。Linux作為一個開放源代碼的操作系統(tǒng),具有穩(wěn)定、高效、易裁減和硬件持廣泛等特點(diǎn),被廣泛應(yīng)用于嵌入式系統(tǒng)開發(fā)領(lǐng)域。他們對一些不合理的代碼進(jìn)行了改進(jìn),修補(bǔ)了代碼錯誤并上傳補(bǔ)丁。但就其總體而言,這些發(fā)行版本具有對盡可能多的網(wǎng)卡的支持。Linux設(shè)備驅(qū)動程序在Linux的內(nèi)核源代碼中占有很大的比例,源代碼長度的日益增加,主要就是驅(qū)動程序的增加。最后,每個網(wǎng)絡(luò)設(shè)備都聲明了很多能操作它的函數(shù),應(yīng)該熟悉較多的能夠?qū)W(wǎng)絡(luò)接口進(jìn)行操作的函數(shù),論文深入的研究了Linux下模塊設(shè)計的必要性,并通過編寫這些操作函數(shù)來實現(xiàn)網(wǎng)卡驅(qū)動模塊的加載以及網(wǎng)絡(luò)設(shè)備的初始化、設(shè)備打開與關(guān)閉、數(shù)據(jù)的發(fā)送與接收、信息統(tǒng)計、網(wǎng)卡驅(qū)動模塊的卸載等功能,章節(jié)中對重要函數(shù)都進(jìn)行了詳細(xì)的說明,這些實現(xiàn)了網(wǎng)卡驅(qū)動的基本要求。首先來分析一下Linux操作系統(tǒng)的體系結(jié)構(gòu),可以從兩個層次上來考慮操作系統(tǒng),如下圖 21所示:圖21 GNU/Linux操作系統(tǒng)的基本體系結(jié)構(gòu)圖最上面是用戶(或應(yīng)用程序)空間。內(nèi)核負(fù)責(zé)處理所有這些請求,根據(jù)內(nèi)核完成任務(wù)的不同,可以將內(nèi)核劃分成如下圖22的功能模塊:圖22 Linux系統(tǒng)模塊及功能圖 Linux的特性Linux是個人計算機(jī)和工作站上的Unix類操作系統(tǒng),但是,它絕不僅僅是簡化的Unix系統(tǒng)。Linux的進(jìn)程調(diào)度方式簡單而有效。內(nèi)存管理是和硬件平臺密切相關(guān)的部分,為了支持不同的硬件平臺而又保證虛擬存儲管理技術(shù)的通用性,Linux的虛擬內(nèi)存管理為不同的硬件平臺提供了統(tǒng)一的接口,因此把Linux內(nèi)核移植到一個新的硬件平臺并不是一件很困難的事。 Linux設(shè)備驅(qū)動程序概述驅(qū)動程序在 Linux內(nèi)核里扮演著特殊的角色。device),塊設(shè)備(block例如,幀抓取器就是這樣一個設(shè)備,應(yīng)用程序可以用mmap或lseek訪問抓取的整個圖象。許多網(wǎng)絡(luò)連接是面向流的,但網(wǎng)絡(luò)設(shè)備卻圍繞數(shù)據(jù)包的傳輸和接收而設(shè)計。一般是把一個中斷處理程序注冊到系統(tǒng)中去,操作系統(tǒng)在硬件中斷發(fā)生后調(diào)用驅(qū)動程序的處理程序。 Linux下網(wǎng)卡驅(qū)動程序設(shè)計的數(shù)據(jù)結(jié)構(gòu)和基本方法網(wǎng)絡(luò)驅(qū)動程序能夠完成數(shù)據(jù)的接收和傳輸,依靠的是網(wǎng)絡(luò)驅(qū)動程序的數(shù)據(jù)結(jié)構(gòu)以及其對該數(shù)據(jù)結(jié)構(gòu)進(jìn)行操作的設(shè)備方法。struct net_device *next;指向全局列表中下一個設(shè)備的指針。這些成員保存了設(shè)備使用的共享內(nèi)存的開始地址和結(jié)束地址。這個成員和內(nèi)存成員一樣,內(nèi)核不使用它們。這個成員只對某些外設(shè)總線有意義,例如 ISA。void hippi_setup(struct net_device *dev);初始化高性能并行接口(HIPPI)的高速互連驅(qū)動的成員。以太網(wǎng)的MTU是1500octet (ETH_DATA_LEN)。unsigned char addr_len;unsigned char broadcast[MAX_ADDR_LEN];unsigned char dev_addr[MAX_ADDR_LEN];硬件(MAC)地址長度和設(shè)備硬件地址。在這里討論一下能夠?qū)W(wǎng)絡(luò)接口進(jìn)行的操作。當(dāng)接口終止時當(dāng)它應(yīng)該被關(guān)閉。在以太網(wǎng)設(shè)備使用的缺省的函數(shù)中通過使用ARP協(xié)議來填充數(shù)據(jù)包缺少的硬件地址信息。通過這些可選的方法,實現(xiàn)禁止中斷、輪詢模式操作接口、執(zhí)行接口特有的ioctl命令、改變硬件地址、改變接口的MTU、以及hhcache的查詢更新等功能。網(wǎng)絡(luò)驅(qū)動程序要負(fù)責(zé)設(shè)置傳入數(shù)據(jù)包的mac指針,這個任務(wù)正常是由 eth_type_trans 處理,但是非以太網(wǎng)驅(qū)動不得直接設(shè)置skb。驅(qū)動程序負(fù)責(zé)將其設(shè)置為PACKET_HOST (數(shù)據(jù)包是給我的),PACKET_OTHERHOST,PACKET_BROADCAST,或者PACKET_MULTICAST。void kfree_skb(struct sk_buff *skb);void dev_kfree_skb(struct sk_buff *skb);void dev_kfree_skb_irq(struct sk_buff *skb);void dev_kfree_skb_any(struct sk_buff *skb);釋放一個緩沖區(qū)。int skb_tailroom(struct sk_buff *skb);該函數(shù)返回緩沖區(qū)中可用空間的大小。它遞減skblen和遞增skbdata;這是從傳入的數(shù)據(jù)包的頭部剝離硬件頭所使用的方法。在嵌入式設(shè)備中,硬件一般只是完成比較特定、專一的功能,一般選擇將驅(qū)動程序靜態(tài)編譯進(jìn)內(nèi)核,這樣可以獲得更高的效率。第4章 系統(tǒng)分析在一個以XLR處理器為核心處理器的嵌入式開發(fā)板中,開發(fā)一個DDOS系統(tǒng),應(yīng)用于商業(yè)、政府、軍隊等行業(yè),保障網(wǎng)絡(luò)的安全運(yùn)行。此外還包括:2個串口輸出,一個MIC輸入接口,一個LINE音頻輸入接口,一個耳機(jī)輸出接口,2個CPU可控LED,AD轉(zhuǎn)換輸入接口,SPI和IIC接口,JTAG調(diào)試接口,CPLD編程接口,擴(kuò)展GPRS和CDMA專用接口(,SPI口,IO引腳,電源等)。MII數(shù)據(jù)接口總共需要16個信號。網(wǎng)絡(luò)控制器可以用同樣的硬件接口與任何PHY進(jìn)行連接。例如對擴(kuò)展寄存器中的0號寄存器即接收/傳輸包的計數(shù)寄存器的訪問方式是:把23號寄存器的第8到11比特全部設(shè)置為1,激活擴(kuò)展寄存器;把23號寄存器的第0到7比特共8個比特設(shè)置0,表示對0號擴(kuò)展寄存器的訪問;讀或者寫21號寄存器,這時21號寄存器存放的值實際上就是0號擴(kuò)展寄存器的值。通過分析和參照其它網(wǎng)絡(luò)設(shè)備驅(qū)動程序,初步將開發(fā)板驅(qū)動程序的模塊結(jié)構(gòu)設(shè)計如下圖52所示:圖52 驅(qū)動程序?qū)崿F(xiàn)模式圖在圖52中看到,開發(fā)板網(wǎng)卡驅(qū)動程序整體結(jié)構(gòu)看起來比較的簡單,主要由模塊加載、網(wǎng)絡(luò)設(shè)備初始化、注冊、設(shè)備打開與關(guān)閉、數(shù)據(jù)的發(fā)送與接收等模塊構(gòu)成。內(nèi)核調(diào)用網(wǎng)卡驅(qū)動模塊的初始化函數(shù)rmi_phnx_mac_init_module(void),如果成功將把網(wǎng)卡驅(qū)動的模塊安裝到系統(tǒng)中,并把模塊的狀態(tài)設(shè)置成為RUNNING[15]。定義了設(shè)備指針以后,便開始實現(xiàn)設(shè)備的初始化。網(wǎng)卡最終是要用來接收和發(fā)送數(shù)據(jù)的,要接收或者發(fā)送以太網(wǎng)數(shù)據(jù)包就必須具有自己的內(nèi)存空間,即I/O內(nèi)存。實現(xiàn)該通道申請的函數(shù)是request_irq(…),參數(shù)rmi_phnx_mac_int_handler是自己定義的中斷處理函數(shù)指針。以上這些值的設(shè)置知識設(shè)備默認(rèn)的,也是以太網(wǎng)對接入以太網(wǎng)的設(shè)備的基本能力的要求。devstop = rmi_phnx_mac_close。網(wǎng)卡驅(qū)動程序定義了自己的設(shè)備打開與關(guān)閉、數(shù)據(jù)傳輸、狀態(tài)更新維護(hù)、組播別表的維護(hù)、接口ioctl命令執(zhí)行、數(shù)據(jù)傳輸超時處理、MTU改變設(shè)置等回調(diào)函數(shù),并讓設(shè)備的相關(guān)函數(shù)指針指向這些回調(diào)函數(shù),傳遞給linux內(nèi)核,在需要的時候由網(wǎng)絡(luò)系統(tǒng)負(fù)責(zé)調(diào)用。采用的自旋鎖的主要原因是,自旋鎖可以在不能休眠的代碼中使用,比如中斷處理例程,這正是網(wǎng)絡(luò)設(shè)備所具有的特點(diǎn)。privtype = phnx_mac_devices[i].type。}。通過privspill_configured這個字段就實現(xiàn)了在多處理器上程序并發(fā)執(zhí)行時的同步控制。設(shè)備的打開,意味著該設(shè)備將可以正常工作了。 void (*function)(unsigned long)。設(shè)備的端口基本配置,到這里就已經(jīng)全部結(jié)束了,但是我們還是可以在使用設(shè)備端口之前,重新按照我們的需要進(jìn)行端口的速率、雙工能力以及流量進(jìn)行等進(jìn)行配置。設(shè)備的關(guān)閉操作仍然需要在自旋鎖的保護(hù)下完成,否則可能發(fā)生資源的爭奪,導(dǎo)致系統(tǒng)錯誤。在設(shè)備進(jìn)行初始化的時候,把設(shè)備的devhard_start_xmit函數(shù)指針指向了驅(qū)動程序自己的數(shù)據(jù)發(fā)送函數(shù)rmi_phnx_mac_xmit,在有數(shù)據(jù)發(fā)送的時候,將調(diào)用rmi_phnx_mac_xmit函數(shù)完成數(shù)據(jù)的發(fā)送任務(wù)。驅(qū)動程序盡量保證了數(shù)據(jù)傳輸?shù)恼_M(jìn)行,而且完畢后正確釋放了skb,如果傳輸失敗,內(nèi)核將會重新試著再傳輸,在這種情況下,驅(qū)動程序沒有繼續(xù)進(jìn)行數(shù)據(jù)的傳輸而是停止了該隊列,等待傳輸失敗原因解決后再進(jìn)行傳輸。設(shè)備有自己的定時器,關(guān)閉設(shè)備時需要禁止該定時器繼續(xù)運(yùn)行,但在這里不是調(diào)用定時器的del_timer的API接口,而是通過調(diào)用del_timer_sync這個接口來實現(xiàn)的。一旦準(zhǔn)備好開始發(fā)送數(shù)據(jù)后,在設(shè)備打開的方法中還必須要啟動該端口的傳輸隊列,這樣來允許接口接收傳輸?shù)臄?shù)據(jù)包,內(nèi)核提供如下的函數(shù)啟動該隊列:netif_start_queue(dev)。 …}。數(shù)據(jù)緩沖區(qū)由skb_buf結(jié)構(gòu)保存。網(wǎng)絡(luò)設(shè)備的注冊由接口registre_netdevice()來完成,調(diào)用registre_netdevice() 向系統(tǒng)注冊網(wǎng)絡(luò)接口,在這個函數(shù)中將分配一個在系統(tǒng)中惟一的名稱給網(wǎng)絡(luò)接口,在驅(qū)動程序中就是將devname字段中的eth%d分別替換為eth0,eth1,eth2,eth3,并且將這些網(wǎng)絡(luò)接口設(shè)備添加到系統(tǒng)網(wǎng)絡(luò)設(shè)備的全局鏈表devbase中,注冊完成以后,系統(tǒng)知道有這個設(shè)備存在,就可以調(diào)用驅(qū)動程序來操作設(shè)備了。phnx_mac_devices數(shù)組中定義了四個元素,即四個端口,并且分別給出了每個端口的各個字段的初始值。privspill_configured = 0。自旋鎖使用上最重要的一個規(guī)則就是,自旋鎖必須盡可能的最在最短時間內(nèi)擁有。之前已經(jīng)描述過的ether_setup()函數(shù)為以太網(wǎng)設(shè)備設(shè)置了很多的默認(rèn)值,但是這些值在設(shè)置為默認(rèn)值之后,我們可以根據(jù)設(shè)備的實際數(shù)據(jù)處理能力修改這些設(shè)置。devset_multicast_list = rmi_phnx_mac_set_multicast_list。devbase_addr = mmio_start。下面就將介紹開發(fā)板網(wǎng)卡驅(qū)動程序是如何初始化設(shè)備指針以及成員函數(shù)的。devirq = phnx_mac_devices[i].irq。dev = alloc_etherdev(sizeof(struct driver_data));向系統(tǒng)申請內(nèi)存并且初始化一個以太網(wǎng)設(shè)備,并且使用eth%d的形式指定分配給網(wǎng)絡(luò)設(shè)備的名字,同時用以太網(wǎng)的默認(rèn)值初始化net_device中的大部分成員。函數(shù)rmi_phnx_mac_init_module是驅(qū)動程序模塊的入口點(diǎn),也是設(shè)備的初始化函數(shù),在這里完成了設(shè)備的初始化,并在最后完成初始化之后向系統(tǒng)注冊了該網(wǎng)卡設(shè)備。當(dāng)然,在實現(xiàn)的過程中,驅(qū)動程序遠(yuǎn)遠(yuǎn)不止這么簡單,還有很多的模塊沒有在圖52中列舉出來,如在多CPU上的同步控制、定時器的維護(hù)、數(shù)據(jù)傳輸超時處理、最大傳輸單元的控制、MII接口的