摘 要: 主要研究了基于Linux内核的网卡驱动的移植。Linux网络设备驱动程序的体系结构可以分为4层,首先分析了各层的具体功能实现,并在此基础上充分利用S3C2440开发板完成DM9000网卡驱动的移植,编译内核生成内核镜像。最后介绍了网络驱动测试的三种方法,并采用第一种方法,即使用ifconfig进行IP地址的设置,完成了测试。
关键词: Linux内核;网卡驱动;S3C2440;DM9000
0 引言
以太网(Ethernet)是一种计算机局域网组网技术。在局域网中,多个节点是共享传输介质的,这就必须由某种机制来决定某个时刻哪个设备占用传输介质来传输数据,因此,局域网的链路层要有介质访问控制的功能,即数据链路层分为逻辑链路控制LLC子层和介质访问控制MAC子层[1]。
本文主要研究基于S3C2440的DM9000网卡驱动的移植。网络对于嵌入式系统来说是必不可少的,但是S3C2440没有集成以太网接口,所以要想使S3C2440具备以太网的功能,就必须扩展网卡接口。本文选择外接DM9000,使其可以与以太网相连接,并完成DM9000网卡驱动的移植。
1 Linux网络驱动层次
Linux网络驱动可以划分为4层,即网络协议接口层、网络设备接口层、设备驱动功能层和设备物理媒介层,内核中是通过以dev_base为头指针的设备链表来管理所有的网络设备的。网络设备驱动的编写主要是网络设备net_device的初始化和数据包的收发函数[2]。
网络协议接口层最主要的功能是给上层协议提供透明的数据包发送和接收接口,当上层的API或IP需要发送数据包时,它将调用网络协议接口层的dev_queue_xmit函数发送一个内容为sk_buff的数据;当上层需要接收数据时,则是通过向netif_rx函数传递一个sk_buff数据结构的指针来完成的[3]。
网络设备接口层主要是为变化多端的网络定义了一个统一且抽象的net_device,实现了多种硬件在软件层次上的统一。网络设备驱动主要是填充net_device的成员并注册net_device来实现硬件操作函数和内核的挂接。通常情况下,网络设备驱动以中断方式接收数据,而net_device中则定义了poll_controller这种纯轮询的接口方式,以提高Linux在宽带系统上的性能。
设备驱动功能层中对于具体的设备,工程师应该实现net_device中的open、stop、tx、hard_header、get_stats、tx_timeout、interruppt等函数。
网络设备媒介层直接对应实际的硬件设备,需要定义一组读写设备内部寄存器的函数,如ior、iow[4]。
2 网络设备驱动移植
2.1 基于S3C2440的DM9000网卡驱动的移植
首先看内核DM9000代码,在/driver/net/Makefile查看:
obj-$(CONFIG_DM9000)+=dm9000.o
在/driver/net/Kconfig查看:
menuconfig NET_ETHERNET
bool "Ethernet (10 or 100Mbit)"
config DM9000
tristate "DM9000 support"
depends on ARM||BLACKFIN||MIPS
select CRC32
select MII
所以配置内核make menuconfig时,需要选中这一项。
根据开发板电路图知道,DM9000的AEN端口接到了nGCS4上,INT端口接到了IRQ_EINT7上,CMD端口接到了LADDR2上,数据线是SD0~SD15,即数据线的位数是16 bit。
根据S3C2440地址空间的分配与片选信号的定义知道,引脚nGCS4对应的空间的起始地址为0x20000000,这由系统地址线控制。同时,DM9000使用的中断号是IRQ_EINT7。另外,DM9000上的CMD信号用来控制是地址端口还是数据端口,如果CMD为0,即LADDR2为0,表示访问地址寄存器;当CMD为1,即LADDR2为1,表示访问数据寄存器[5]。
2.2 DM9000驱动的移植
在mach-S3C2440.c中添加如下代码:
#include<linux/dm9000.h>
#define MACH_S3C2440_DM9K_BASE(S3C2410_CS4+0x300)
Static struct resource S3C2440_dm9k_resource[]={
[0]={//地址端口
.start=MACH_S3C2440_DM9K_BASE,
.end=MACH_S3C2440_DM9K_BASE+3,
.flags=IORESOURCE_MEM
},
[1]={//数据端口
.start=MACH_S3C2440_DM9K_BASE+4,
.end=MACH_S3C2440_DM9K_BASE+7,
.flags=IORESOURCE_MEM
},
[2]={//中断号
.start=IRQ_EINT7,
.end=IRQ_EINT7,
.flags=IORESOURCE_IRQ|IORESOURCE_IRQ_HIGHEDGE,
//高电平触发
}
};
Static struct dm9000_plat_data S3C2440_dm9k_pdata={
//数据线的位数是16 bit,没有使用E2PROM
.flags=(DM9000_PLATF_16BITONLY|DM9000_PLATF_NO_ EEPROM),
.dev_addr={0x08,0x90,0x90,0x90,0x90,0x90},
//MAC地址
};
static struct platform_device S3C2440_device_eth={
.name="dm9000",//设备名
.id=-1,
.num_resources=ARRAY_SIZE(S3C2440_dm9k_resource),
.resource=S3C2440_dm9k_resource,//资源
.dev={
.platform_data=&S3C2440_dm9k_pdata,
//私有数据
},
};
最后在S3C2440的BSP文件mach-S3C2440.c中添加如下代码:
static struct platform_device*S3C2440_devices[]__initdata={
……
& S3C2440_device_eth,//添加
};
移植完毕后编译内核生成内核镜像。
3 网络设备驱动测试
网络设备没有字符设备里的open、close等函数,而是靠IP地址选择路由,Linux网络系统的路由选择会自动查找匹配合适的驱动,这是网络驱动与其他两种驱动的主要区别[6]。
下面给出三种测试网络驱动是否正常的方法。
(1)使用ifconfig进行IP地址的设置。
(2)为了让用户获取网络统计的数据,驱动一般有一个net_device_stats结构体,并提供get_stats函数接收它。
(3)应用程序使用标准的socket、bind、send等操作。
本文采用第一种方法进行双向ping通测试。首先在开发板终端上输入命令ifconfig eth0 10.10.150.180,设置好开发板IP地址,再将网口通过网线与PC相连,查得PC IP地址是10.10.150.174。在Windows命令行界面上输入命令ping 10.10.150.180,得到如下结果:
Ping 10.10.150.180 with 32 bytes of data:
Reply from 10.10.150.180:bytes=32 time<1ms TTL=64
Reply from 10.10.150.180:bytes=32 time<1ms TTL=64
Reply from 10.10.150.180:bytes=32 time<1ms TTL=64
接着在开发板终端上输入命令ping 10.10.150.174,得到如下结果:
Ping 10.10.150.174(10.10.150.174):56 data bytes
64 bytes from 10.10.150.174:icmp_seq=0 ttl=64 time=0.9ms
64 bytes from 10.10.150.174:icmp_seq=1 ttl=64 time=0.9ms
64 bytes from 10.10.150.174:icmp_seq=2 ttl=64 time=0.9ms
测试结果表明网络驱动正常。
4 结论
本文基于S3C2440开发板,通过外接DM9000网卡,完成网卡驱动的移植,编译内核生成内核镜像,实现网络设备驱动的匹配。最后通过ping命令测试网口是否能正常工作。本文的移植方法可为其他网络驱动移植作为参考。
参考文献
[1] 李方军,金炜东.嵌入式Linux网络驱动程序的研究与实现[J].现代电子技术,2005(16):20-30.
[2] 宋宝华.Linux设备驱动开发详解[M].北京:人民邮电出版社,2010.
[3] 贺金平.嵌入式Linux下DM9000网卡驱动的移植与实现[J].电脑知识与技术,2009,22(5):82-86.
[4] 丁忠,林畅卫.功基于Linux的网络设备驱动程序设计[J].微计算机应用,2007(9):56-77.
[5] 潘攀.Linux在嵌入式系统上的移植[J].科技信息,2010(20):45-63.
[6] 吴士力.嵌入式Linux应用开发全程解析与实战[M].北京:机械工业出版社,2010