在mini2440上移植DM9000E网卡的参考步骤如下:
一、看电路图
在mini2440开发板上移植好Linux-2.6.29.1内核和根文件系统的基础上,进行网卡DM9000E的移植,因为手里面有韦东山写的《嵌入式Linux应用开发完全手册》一书,在书中找到了DM9000网卡移植部分,对照该书与友善光盘里面的原理图,移植之前先从看原理图开始。看了DM9000E与S3C2440的电路图发现:
1、DM9000E挂接到S3C2440总线
S3C2440通过总线来访问DM9000E。mini2440访问DM9000E的物理地址的基址是BANK4,用到一条地址线ADDR2,对应DM9000E的CMD引脚,,因为DM9000E的地址信号和数据信号复用,CMD引脚决定传输的是地址信号还是数据信号,于是地址线ADDR2的引脚状态决定了DM9000E与S3C2440传输的是地址信号还是数据信号。
2、总线位宽16,用到nWAIT信号
3、DM9000E收到完整的数据包,通过中断引脚通知S3C2440来接收数据包,与S3C2440相连的中断引脚为EINT7。
二、网卡驱动程序修改
修改内核中网卡驱动程序时需要先结合所使用的内核,先查看当前内核是否支持该网卡,如果不支持需要查找支持该网卡的驱动程序进行修改。我用的是Linux-2.6.29.1内核,该内核已经对DM9000E具有很好的支持了,这在内核的Documentation/networking/dm9000.txt中有对内核中dm9000驱动程序详细地说明,其中如下部分说明Linux-2.6.29.1内核对DM9000E网卡的友好支持。
The driver supports three DM9000 variants, the DM9000E which is the first chip supported as well as the newer DM9000A and DM9000B devices. It is currently maintained and tested by Ben Dooks, who should be CC: to any patches for this driver.
一些低版本的内核(比如linux-2.6.13等)对DM9000E不支持,可以用其它内核版本的dm9000.c驱动程序添加到内核中,进行修改和配置。由于这里使用的内核已经对DM9000E网卡具有很好的支持,只需简单的配置和修改即可。
1、修改DM9000平台设备
修改/arch/arm/plat-s3c24xx/common-smdk.c文件
(1)、添加要包含的头文件
#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
#include
#endif
(2)、添加DM9000的平台设备结构
#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
/*DM9000*/
static struct resource s3c_dm9k_resource[]={
[0] = {
.start = S3C2410_CS4, //ADDR2 = 0
.end = S3C2410_CS4 + 3,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = S3C2410_CS4 + 4, //ADDR2 = 1
.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,
};
static struct platform_device s3c_device_dm9k = {
.name = "dm9000",
.id = 0,
.num_resources = ARRAY_SIZE(s3c_dm9k_resource),
.resource = s3c_dm9k_resource,
.dev = {
.platform_data = &s3c_dm9k_platdata,
}
};
#endif
(3)、将DM9000平台设备加入内核设备列表中
/* devices we initialise */
static struct platform_device __initdata *smdk_devs[] = {
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
&s3c_device_dm9k,
#endif
};
2、修改drivers/net/dm9000.c
dm9000.c中包含dm9000_probe函数,该函数完成DM9000设备的枚举,dm9000_probe函数的介绍在《嵌入式Linux应用开发完全手册》一书中详细介绍。
(1)、添加必要的头文件
#if defined(CONFIG_ARCH_S3C2410)
#include
#endif
在《嵌入式Linux应用开发完全手册》一书中上面的#include是#include ,这使得我编译通不过,被我改成#include后编译成功,这是不同版本内核文件的程序所在文件的差别造成。
(2)、在dm9000_probe中设置存储器使BANK4可用,设置默认MAC地址(也可以在根文件系统启动脚本设置),添加的代码如下:
/*
* Search DM9000 board, allocate space and register it
*/
static int __devinit
dm9000_probe(struct platform_device *pdev)
{
…
#if defined(CONFIG_ARCH_S3C2410)
unsigned int oldval_bwscon; //用来保存BWSCON寄存器的值
unsigned int oldval_bankcon4; //用来保存S3C2410_BANKCON4寄存器的值
#endif
…
#if defined (CONFIG_ARCH_S3C2410)
//设置BANK4:总线宽度为16,使能nWAIT
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;
//设置BANK4的时间参数
oldval_bankcon4 = *((volatile unsigned int *)S3C2410_BANKCON4);
*((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
#endif
…
if (!is_valid_ether_addr(ndev->dev_addr))
dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
"set using ifconfig/n", ndev->name);
#if defined(CONFIG_ARCH_S3C2410)
printk("Now use the default MAC address:08:90:90:90:90:90/n");
ndev->dev_addr[0] = 0x08;
ndev->dev_addr[1] = 0x90;
ndev->dev_addr[2] = 0x90;
ndev->dev_addr[3] = 0x90;
ndev->dev_addr[4] = 0x90;
ndev->dev_addr[5] = 0x90;
#endif
…
out:
printk("%s:not found (%d)./n",CARDNAME,ret);
#if defined(CONFIG_ARCH_S3C2410)
*((volatile unsigned int *)S3C2410_BWSCON) = oldval_bwscon;
*((volatile unsigned int *)S3C2410_BANKCON4) = oldval_bankcon4;
#endif
(3)、指定注册中断时的触发方式
dm9000_open(struct net_device *dev)
{
…
irqflags |= IRQF_SHARED;
#if defined (CONFIG_ARCH_S3C2410)
if(request_irq(dev->irq,&dm9000_interrupt,IRQF_SHARED|IRQF_TRIGGER_RISING,dev->name,dev))
#else
if(request_irq(dev->irq,&dm9000_interrupt,IRQF_SHARED,dev->name,dev))
#endif
//if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))
return -EAGAIN;
…
}
三、在内核中增加对网卡DM9000的配置
在内核目录下执行“make menuconfig”命令进行如下的配置:
Device Drivers--->
[*]Network device support--->
[*]Ethernet(10 or 100Mbit)--->
<*>DM9000 support
[*]Networking support--->
Networking options--->
<*>TCP/IP networking
<*>IP:kernel leel autoconfiguration
//增加对nfs的支持
File systems--->
[*]Networking File Systems--->
<*>NFS client support
[*]NFS client support for NFS version 3
[*]NFS client support for the NFSv3 ACL protocol extension
[*]Boot file system on NFS
[*]NFS server support
四、修改根文件系统启动脚本rcS
在根文件etc/init.d/rcS文件中添加如下:
echo "network interface"
/sbin/ifconfig lo 127.0.0.1
/sbin/ifconfig eth0 192.168.1.230 up
route add default gw 192.168.1.1
五、测试和修改
至此,将修改过的内核和根文件系统下载到mini2440开发板,启动时出现如下信息:
----------munt all----------------
network interface
dm9000 dm9000.0: WARNING: no IRQ resource flags set.
eth0: link up, 10Mbps, half-duplex, lpa 0x0021
***********************************************
****************Studying ARM*********************
Kernel version:linux-2.6.29.1
Student:Feng dong rui
Date:2009.07.15
***********************************************
Please press Enter to activate this console.
[MrFeng]#
1、测试
Please press Enter to activate this console.
[MrFeng]#ifconfig -a
eth0 Link encap:Ethernet HWaddr 10:23:45:67:89:AB
inet addr:192.168.1.230 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1506 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:101460 (99.0 KiB) TX bytes:0 (0.0 B)
Interrupt:51 Base address:0x8000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:6 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:504 (504.0 B) TX bytes:504 (504.0 B)
[MrFeng]#ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: seq="0" ttl="64" time="1".004 ms
64 bytes from 127.0.0.1: seq="1" ttl="64" time="0".518 ms
64 bytes from 127.0.0.1: seq="2" ttl="64" time="0".436 ms
^C
--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.436/0.652/1.004 ms
[MrFeng]#ping 192.168.1.103
PING 192.168.1.103 (192.168.1.103): 56 data bytes
64 bytes from 192.168.1.103: seq="0" ttl="64" time="2".098 ms
64 bytes from 192.168.1.103: seq="1" ttl="64" time="1".342 ms
64 bytes from 192.168.1.103: seq="2" ttl="64" time="0".823 ms
^C
--- 192.168.1.103 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.823/1.421/2.098 ms
//挂载网络文件系统
[MrFeng]#mount -t nfs -o nolock 192.168.1.103:/opt/nfs /mnt
[MrFeng]#ls /mnt
pic.jpg
[MrFeng]#umount /mnt
[MrFeng]#ls /mnt
[MrFeng]#
注:在挂载网络文件系统时先要在Linux系统下设置共享目录才能在从开发板挂载该目录,这里已经在虚拟机下Redhat9.0系统中的/opt下设置了共享目录nfs,虚拟机的ip为192.168.1.103,故通过mount -t nfs -o nolock 192.168.1.103:/opt/nfs /mnt命令挂载。
2、曾经出现的问题
(1)、ping不同局域网内其它主机,ping自己也有时会出现如下问题:
[ ] (s3c_irq_demux_extint4t7+0x0/0xa8) from [ ] (asm_do_IRQ+0x
44/0x5c)
r4:c03c2350
[ ] (asm_do_IRQ+0x0/0x5c) from [ ] (__irq_svc+0x24/0xa0)
Exception stack(0xc2e2bd98 to 0xc2e2bde0)
bd80: 00000000 fb000000
bda0: 00000001 00000000 c03c2a18 00000033 40000013 00000080 00000033 00000000
bdc0: c39bfc80 c2e2be10 c2e2bdbc c2e2bde0 c007320c c0072748 60000013 ffffffff
r7:00000080 r6:00000010 r5:f4000000 r4:ffffffff
[ ] (setup_irq+0x0/0x248) from [ ] (request_irq+0xb0/0xcc)
[ ] (request_irq+0x0/0xcc) from [ ] (dm9000_open+0x16c/0x23c)
[ ] (dm9000_open+0x0/0x23c) from [ ] (dev_open+0xa8/0x10c)
[ ] (dev_open+0x0/0x10c) from [ ] (dev_change_flags+0x98/0x164
)
r5:00000000 r4:c382b800
[ ] (dev_change_flags+0x0/0x164) from [ ] (devinet_ioctl+0x2f0
/0x708)
r7:bed9ba88 r6:c39fdf00 r5:00000000 r4:ffffff9d
[ ] (devinet_ioctl+0x0/0x708) from [ ] (inet_ioctl+0xc0/0xf4)
[ ] (inet_ioctl+0x0/0xf4) from [ ] (sock_ioctl+0x1e4/0x244)
[ ] (sock_ioctl+0x0/0x244) from [ ] (vfs_ioctl+0x3c/0x84)
r7:00000003 r6:00008914 r5:ffffffe7 r4:c2d1a420
[ ] (vfs_ioctl+0x0/0x84) from [ ] (do_vfs_ioctl+0x284/0x2a4)
r6:00000000 r5:bed9ba88 r4:c2d1a420
[ ] (do_vfs_ioctl+0x0/0x2a4) from [ ] (sys_ioctl+0x40/0x5c)
r7:00000036 r6:00008914 r5:fffffff7 r4:c2d1a420
[ ] (sys_ioctl+0x0/0x5c) from [ ] (ret_fast_syscall+0x0/0x2c)
r6:00000000 r5:00159dec r4:00159d5c
出现这个问题的原因是我没将中断的触发方式按照默认的,没有改成上面修改的。
(2)、挂载不了网络文件系统
可能的原因:检查内核的配置中是否选中对NFS的支持,Linux主机是否能连通局域网并设置了共享目录,硬件的链接是否良好。还有就是Linux主机的防火墙是否关闭,nfs服务是否已经开启。
六、参考资料
在学习的过程中,参考了韦东山写的《嵌入式Linux应用开发完全手册》一书,该书我觉得虽然没有把很多东西讲得很详细,嵌入式Linux的书也不可能在一本书上讲得详细,但我每想做什么就不自觉的翻阅它,对我来说非常具有参考价值。另外就是网上的一些热心网友的博客、帖子上的内容给了我很多参考,结合“百家之长”解决问题,网上的资料很多,不一一列举。