<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 嵌入式Linux網(wǎng)絡(luò )驅動(dòng)程序開(kāi)發(fā)設計

嵌入式Linux網(wǎng)絡(luò )驅動(dòng)程序開(kāi)發(fā)設計

作者: 時(shí)間:2012-02-16 來(lái)源:網(wǎng)絡(luò ) 收藏

引言

本文引用地址:http://dyxdggzs.com/article/149659.htm

隨著(zhù)人們對開(kāi)放源代碼軟件熱情的日益增高,作為一個(gè)功能強大而穩定的開(kāi)源操作系統,越來(lái)越受到成千上萬(wàn)的計算機專(zhuān)家和愛(ài)好者的青睞。在領(lǐng)域,通過(guò)對進(jìn)行小型化裁剪后,使其能夠固化在容量只有幾十兆字節的存儲器芯片或單片機中,成為應用于特定場(chǎng)合的系統。Linux強大的支持功能實(shí)現了對包括TCP/IP在內的多種協(xié)議的支持,滿(mǎn)足了面向21世紀的系統應用聯(lián)網(wǎng)的需求。因此,在嵌入式系統開(kāi)發(fā)調試時(shí),接口幾乎成為不可或缺的模塊。

1 嵌入式Linux介紹

Linux網(wǎng)絡(luò )作為L(cháng)inux網(wǎng)絡(luò )子系統的一部分,位于TCP/IP網(wǎng)絡(luò )體系結構的網(wǎng)絡(luò )接口層,主要實(shí)現上層協(xié)議棧與網(wǎng)絡(luò )設備的數據交換。Linux的網(wǎng)絡(luò )系統主要是基于BSD Unix的套接字(socket)機制,網(wǎng)絡(luò )設備與字符設備和塊設備不同,沒(méi)有對應地映射到文件系統中的設備節點(diǎn)。

通常,Linux有兩種加載方式:一種是靜態(tài)地編譯進(jìn)內核,內核啟動(dòng)時(shí)自動(dòng)加載;另一種是編寫(xiě)為內核模塊,使用insmod命令將模塊動(dòng)態(tài)加載到正在運行的內核,不需要時(shí)可用rmmod命令將模塊卸載。Linux 2.6內核引入了kbuild機制,將外部?jì)群四K的編譯同內核源碼樹(shù)的編譯統一起來(lái),大大簡(jiǎn)化了特定的參數和宏的設置。這樣將編寫(xiě)好的驅動(dòng)模塊加入內核源碼樹(shù),只需要修改相應目錄的KcONfig文件,把新的驅動(dòng)加入內核的配置菜單,然后需要修改相應子目錄中與模塊編譯相關(guān)的Kbuild Makefile,即可使新的驅動(dòng)在內核源碼樹(shù)中被編譯。在嵌入式系統驅動(dòng)開(kāi)發(fā)時(shí),常常將驅動(dòng)程序編寫(xiě)為內核模塊,方便開(kāi)發(fā)調試。調試完畢后,就可以將驅動(dòng)模塊編譯進(jìn)內核,并重新編譯出支持特定物理設備的Linux內核。

2 嵌入式Linux網(wǎng)絡(luò )驅動(dòng)程序的體系結構和實(shí)現原理

2.1 Linux網(wǎng)絡(luò )設備驅動(dòng)的體系結構

如圖1所示,Linux網(wǎng)絡(luò )驅動(dòng)程序的體系結構可劃分為4個(gè)層次。Linux內核源代碼中提供了網(wǎng)絡(luò )設備接口及以上層次的代碼,因此移植特定網(wǎng)絡(luò )硬件的驅動(dòng)程序的主要工作就是完成設備驅動(dòng)功能層的相應代碼,根據底層具體的硬件特性,定義網(wǎng)絡(luò )設備接口STruct net_Device類(lèi)型的結構體變量,并實(shí)現其中相應的操作函數及中斷處理程序。

Linux中所有的網(wǎng)絡(luò )設備都抽象為一個(gè)統一的接口,即網(wǎng)絡(luò )設備接口,通過(guò)struct net_device類(lèi)型的結構體變量表示網(wǎng)絡(luò )設備在內核中的運行情況,這里既包括回環(huán)(loopback)設備,也包括硬件網(wǎng)絡(luò )設備接口。內核通過(guò)以dev_base為頭指針的設備鏈表來(lái)管理所有的網(wǎng)絡(luò )設備。

2.2 net_device 數據結構

struct net_device結構體是整個(gè)網(wǎng)絡(luò )驅動(dòng)結構的核心,其中定義了很多供網(wǎng)絡(luò )協(xié)議接口層調用設備的標準方法,該結構在2.6內核源碼樹(shù)文件中定義,下面只列出其中主要的成員。

2.2.1全局信息及底層硬件信息

  name:網(wǎng)絡(luò )設備名稱(chēng),默認是以太網(wǎng);

  *next:指向全局鏈表下一個(gè)設備的指針,驅動(dòng)程序中不修改;

  mem_,rmem_:發(fā)送和接收緩沖區的起始,結束位置;

  base_addr,IRq:網(wǎng)絡(luò )設備的I/O基地址,中斷號,ifconfig命令可顯示和修改;

  hard_header_len:硬件頭的長(cháng)度,以太網(wǎng)中值為14;

  mtu:最大傳輸單元,以太網(wǎng)中值為1500B;

  dev_addr[MAX_ADDR_LEN]:硬件(MAC)地址長(cháng)度及設備硬件地址,以太網(wǎng)地址長(cháng)度是48bit,ether_setup會(huì )對其進(jìn)行正確的設置;

2.2.2 主要的操作方法

  int (*init)(struct net_device *dev); 設備初始化和向系統注冊的函數,僅調用一次;

  int (*open)(struct net_device *dev);設備打開(kāi)接口函數,當用ifconfig激活網(wǎng)絡(luò )設備時(shí)被調用,注冊所用的系統資源(I/O端口,IRQ,DMA等)同時(shí)激活硬件并增加使用計數;

  int (*stop)(struct net_device *dev);執行open方法的反操作;

  *hard_start_xmit;初始化數據包傳輸的函數;

  *hard_header;該函數(在hard_start_xmit前被調用)根據先前檢索到的源和目標硬件地址建立硬件頭。 eth_header是以太網(wǎng)類(lèi)型接口的默認函數;

2.3網(wǎng)絡(luò )驅動(dòng)程序的編寫(xiě)及實(shí)現原理

Linux網(wǎng)絡(luò )系統各個(gè)層次之間的數據傳送都是通過(guò)套接字緩沖區sk_buff完成的,sk_buff數據結構是各層協(xié)議數據處理的對象。sk_buff是驅動(dòng)程序與網(wǎng)絡(luò )之間交換數據的媒介,驅動(dòng)程序向網(wǎng)絡(luò )發(fā)送數據時(shí),必須從其中獲取數據源和數據長(cháng)度;驅動(dòng)程序從網(wǎng)絡(luò )上接收到數據后也要將數據保存到sk_buff中才能交給上層協(xié)議處理。

對于實(shí)際開(kāi)發(fā)以太網(wǎng)驅動(dòng)程序,可以參照內核源碼樹(shù)中的相應模板程序,重點(diǎn)理解網(wǎng)絡(luò )驅動(dòng)的實(shí)現原理和程序的結構框架,然后針對開(kāi)發(fā)的特定硬件改寫(xiě)代碼,實(shí)現相應的操作函數。下面結合作者利用Linux2.6.18內核在深圳優(yōu)龍公司的FS2410開(kāi)發(fā)板(SAMSUNG S3C2410處理器)上移植編寫(xiě)嵌入式CS8900A網(wǎng)卡驅動(dòng)程序的實(shí)例,說(shuō)明網(wǎng)絡(luò )驅動(dòng)程序的實(shí)現原理。

2.3.1網(wǎng)絡(luò )設備初始化

網(wǎng)絡(luò )設備的初始化是由net_device結構中的init函數實(shí)現的,內核加載網(wǎng)絡(luò )驅動(dòng)模塊后,就會(huì )調用初始化過(guò)程。實(shí)例中初始化函數_init Cs8900_probe中主要完成的工作:

  a.調用內核中通用的設置以太網(wǎng)接口的函數ether_setup();

  b.填充net_device結構體變量dev中其它大部分成員;

  c.調用check_mem_region()檢測I/O地址空間,然后調用request_mem_region()申請以dev->base_addr為起始地址的16個(gè)連續的 I/O地址空間;

  d.通過(guò)cs8900_read()探測網(wǎng)卡CS8900A,讀取ID信息;

  e.設置CS8900A的INTRQ0作為中斷信號輸出引腳;

  f.將MAC地址寫(xiě)入CS8900A的IA寄存器中;

  g.通過(guò)register_netdev()將CS8900A注冊到Linux全局網(wǎng)絡(luò )設備鏈表中;

2.3.2打開(kāi)(或關(guān)閉)網(wǎng)絡(luò )設備

系統響應ifconfig命令時(shí),打開(kāi)(關(guān)閉)一個(gè)網(wǎng)絡(luò )接口。ifconfig命令開(kāi)始會(huì )調用ioctl(SIOCSIFADDR)來(lái)將地址賦予接口。響應SIOCSIFADDR由內核來(lái)完成,與設備無(wú)關(guān)。接著(zhù),ifconfig命令會(huì )調用ioctl(SIOCSIFFLAGS)設置dev->flag的IFF_UP位來(lái)打開(kāi)設備,這個(gè)調用會(huì )使設備的open方法得到調用。(當ifconfig調用ioctl(SIOCSIFFLAGS)清除dev->flag的IFF_UP位時(shí),設備的stop方法將被調用)

實(shí)例中利用cs8900_start()函數打開(kāi)網(wǎng)絡(luò )設備,主要完成的工作:

  a.通過(guò)set_irq_type()向內核注冊網(wǎng)絡(luò )設備的中斷處理程序;

  b.通過(guò)cs8900_set()設置CS8900A網(wǎng)卡中各控制寄存器和配置寄存器;

  c.通過(guò)內核中netif_start_queue()函數開(kāi)啟網(wǎng)絡(luò )接口的數據傳輸隊列;

2.3.3網(wǎng)絡(luò )數據包的發(fā)送

數據包的發(fā)送和接收是網(wǎng)絡(luò )驅動(dòng)程序中實(shí)現的兩個(gè)最重要的任務(wù)。當網(wǎng)絡(luò )設備被激活時(shí),net_device結構中的open方法被調用,它負責打開(kāi)設備并調用net_device結構中的hard_header函數指針建立硬件幀頭信息。最后通過(guò)函數dev_queue_xmit()來(lái)調用net_device結構中的hard_start_xmit方法把存放在sk_buff中的數據發(fā)送到網(wǎng)絡(luò )物理設備。如果發(fā)送成功,則在hard_start_xmit中釋放sk_buff并返回0;如果硬件設備忙暫時(shí)無(wú)法處理,則返回1。網(wǎng)絡(luò )硬件在發(fā)送完數據包后會(huì )產(chǎn)生中斷,把dev->tbusy置0,通知系統可以再次發(fā)送。

實(shí)例中,hard_start_xmit方法即為網(wǎng)絡(luò )設備數據發(fā)送函數cs8900_send_start(),該函數實(shí)現把數據發(fā)送到以太網(wǎng)上,由網(wǎng)絡(luò )協(xié)議接口層函數dev_queue_xmit()對其調用。

  cs8900_send_start()中主要完成的工作:

  a.發(fā)送數據前關(guān)閉中斷,中止網(wǎng)絡(luò )設備的數據傳輸隊列;

  b.向CS8900A寄存器TxCMD中寫(xiě)入傳送數據命令控制字,向寄存器TxLength中寫(xiě)入待發(fā)送數據幀長(cháng)度;

  c.通過(guò)cs8900_read()反復讀取CS8900A總線(xiàn)狀態(tài)寄存器BusST信息,直到其已經(jīng)準備好接收來(lái)自主機的數據;

  d.調用cs8900_frAME_write()將待發(fā)數據送入CS8900A的sk_buff中,硬件設備會(huì )將數據幀發(fā)送到以太網(wǎng)上;

  e.記錄數據幀的發(fā)送時(shí)刻,打開(kāi)中斷,釋放sk_buff緩存,函數返回0;

2.3.4網(wǎng)絡(luò )數據包的接收和中斷處理

網(wǎng)絡(luò )設備是異步地接收外來(lái)的數據包并且主動(dòng)的“請求”將硬件獲得的數據包壓入內核。網(wǎng)絡(luò )設備接收數據包是通過(guò)中斷實(shí)現的。對于網(wǎng)絡(luò )接口,接收到新數據包,發(fā)送完成或者報告錯誤信息及連接狀態(tài)等都會(huì )觸發(fā)中斷,通常中斷處理程序通過(guò)檢測硬件狀態(tài)寄存器判斷是哪種情況。

當設備收到數據后會(huì )產(chǎn)生一個(gè)中斷,由硬件通知驅動(dòng)程序有數據包到達。在中斷處理程序中驅動(dòng)程序申請一塊sk_buff(一般定義為skb)緩沖區,然后從硬件讀出數據放到申請好的緩沖區里,接下來(lái)填充sk_buff中的部分信息:包括接收到數據的設備結構體指針填入skb->dev;收到數據幀的類(lèi)型填入skb->protocol;把指針skb->mac.raw指向硬件數據并丟棄硬件針頭(skb_pull);設置skb->pkt_type,標明鏈路層數據類(lèi)型。最后調用協(xié)議接口層函數netif_rx() 把接收到的數據包傳輸到網(wǎng)絡(luò )上層協(xié)議處理。這里,netif_rx()只是負責把數據放入工作隊列就返回,真正的處理是在中斷返回以后,這樣可減少中斷處理的時(shí)間。幾乎每個(gè)中斷處理程序的編寫(xiě)都要涉及底半部機制,這樣可以保證中斷的高效處理。

實(shí)例中數據接收函數cs8900_receive()由網(wǎng)絡(luò )驅動(dòng)的中斷處理函數調用,主要完成如下工作:

  a.通過(guò)從I/O口讀取RxStatus和RxLength的值,確定接收數據幀的狀態(tài)信息和長(cháng)度;

  b.判斷接收數據幀的狀態(tài)是否正常,若異常則記錄相關(guān)錯誤信息,然后函數返回;

  c.正常情況下,在內存中申請一塊sk_buff緩存,并將數據從CS8900A的片內存儲器傳送到sk_buff緩存中;d.從數據幀中獲取協(xié)議頭并賦給skb->protocol;

  e.通過(guò)調用netif_rx()函數將接收到的數據送往上層協(xié)議棧進(jìn)行處理;

  f.記錄接收數據的時(shí)間并更新統計信息;

3 將設備驅動(dòng)模塊編譯進(jìn)內核

設計好模塊化的網(wǎng)絡(luò )驅動(dòng)程序后,我們就可以編譯這個(gè)內核模塊,并將這個(gè)自定義的內核模塊作為L(cháng)inux系統源碼的一部分編譯出新的系統。下面介紹的內容均在Linux2.6.18內核上編譯通過(guò),可以在2.6.x版本內核中通用。如前所述,由于Linux2.6內核引入了kbuild的新機制,使得編譯新的內核模塊或者將自己編寫(xiě)的內核模塊集成到內核源碼中都變得非常簡(jiǎn)單了。

Linux2.6內核中,編譯內核模塊首先要在/usr/src下正確配置和構造內核源碼樹(shù),即把需要版本的內核源碼解壓在/usr/src/,并在內核源碼的主目錄下(這里為/usr/src/linux-2.6.18.3),使用make menuconfig或者make gconfig命令配置內核,然后使用make all完整編譯內核。

下面以作者開(kāi)發(fā)的CS8900A網(wǎng)卡驅動(dòng)為實(shí)例,介紹如何將網(wǎng)絡(luò )設備驅動(dòng)模塊編譯進(jìn)內核。

  a.在系統源碼樹(shù)drivers目錄下創(chuàng )建新目錄Cs8900;

  b.將編寫(xiě)好的文件cs8900.c和cs8900.h拷貝到drivers/Cs8900目錄下;

  c.在drivers/Cs8900目錄下,編寫(xiě)Makefile文件:

 ?。akefile for CS8900A Network Driver

  obj -$(CONFIG_DRIVER_CS8900A) +=cs8900.o

  d.在drivers/Cs8900目錄下,編寫(xiě)Kconfig文件:

 ?。ust for CS8900A Network Interface

  menu CS8900A Network Interface support

  config DRIVER_CS8900A

  tristate CS8900A support

  --------help--------

  This is a network driver module for CS8900A.

  endmenu

  e.在driver目錄下的Kconfig文件endmenu語(yǔ)句前,加入一行:

  source drivers/Cs8900/Kconfig

這樣在內核源碼樹(shù)的主目錄下,通過(guò)make menuconfig或者make gconfig命令就可以在Device Drivers選項的下面找到CS8900A Network Interface support選項,并找到CS8900A support的選擇菜單,它有三種狀態(tài):未選中(不編譯)、選中(M)一編譯為模塊、選中(*)一編譯為新系統一部分。

重新編譯內核即可得到支持CS8900A網(wǎng)卡的內核,然后將內核下載到FS2410的開(kāi)發(fā)板上,通過(guò)配置網(wǎng)絡(luò )參數,就可以測試網(wǎng)卡驅動(dòng)程序的行為了。

4 結束語(yǔ)

在這個(gè)信息爆炸的時(shí)代,人們對于網(wǎng)絡(luò )的需求愈發(fā)強烈,越來(lái)越多的嵌入式設備都需要具有以太網(wǎng)的接入功能,因此開(kāi)發(fā)網(wǎng)絡(luò )驅動(dòng)程序對于很多嵌入式產(chǎn)品的研發(fā)至關(guān)重要。具體開(kāi)發(fā)嵌入式Linux網(wǎng)絡(luò )驅動(dòng)程序時(shí),可以參照內核中已經(jīng)支持的網(wǎng)絡(luò )驅動(dòng)源代碼,在重點(diǎn)理解Linux網(wǎng)絡(luò )驅動(dòng)實(shí)現原理的基礎上,按照模塊設計較為固定的開(kāi)發(fā)模式,結合具體物理設備的硬件手冊,移植編寫(xiě)需要的模塊化的網(wǎng)絡(luò )驅動(dòng)程序。

linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)


評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>