上一節 我們學習了: 網卡驅動介紹以及製作虛擬網卡驅動: http://www.cnblogs.com/lifexy/p/7763352.html 接下來本節,學習網卡晶元DM9000C,如何編寫移植DM9000C網卡驅動程式。 1.首先來看DM9000C原理圖 如下圖所示: (#:表示低電平有效) ...
上一節 我們學習了:
網卡驅動介紹以及製作虛擬網卡驅動: http://www.cnblogs.com/lifexy/p/7763352.html
接下來本節,學習網卡晶元DM9000C,如何編寫移植DM9000C網卡驅動程式。
1.首先來看DM9000C原理圖
如下圖所示:
(#:表示低電平有效)
- SD0~15: 16位數據線,有CMD引腳決定訪問類型
- CMD: 命令線,當CMD為高,表示SD 傳輸的是數據,CMD為低表示傳輸的是地址
- INT: 中斷引腳,接在2440的GPF7腳上
- IOR#: 讀引腳,接在2440的nOE腳上
- IOW#: 寫引腳,接在2440的nWE腳上
- CS#: 片選,放在2440的bank4的片選上面
1.1其中2440手冊的bank4地址區間如下圖:
bank4的區間位於: 0X20000000~0X28000000,當我們訪問這個區間的地址,記憶體控制器便會使能網卡DM9000C的使能腳,所以我們的DM9000C的io基地址=0X20000000
其中DM9000C的CMD引腳接在bank4的LADDR2上面
所以當訪問的io基地址=0X2000 0000,表示讀寫的地址里的內容是DM9000C的地址
訪問的io基地址=0X2000 0100,表示讀寫的地址里的內容是DM9000C的數據
1.2 DM9000C收發過程
當DM9000C收到外部的數據後,會暫存到內部地址中,然後產生一個上升沿中斷,等待2440讀取數據
當DM9000C將2440的數據轉發出去後,也會產生一個上升沿中斷給2440
如下圖所示,DM9000C的中斷引腳位於pin34腳
接在2440的GPF7引腳上,使用的中斷為EINT7
接下來便來修改廠家提供的DM9000C源代碼
2.發現它的init_module()入口函數前有個條件編譯
所以要註釋掉 “#ifdef MODULE” 和 “#endif”
3.修改入口出口函數名,並修飾它們(修改函數名避免與內核的其它函數重名)
4.修改驅動的硬體相異性(設置基地址,寄存器,中斷等)
4.1先來找找代碼在哪裡初始化DM9000C硬體的
進入dm9000c_init()
-> dmfe_probe()
其中dmfe_probe()函數如下:
struct net_device * __init dmfe_probe(void) { struct net_device *dev; dev= alloc_etherdev(sizeof(struct board_info)); //分配一個net_device結構體 ... ... err = dmfe_probe1(dev); //調用dmfe_probe1()函數 ... ... err = register_netdev(dev); //向內核註冊net_device結構體 ... ... }
顯然dmfe_probe1()函數就是用來初始化DM9000C硬體和設置net_device結構體的成員用的
4.2 進入dmfe_probe1()函數
如下圖,這個iobase 變數就是我們DM9000C的io基地址0x20000000
iobase的作用:
如上圖, 讀一次DM9000C的VID低位元組之前,需要先將地址賦為0x20000000,也就是將DM9000C的CMD置0,然後向0x20000000寫入要讀的DM9KS_VID_L地址值
最後再將地址+4,也就是賦為0x20000100,將CMD置1,然後讀出0x20000100的值,也就是DM9000C的VID低位元組
DM9000C的讀寫方式都是這樣的,先將CMD置0,寫入DM9000C的地址,然後再將CMD置1,來讀寫數據
4.3所以在init函數中便重新設置iobase 變數,其中iobase是int型
併在exit出口函數中,添加iounmp()
4.4 繼續進入dmfe_probe1()函數,往下看
如下圖所示,屏蔽紅框里的代碼,該代碼用來核對版本,我們的DM9000C版本號不一樣,所以要屏蔽
4.5 在init函數中,修改中斷名,將irq改為IRQ_EINT7
4.6 修改中斷
當使用了register_netdev()註冊了網卡驅動net_device後,在內核中使用ifconfig就會進入net_device->open成員函數申請中斷,激活隊列等
所以我們要修改open成員函數的申請中斷函數,將觸發中斷改為“IRQT_RISING”,上升沿觸發
5.接下來便開始設置2440的存儲控制寄存器
設置2440的bank4的硬體位寬,時序,因為不同的硬體,涉及的數據收發都不同,
5.1設置BWSCON匯流排寬度控制寄存器
我們只設置BANK4的內容,所以只有下麵3個(BANK0的位寬由OM[1:0] 硬體設置)
設置ST4=0,不使用UB/LB(UB/LB:表示高位元組與低位元組數據是否分開傳輸)
設置WS4=0,其中WAIT引腳為PE4,而我們DM9000C沒有引腳接入PE4,所以禁止
設置DW4=0x01,我們的DM9000C的數據線為16位
5.2設置BANKCON4控制寄存器
設置這些時序之前,首先來看DM9000C晶元手冊時序圖和2440的時序圖
參考上圖,得出BANKCON4 寄存器設置如下(HCLK=100MHZ,1個時鐘等於10ns)
設置Tacs=0,CS和CMD信號可以同時進行(CMD腳就是2440的地址引腳)
設置Tcos=T1=0(CS片選使能後維持時間)
設置Tacc=T2=0,要>=10ns(讀寫信號的訪問維持時間)
設置Tcoh=T4=1,要>=3ns(片選結束維持時間)
設置Tcah=T8=0, CS和CMD信號可以同時結束(地址匯流排結束維持時間)
代碼如下圖,在init入口函數中設置
與硬體相關的部分已經改好了,接下來開始編譯
6.編譯測試
編譯之前,首先添加該驅動需要的內核頭文件:
#include <asm/delay.h> #include <asm/irq.h> #include <linux/irq.h> #include <asm/io.h> #include <asm/arch-s3c2410/regs-mem.h>
編譯無誤後,便開始測試DM9000C驅動程式:
1) 把dm9dev9000c.c放到內核的drivers/net目錄下,來替換原來內核的DM9000C
2) 修改drivers/net/Makefile
把
obj-$(CONFIG_DM9000) += dm9000.o
改為(如下圖所示)
obj-$(CONFIG_DM9000) += dm9dev9000c.o
3) make uImage
如下圖,說明新的驅動已編譯進內核
4) 使用新內核啟動
ifconfig eth0 192.168.2.107
ping 192.168.2.1
如下圖,可以ping通,說明移植成功