上一节 我们学习了:
网卡驱动介绍以及制作虚拟网卡驱动: http://www.cnblogs.com/lifexy/p/7763352.html
接下来本节,学习网卡芯片DM9000C,如何编写移植DM9000C网卡驱动程序。
1.首先来看DM9000C原理图
如下图所示:
( #:表示低电平有效)
- SD0~15: 16位数据线,有CMD引脚决定访问类型
- CMD: 命令线,当CMD为高,表示SD 传输的是数据,CMD为低表示传输的是地址
- INT: 中断引脚,接在2440的GPF7脚上
- IOR#: 读引脚,接在2440的nOE脚上
- IOW#: 写引脚,接在2440的nWE脚上
- CS#: 片选,放在2440的bank4的片选上面
1.1其中2440手册的bank4地址区间如下图:
bank4的区间位于: 0X20000000~0X28000000 ,当我们访问这个区间的地址,内存控制器便会使能网卡DM9000C的使能脚,所以我们的DM9000C的io基地址 =0X20000000
其中DM9000C的CMD引脚接在 bank4 的LADDR2上面
所以当访问的 io基地址=0X2000 0000 ,表示读写的地址里的内容是DM9000C的地址
访问的 io基地址=0X2000 0100 ,表示读写的地址里的内容是DM9000C的数据
1.2 DM9000C收发过程
当DM9000C收到外部的数据后,会暂存到内部地址中,然后产生一个上升沿中断,等待2440读取数据
当DM9000C将2440的数据转发出去后,也会产生一个上升沿中断给2440
如下图所示,DM9000C的中断引脚位于pin34脚
接在2440的GPF7引脚上,使用的中断为 EINT7
接下来便来修改厂家提供的DM9000C源代码
2.发现它的init_module()入口函数前有个条件编译
所以要注释掉 “#ifdef MODULE” 和 “#endif”
3.修改入口出口函数名,并修饰它们(修改函数名避免与内核的其它函数重名)
4.修改驱动的硬件相异性(设置基地址,寄存器,中断等)
4.1先来找找代码在哪里初始化DM9000C硬件的
进入dm9000c_init()
-> dmfe_probe()
其中dmfe_probe()函数如下:
struct net_device * __init dmfe_probe(void)
{
struct net_device *dev;
dev= alloc_etherdev(sizeof(struct board_info)); //分配一个net_device结构体
... ...
err = dmfe_probe1(dev); //调用dmfe_probe1()函数
... ...
err = register_netdev(dev); //向内核注册net_device结构体
... ...
}
显然dmfe_probe1()函数就是用来初始化DM9000C硬件和设置net_device结构体的成员用的
4.2 进入dmfe_probe1()函数
如下图,这个iobase 变量就是我们DM9000C的 io基地址0x20000000
iobase的作用:
如上图, 读一次DM9000C的VID低字节之前,需要先将地址赋为0x20000000,也就是将DM9000C的CMD置0,然后向0x20000000写入要读的 DM9KS_VID_L 地址值
最后再将地址+4,也就是赋为0x20000100,将CMD置1,然后读出0x20000100的值,也就是DM9000C的 VID低字节
DM9000C的读写方式都是这样的,先将CMD置0,写入DM9000C的地址,然后再将CMD置1,来读写数据
4.3所以在init函数中便重新设置iobase 变量,其中iobase是i nt型
并在exit出口函数中,添加 iounmp()
4.4 继续进入dmfe_probe1()函数,往下看
如下图所示,屏蔽红框里的代码,该代码用来核对版本,我们的DM9000C版本号不一样,所以 要屏蔽
4.5 在init函数中,修改中断名,将irq改为IRQ_EINT7
4.6 修改中断
当使用了register_netdev()注册了网卡驱动net_device后,在内核中使用ifconfig就会进入net_device->open成员函数申请中断,激活队列等
所以我们要修改open成员函数的申请中断函数,将触发中断改为 “IRQT_RISING” ,上升沿触发
5. 接下来便开始设置2440 的存储控制寄存器
设置2440的bank4的硬件位宽,时序,因为不同的硬件,涉及的数据收发都不同,
5.1设置BWSCON总线宽度控制寄存器
我们只设置 BANK4 的内容,所以只有下面3个 (BANK0的位宽由OM[1:0] 硬件设置)
设置 ST4=0 ,不使用UB/LB(UB/LB:表示高字节与低字节数据是否分开传输)
设置 WS4=0 ,其中WAIT引脚为PE4,而我们DM9000C没有引脚接入PE4,所以禁止
设置 DW4=0x01 ,我们的DM9000C的数据线为16位
5.2设置BANKCON4控制寄存器
设置这些时序之前,首先来看DM9000C芯片手册时序图和2440的时序图
参考上图,得出 BANKCON4 寄存器设置如下(HCLK=100MHZ,1个时钟等于10ns)
设置 Tacs=0, CS和CMD信号可以同时进行(CMD脚就是2440的地址引脚)
设置 Tcos=T1=0 (CS片选使能后维持时间)
设置 Tacc=T2=0 ,要>=10ns(读写信号的访问维持时间)
设置 Tcoh=T4=1 ,要>=3ns(片选结束维持时间)
设置 Tcah=T8=0 , CS和CMD信号可以同时结束(地址总线结束维持时间)
代码如下图, 在init 入口函数中设置
与硬件相关的部分已经改好了, 接下来开始编译
6.编译测试
编译之前,首先添加该驱动需要的内核头文件:
#include
#include
#include
#include
#include
编译无误后,便开始测试DM9000C驱动程序:
1) 把dm9dev9000c.c放到内核的drivers/net目录下,来 替换 原来内核的DM9000C
2) 修改 drivers/net/Makefile
把
obj-$(CONFIG_DM9000) += dm9000.o
改为 (如下图所示)
obj-$(CONFIG_DM9000) += dm9dev9000c.o
3) make uImage
如下图,说明新的驱动已编译进内核
4) 使用新内核启动
ifconfig eth0 192.168.2.107
ping 192.168.2.1
如下图,可以ping通,说明移植成功