轉載自: http://my.csdn.net/weiqing1981127
一.網絡設備驅動基礎
1. 以太網基礎理論
以太網是局域網的一種,它使用載波監聽多路訪問及沖突檢測技術(CSMA/CD),並以10M/S的速率運行在多種類型的電纜上,常用的網卡芯片有DM9000、DM9161、CS8900芯片。
以太網的拓撲結構有總線型和星型,以太網的工作模式有半雙工和全雙工。目前雙絞線是以太網最普通的傳輸介質,它多用於從主機到集線器或交換機的連接,光纖主要用於交換機間的級聯和交換機到路由器間的點到點的鏈路上。
在局域網中,多個節點是共享傳輸介質的,這就必須有某種機制來決定某個時刻,哪個設備占用傳輸介質來傳輸數據,因此,局域網的鏈路層要有介質訪問控制的功能,即數據鏈路層分為邏輯鏈路控制LLC子層和介質訪問控制MAC子層。
以太網的幀結構主要有Ethernet II 、Ethernet 802.3raw、Ethernet802.3SAP、Ethernet802.3SNAP
以太網控制器實現了MAC層功能,而且必須與PHY(物理層收發器)聯合使用,前者與OSI的數據鏈路層相關,后者實現物理層功能。MII(媒體無關接口)是連接快速以太網MAC和PHY的標准接口,以太網的設備驅動是通過MII與PHY通信,以配置PHY ID、速率、雙工模式等參數。
2. Linux網絡驅動層次
Linux網絡驅動可以划分四層,即網絡協議接口層、網絡設備接口層、設備驅動功能層和設備物理媒介層,內核中是通過以dev_base為頭指針的設備鏈表來管理所有的網絡設備。網絡設備驅動的編寫主要是網絡設備net_device的初始化和數據包的收發函數。
網絡協議接口層
網絡協議接口層最主要的功能是給上層協議提供了透明的數據包發送和接收接口,當上層的API或IP需要發送數據包時,它將調用網絡協議接口層的dev_queue_xmit函數發送一個內容為sk_buff的數據;當上層對數據包的接收數據,則是通過向netif_rx函數傳遞一個sk_buff數據結構的指針來完成的。Sk_buff套接字緩沖區為linux網絡層提供了高效的緩沖區處理和流量控制機制,當發送數據包時,Linux內核的網絡處理模塊必須建立一個需要傳輸的數據包sk_buff,然后將sk_buff遞交給下層,各層在sk_buff中添加不同的協議頭直至交給網絡設備發送。同樣的,當網絡設備從網絡媒介上接收到數據包后,必須去掉不同的協議頭再交給用戶。
下面是sk_buff的部分結構體成員定義
struct sk_buff {
……
unsigned int len,
data_len;
__u16 mac_len,
hdr_len;
sk_buff_data_t transport_header; //傳輸層的頭
sk_buff_data_t network_header; //網絡層的頭
sk_buff_data_t mac_header; //MAC層的頭
sk_buff_data_t tail; //有效數據的尾指針
sk_buff_data_t end;
unsigned char *head, //整個緩沖區的頭
*data; //有效數據的頭指針
unsigned int truesize;
atomic_t users;
};
對於sk_buff操作,除了分配和釋放外,需要知道如下幾個函數:在緩沖區尾部增加數據skb_put;在緩沖區開頭增加數據skb_push;在緩沖區開頭移除數據skb_pull;調整整個緩沖區的頭部skb_reserve。
網絡設備接口層
網絡設備接口層主要是為變化多端的網絡定義了一個統一且抽象的net_device,實現了多種硬件在軟件層次上的統一。網絡設備驅動主要是填充net_device的成員並注冊net_device來實現硬件操作函數和內核的掛接。通常情況下,網絡設備驅動以中斷方式接受數據,而net_device中則定義了poll_controller這種純輪詢的接口方式,另外由於寬帶接口每秒會收到幾千個數據包,如果使用中斷方式會導致系統性能下降,為了提高linux在寬帶系統上的性能,網絡子系統開發者創建了一種基於輪詢的數據接收方式是NAPI(New API),其數據接收流程是”接收中斷來臨—關閉接收中斷—以輪詢方式接收完所有數據—開啟接收中斷—接收中斷來臨……”,與NAPI相關的函數有添加NAPI,使能NAPI,調度NAPI,具體函數是netif_napi_add,napi_enable,napi_schedule。最后需要注意的是對於NAPI方式和中斷方式接收數據,驅動設計上還是有一些不同的,比如NAPI方式是用netif_receive_skb函數將數據包傳遞給內核,而不是使用netif_rx函數。
設備驅動功能層
對於具體的設備,工程師應該實現net_device中的open,stop,tx,hard_header,get_stats,tx_timeout,interruppt等函數。
網絡設備媒介層
網絡設備媒介層直接對應實際的硬件設備,我們需要定義一組讀寫設備內部寄存器的函數,如ior,iow。
二.網絡設備驅動移植
下面我們主要講解基於mini2440的DM9000網卡驅動的移植
首先看內涵DM9000代碼在/driver/net/dm9000.c
查看/driver/net/Makefile
obj-$(CONFIG_DM9000) += dm9000.o
查看/driver/net/Konfig
menuconfig NET_ETHERNET
bool "Ethernet (10 or 100Mbit)"
config DM9000
tristate "DM9000 support"
depends on ARM || BLACKFIN || MIPS
select CRC32
select MII
所以配置內核make menuconfig 時,需要選中這一項。
根據開發板電路圖知道DM9000的AEN端口接到了nGCS4上,同時DM9000的INT端口接到了IRQ_EINT7上,另外DM9000的CMD端口接到了LADDR2上,最后發現DM9000上數據線是SD0-SD15,即數據線的位數是16位。
根據mini2440地址空間的分配與片選信號的定義知道,引腳nGCS4對應的空間的起始地址為0x20000000,這個由系統地址線控制。同時我們知道DM9000使用的中斷號就是IRQ_EINT7。另外,DM9000上的CMD信號是控制地址端口還是數據端口的,如果CMD為0,即LADDR2為0表示訪問地址寄存器,當CMD為1,即LADDR2為1表示訪問數據寄存器。
下面我們進行DM9000驅動的移植,在mach-mini2440.c中添加如下代碼
#include <linux/dm9000.h>
#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300)
static struct resource mini2440_dm9k_resource[] = {
[0] = { //地址端口
.start = MACH_MINI2440_DM9K_BASE,
.end = MACH_MINI2440_DM9K_BASE + 3,
.flags = IORESOURCE_MEM
},
[1] = { //數據端口
.start = MACH_MINI2440_DM9K_BASE + 4,
.end = MACH_MINI2440_DM9K_BASE + 7,
.flags = IORESOURCE_MEM
},
[2] = { //中斷號
.start = IRQ_EINT7,
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,//高電平觸發
}
};
static struct dm9000_plat_data mini2440_dm9k_pdata = {
//數據線的位數是16位,沒有使用E2PROM
.flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
.dev_addr = { 0x08,0x90,0x90,0x90,0x90,0x90}, //MAC地址
};
static struct platform_device mini2440_device_eth = {
.name = "dm9000", //設備名
.id = -1,
.num_resources = ARRAY_SIZE(mini2440_dm9k_resource),
.resource = mini2440_dm9k_resource, //資源
.dev = {
.platform_data = &mini2440_dm9k_pdata, //私有數據
},
};
最后在mini2440的BSP文件mach-mini2440.c中添加如下代碼
static struct platform_device *mini2440_devices[] __initdata = {
……
& mini2440_device_eth, //添加
};
這樣移植完畢后編譯內核生成內核鏡像。
