27.Linux-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上面

比如當在地址0X2000 0000上讀寫數據時,表示讀寫的數據是DM9000C的地址

訪問的地址0X2000 0004上讀寫數據時,表示讀寫的數據是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可以同時結束(bank4地址(也就是CMD)穩定多久后,CS片選才啟動)
  • 設置Tcos=T1=0(CS片選后,多久才能使能讀寫)
  • 設置Tacc=T2>=10ns=1,表示2個時鍾 (access cycle ,讀寫使能后,多久才能訪問數據)
  • 設置Tcoh=T4>=3ns=1,表示1個時鍾 ,因為當DM9000的寫信號取消后,數據線上的數據還需要至少3ns才消失(nOE讀寫取消后,片選需要維持多長時間)
  • 設置Tcah=0,因為 CS和CMD可以同時結束 (CS片選取消后,地址(也就是CMD)需要維持多長時間)

 

代碼如下圖,在init入口函數中設置

 

 

(PS:若DM9000C無法驅動,可能是Tacc時間太短,導致讀取不到數據,可以將Tacc設大一點)

與硬件相關的部分已經改好了,接下來開始編譯

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通,說明移植成功

 

 

 

下章學習:28.Linux-IIC驅動(詳解)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM