Linux2.6.14 下已经有DM9000的驱动源代码,我们要做的工作是使内核支持它,移植的关键是接口与中断。其它工作就完全交给源代码了。
移植工作包括三件事情:
1、 要让系统能检测到DM9000
2、 初始化DM9000,
3、 让驱动找到收发的接口,也就是中断。
DM9000网卡驱动的移植探索过程较复杂。以下是我整理的全部过程:
Linux2.6内核加入了设备平台与设备驱动的概念:platform_device 和platform_driver
说明:根据华恒的资料,DM9000占用S3C2410的片选CS1,即0X08000000。占用外部中断:EINT0。DM9000 默认I/0 基地址为300H。CMD 引脚用于设置COMMAND 模式,CMD为高时,选择数据端口。CMD为低时,选地址端口。数据端口和地址端口的地址码由下式决定:
DM9000地址端口=高位片选地址+300H
DM9000数据端口=高位片选地址+300H+4H
一:打开linux-2.6.14/ach/arm/mach-s3c2410/devs.c文件。
增加:include <linux/dm9000.h>
把DM9000的平台设备加进去。最后用EXPORT_SYMBOL(s3c_device_dm9000) 声明。被mach-smdk2410.c调用。
static struct resource s3c_dm9000_resource[] = {
[0] = {
.start = S3C2410_CS1+0x300,
.end = S3C2410_CS1+0x300+0x3,
.flags = IORESOURCE_MEM,
},
[1]={
.start = S3C2410_CS1+0x300+0x4,
.end = S3C2410_CS1+0x300+0x4+0x7c,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_EINT0,
.end = IRQ_EINT0,
.flags = IORESOURCE_IRQ,
}
};
static struct dm9000_plat_data s3c_device_dm9000_platdata = {
.flags= DM9000_PLATF_16BITONLY,
};
struct platform_device s3c_device_dm9000 = {
.name= "dm9000",
.id= -1,
.num_resources= ARRAY_SIZE(s3c_dm9000_resource),
.resource= s3c_dm9000_resource,
.dev= {
.platform_data = &s3c_device_dm9000_platdata,
}
};
EXPORT_SYMBOL(s3c_device_dm9000);
二:在devs.h 中加入以下这句声明:
extern struct platform_device s3c_device_dm9000;
三:打开arch/arm/mach-s3c2410/mach-smdk2410.c将dm9000加入到要初始化的设备链表里去,内核启动时将会检测设备并加载驱动。
static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
&s3c_device_dm9000, //add here
};
四:在驱动源代码里,加入:使能EINT0中断,设备中断类型,总线带宽和等待时间控制,BANKCON1总线控制。
所有要用到的寄存器所在的物理地址以及各位参数的意义参考S3C2410用户手册。
打开linux-2.6.14/driver/net/dm9000.c
在开头部分加入CPU中断寄存器的地址定义:
#define BWSCON (0x48000000) //总线带宽和等待时间控制寄存器
#define BANKCON1 (0x48000008) // BANKCON1总线控制
#define EXTINT0 (0x56000088) //EINT0号中断控制
#define INTMSK (0x4A000008) //中断使能控制
#define INTMOD (0x4A000004) //中断类型控制
找到dm9000_probe() 函数,
该函数在模块加载时被调用。作用是探测设备,并记录设备型号和相关信息,在
该函数中要设置相关的中断。把控制字写入相关寄存器。
在函数开始部分加入以下内容:
static void *bwscon, *bankcon1, *extint0, *intmsk, *intmod;
bwscon=ioremap_nocache(BWSCON, 4);
bankcon1=ioremap_nocache(BANKCON1, 4);
ettint0=ioremap_nocache(EXTINT0, 4);
intmsk=ioremap_nocache(INTMSK, 4);
intmod=ioremap_nocache(INTMOD, 4);
writel(readl(bwscon)|0xc0, bwscon); //设置总线带宽和等待时间控制寄存器
writel(readl(bankcon1)|0x1f7c, bankcon1); //设置片选1
writel(readl(intmsk)&0xfff7,intmsk); //使能EINT0中断
writel(readl(intmod)&0xfffffffe,intmod);//设置EINT0为IRQ,重要!
writel(readl(extint0)|0x4, extint0); //设置中断为上升缘触发
iounmap(bwscon);
iounmap(bankcon1);
iounmap(extint0);
iounmap(intmsk);
iounmap(intmod);
说明:ioremap_nocache()函数的功能是把相关寄存器的物理地址映射为虚拟地址,因为内核不能处理物理地址的。第一个参数是物理地址,第二个参数是大小。该函数返回一个虚拟地址。供内核调用处理。函数writel()将向IO写入32位的控制字。writel()函数的第一个参数是要写入的值,第二个参数是地址。
在函数ioremap_nocache()中获得的虚拟地址要被iounmap()释放。
五:设置MAC 地址:
还是在probe()函数中,
在该函数开头部分加入MAC地址数组:
unsigned char ne_eth_mac_addr[]={
0x00,0x12,0x34,0x56,0x78,0x49};
这时要把原来的设置MAC地址的两行代码注释掉:
/*for(i=0;i<6;i++)
{dev->dev_addr[i]=db->srom[i];
} */
然后在驱动函数初始化之后(在上面被注释掉的地方)设置MAC地址值加入以代码:
/*set mac address*/
for(i=0;i<6;i++)
{
ndev->dev_addr[i]=ne_eth_mac_addr[i];
}
说明:之所以把它注释掉,是因为在ROM里读出来的MAC是全零。MAC数组里可以随便设置,只要不是全0或者全1的6组数据。dev_addr[]是net_device里的成员,记录着MAC地址。
调试的过程中,可以用printk()函数跟踪调试,看是否有输出。然后确定错误的出处,驱动要打交道的是硬件,所以一定要看S3C2410 user manul,以及华恒提供的技术手册,因为整个硬件平台上的连线是华恒公司决定的。
DM9000移植过程中,关键是中断的设置,中断是否申请成功。主要是设置INTMOD寄存器的值,使申请的EINT0不会变成FIQ,我们只需要IRQ,否则驱动无法加载,中断的申请在open()函数中,如果中断设置不正确,虽然驱动可以探测出网卡的信息,但用ifconfig eth0 up的时候会出错。用户空间调用eth0 up的时候,会调用到内核空间的open()函数。
以下是加载网卡后出现的主要问题以及解决方法:
1:可以ping 通主机,但不能ping通自己。调用ifconfig 后发现只有网卡eth0
方法:启动虚拟网卡lo ,这是一个不真实存在的网卡。
ifconfig lo 127.0.0.1
也可以在文件系统的etc/init.d/rc.S启动文件中加入以下两句:
ifconfig eth0 192.168.2.222
ifconfig lo 127.0.0.1
这样系统启动后会自动启动这两块网卡。
2:网络可以ping通自己,也可以ping通主机。但不能mount主机。
方法:内核配置里要选上
File systemsà
Network file systems-à
[*]NFS file system support
[*]Provide NFSv3 client support
在BUSYBOX-1.2.0里选上
Linux System Utilitiesà
[*]mount
[*]Support mounting NFS file systems
这里建议最好使用BUSYBOX-1.2.0,多次试验发觉其它的版本的BUSYBOX使用情况都不够理想,然后把生成的_install目录下的bin sbin目录覆盖原来文件系统的两个目录。如果还是无法MOUNT宿主机,就换BUSYBOX,直到可行为止。
一点疑问:DM9000占用外部0号中断,CPU的中断号应该是0,但查看内核源代码,EINT0为16,上网查看资料,原来LINUX2.6保留了16号之前的中断,所以我们只能申请16号之后的中断源,EINT0=16。只能这样理解了,但DM9000中断接的是外部中断0,这是硬件的连接,我们不能更改的,怎么能用16号中断取代0号中断??无法理解。
05电子 陈培泽
2009.1.10