Linux2.6.38内核已经有自带的DM9000网上驱动,要移植DM9000的网卡驱动我们只要在内核原有的驱动代码上加以改动就可以了。我们先简单分析一下DM9000的驱动代码,DM9000的驱动的源文件目录为:drivers/net/dm9000.c,我们从它的入口函数进行分析:
static int __init
dm9000_init(void)
{
printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);
return platform_driver_register(&dm9000_driver);
}
入口函数很简单,只是注册了一个平台设备驱动。对应的平台设备是:
static struct platform_driver dm9000_driver = {
.driver = {
.name = "dm9000",
.owner = THIS_MODULE,
.pm = &dm9000_drv_pm_ops,
},
.probe = dm9000_probe,
.remove = __devexit_p(dm9000_drv_remove),
};
设备名称是:“dm9000”,跟踪进入dm9000_probe()函数进一步分析。进入dm9000_probe()函数,其它的先不用看,我们能看到一个这样的东西:
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
这是一个平台资源,所以我们要移植DM9000的驱动就得先为它构建一个相应的平台资源。db->addr_res是发送地址时使用的地址,db->data_res是发送数据时使用的地址,db->irq_res是中断号。
开始移植:
要移植DM9000网卡驱动,要修改的地方不多,主要修改arch/arm/plat-s3c24xx/common-smdk.c和drivers/net/dm9000.c两个文件,在common-smdk.c文件中加入平台设备资源,并添加设备,之后再修改dm9000.c的dm9000_probe()函数,加入相应的硬件操作,再修改dm9000_open()函数的中断注册就OK了,细节如下:
打开common-smdk.c文件:
vi arch/arm/plat-s3c24xx/common-smdk.c
1、包含头文件#include <linux/dm9000.h>
2、添加设备资源,定义下面几个结构体变量
static struct resource s3c_dm9k_resource[] = {
[0] = {
.start = S3C2410_CS4 , //发送地址时用到的地址
.end = S3C2410_CS4 + 3 ,
.flags = IORESOURCE_MEM ,
},
[1] = {
.start = S3C2410_CS4 + 4 , //发送数据时用到的地址
.end = S3C2410_CS4 + + 4 + 3 ,
.flags = IORESOURCE_MEM ,
},
[2] = {
.start = IRQ_EINT7 , //中断号
.end = IRQ_EINT7 ,
.flags = IORESOURCE_IRQ ,
},
};
static struct dm9000_plat_data s3c_dm9k_platdata = {
.flags = DM9000_PLATF_16BITONLY , //设置数据位宽为16位
};
//平台设备
static struct platform_device s3c_device_dm9k = {
.name = "dm9000" , //这里的名称必须与dm9000.c文件中驱动名称一样
.num_resources = ARRAY_SIZE(s3c_dm9k_resource) ,
.resource = s3c_dm9k_resource ,
.dev = {
.platform_data = &s3c_dm9k_platdata ,
}
};
注意:DM9000的访问基址为0x20000000(BANK4的基址),所以用到的内存址用S3C2410_CS4。
3、添加设备
static struct platform_device __initdata *smdk_devs[] = {
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
&s3c_device_dm9k, //在这里添加自己定义的平台设备
};
再修改drivers/net/dm9000.c文件中的dm9000_probe()函数和dm9000_open()函数,修改dm9000_probe()函数主要是设置存储器控制器使BANK4可用,修改dm9000_open()主要是修改中断注册。
1、打开dm9000.c文件,加入头文件#include <mach/regs-mem.h>
2、修改dm9000_probe()函数,在函数开头处定义两个变量用来保存寄存器的值,同时更改寄存器的值
unsigned int oldval_bwscon ;
unsigned int oldval_bankcon4 ;
oldval_bwscon = *((volatile unsigned int *)S3C2410_BWSCON) ;
*((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<16) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4 ;
Oldval_bankcon4 = *((volatile unsigned int *)S3C2410_BANKCON4) ;
*((volatile unsigned int *)S3C2410_BANKCON4 ) = 0x1f7c ;
3、异常退出时还原寄存器的值,在out:段下面加入以下代码
out:
*((volatile unsigned int *)S3C2410_BWSCON) = oldval_bwscon ;
*((volatile unsigned int *)S3C2410_BANKCON4) = oldval_bankcon4 ;
4、修改dm9000_open()函数,为中断注册标识加上升沿
... //部分代码
if (irqflags == IRQF_TRIGGER_NONE)
dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
irqflags |= IRQF_SHARED;
irqflags |= IRQF_TRIGGER_RISING; //加入上升沿
if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
return -EAGAIN;
... //部分代码
5、保存退出
代码修改完之后,make menuconfig选中DM9000网卡驱动编译进内核
Device Drivers --->
Network device support --->
[*] Network device support
Ethernet (10 or 100Mbit) --->
<*> DM9000 support
然后make uImage就OK了,编译好内核后下载到开发板启动,只要能看到跟下面内容类拟的输出就说明网卡驱动移植成功了。
IP-Config: Guessing netmask 255.255.255.0
IP-Config: Complete:
device=eth0, addr=192.168.7.159, mask=255.255.255.0, gw=255.255.255.255,
host=192.168.7.159, domain=, nis-domain=(none),
bootserver=255.255.255.255, rootserver=192.168.7.119, rootpath=