一般來說,我們在編譯kernel時,設備驅動的選擇有兩種方式:一種是直接編譯到kernel裡,另一種是以模塊方式掛接。
CS8900網卡驅動如果以模塊方式掛接,函數init_module就是入口;如果是直接編譯到kernel裡,那麼函數cs89x0_probe才是入口。在此入口函數中,將完成網卡驅動的各項初始化。如注冊虛擬地址,設備號,中斷號,以及各個相關寄存器的初始化。
cs89x0_probe函數裡會去調用真正的初始化函數cs89x0_probe1。下面說一下該初始化函數裡需要完成的幾個重要地方:
1、 注冊虛擬地址。
通過request_region函數注冊虛擬地址。在kenel裡面,我們所操作的寄存器的地址其實都是虛擬地址,但是每一個寄存器的虛擬地址都有唯一和其對應的物理地址,因為在kernel裡面任何虛擬地址都會通過MMU轉化成物理地址。所以在kernel裡,定義完所要用到的寄存器後,都必須使用一個函數ioremap將我們所要用到的寄存器的物理地址轉換成為在kernel裡可以操作的虛擬地址,然後才能將他們用以具體的操作,否則一切都是徒勞。 ioaddr = (int)ioremap(BASE_ADDR,16);
2、填充net_device結構體。
該結構體的成員都是和網絡設備有關的變量。其中比較重要的有兩個:dev_addr和open。dev_addr裡要存的是主機的MAC地址,一般都是從eeproom中讀出來再存放到該變量中,當然也可以根據自己的需要手動賦值。
for (i=0; i < ETH_ALEN/2; i++) { unsigned int Addr; Addr = readreg(dev, PP_IA+i*2); dev->dev_addr[i*2] = Addr & 0xFF; dev->dev_addr[i*2+1] = Addr >> 8; }
writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); request_irq(dev->irq, &net_interrupt, 0, dev->name, dev);
writel(readl(S 3C2410_GPGCON) | 0x8, S3C2410_GPGCON); writel(readl(S3C2410_EXTINT1) | 0x40, S3C2410_EXTINT1);
static u16 readword(unsigned long base_addr, int portno) { return inw(base_addr + portno); } static void writeword(unsigned long base_addr, int portno, u16 value) { outw(value, base_addr + portno); }