欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

S3C2440 DM9000C网卡移植(二十六)

程序员文章站 2022-07-14 10:17:06
...

https://www.cnblogs.com/lifexy/p/7777961.html

上一节 我们学习了:

网卡驱动介绍以及制作虚拟网卡驱动:https://blog.csdn.net/xiaodingqq/article/details/81501393

接下来本节,学习网卡芯片DM9000C,如何编写移植DM9000C网卡驱动程序。


1、首先来看看DM9000C原理图

如下图所示:

S3C2440 DM9000C网卡移植(二十六)

(#表示低电平有效)

  • SD0~15:16位数据线,有CMD引脚决定访问类型
  • CMD:命令线,当CMD为高电平,表示SD传输的是数据,当CMD为低电平,表示SD传输的是地址
  • INT:中断引脚,接在2440的GPF7引脚上
  • IOR#:读引脚,接在2440的nOE上
  • IOW#:写引脚,接在2440的nWE上
  • CS#:片选引脚,放在2440的bank4的片选上面

1.1 其中2440手册的bank4地址区间如下图:

S3C2440 DM9000C网卡移植(二十六)

bank4的区间位于:0x2000 0000~0x2800 0000,当我们访问这个区间的地址,内存控制器便会使能网卡DM9000C的使能引脚(被选中了),所以我们的DM9000C的io基地址=0x2000 0000

其中DM9000C的CMD引脚接在bank4的LADDR2上面

比如当在地址0x2000 0000上读写数据时,表示读写的数据是DM9000C的地址

访问的地址0x2000 0004上读写数据时,表示读写的数据是DM9000C的数据

 

1.2 DM9000C收发过程

当DM9000C收到外部数据后,会暂存到内部地址中,然后产生一个上升沿中断,等待2440读取数据

当DM9000C将2440的数据转发出去后,也会产生一个上升沿中断给2440

如下图所示,DM9000C的中断引脚位于PIN34脚

S3C2440 DM9000C网卡移植(二十六)

S3C2440 DM9000C网卡移植(二十六)

接在2440的GPF7引脚上,使用的中断为EINT7

 

接下来便来修改厂家提供的DM9000C源代码 dm9dev9000c.c

2、发现它的init_module()入口函数前有个条件编译

S3C2440 DM9000C网卡移植(二十六)

所以要注释掉“#ifdef MODULE”和“#endif

 

3、修改入口出口函数名,并修饰它们(修改函数名免与内核的其他函数重名)

S3C2440 DM9000C网卡移植(二十六)

S3C2440 DM9000C网卡移植(二十六)S3C2440 DM9000C网卡移植(二十六)

 

4、修改驱动的硬件相异性(设置基地址,寄存器,中断等)

4.1 先来找找代码在哪里初始化DM9000C硬件的

进入dm9000c_init()

-》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);//设置
	... ...
	err = register_netdev(dev);//向内核注册net_device结构体
	... ...
}

虽然dmfe_probe1()函数是用来初始化DM9000C硬件和设置net_device结构体的成员用的

 

4.2 进入dmfe_probe1()函数

如下图,这个iobase变量就是我们DM9000C的io基地址0x2000 0000

S3C2440 DM9000C网卡移植(二十六)

iobase的作用:

如上图,读一次DM9000C的VID低字节之前,需要先将地址赋为0x2000 0000,也就是将DM9000C的CMD置0,然后向0x2000 0000写入要读的DM9KS_VID_L地址值

最后再将地址+4,也就是赋为0x2000 0100,将CMD置1,然后读出0x2000 0100的值,也就是DM9000C的VID低字节

DM9000C的读写方式都是这样,先将CMD置0,写入DM9000C的地址,然后再将CMD置1来读写数据

 

4.3 所以在init函数中便重新设置iobase变量,其中iobase是init类型

S3C2440 DM9000C网卡移植(二十六)

并在exit出口函数中,添加iounmap()

S3C2440 DM9000C网卡移植(二十六)

4.4 继续进入dmfe_probe1()函数,往下看

如下图所示,屏蔽红色下划线的代码,该代码用来核对版本,我们的DM9000C版本号不一样,所以要屏蔽

S3C2440 DM9000C网卡移植(二十六)

4.5 在init函数中,修改中断名,将irq修改为IRQ_EINIT7

S3C2440 DM9000C网卡移植(二十六)

4.6 修改中断

当使用了register_netdev()注册了网卡驱动net_device后,在内核中使用ifconfig就会进入net_device->open成员函数申请中断,**队列等

所以我们要修改open成员函数的申请中断,将触发中断改为“IRQT_RISING”,上升沿触发

S3C2440 DM9000C网卡移植(二十六)

 

5、接下来便开始设置2440的存储控制寄存器(Memory Contrller)

设置2440的bank4的硬件位宽,时序,因为不同的硬件,涉及的数据收发都不同

5.1 设置BWSCON,总线宽度控制寄存器

我们只需要设备BANK4的内容,所以只有下面3个(BANK0的位宽由OM[1:0]硬件设置)

S3C2440 DM9000C网卡移植(二十六)

设置ST4=0,不使用UB/LB(UB/LB:表示高字节与低字节是否分开传输)

设置WS4=0,其中WAIT引脚为PE4,而我们DM9000C没有引脚接入PE4,所以禁止

设置DW4=0x01,从原理图,我们可知DM9000C的数据线为16位(SD0~SD15)

5.2 设置BANKCON4控制寄存器

S3C2440 DM9000C网卡移植(二十六)

设置这些时序之前,首先来看DM9000C芯片手册的时序图和2440的时序图

S3C2440 DM9000C网卡移植(二十六)

参考上图,得出BANKCON4寄存器设置如下(HCLK=100MHZ,1个时钟等于10ns)

  • 设置Tacs=0,表示发出片选信号之前,多长时间内要发现地址信号,CS和CMD可以同时结束(bank4地址(也就是CMD)稳定多久后,CS片选才启动)
  • 设置Tcos=T1=0(发出CS片选信号后,多久才能发出读信号nOE)
  • 设置Tacc=T2>=10ns=1,表示读写信号的脉冲长度,2个时钟(access cycle,读写使能后,多久才能访问数据)
  • 设置Tcoh=T4>=3ns=1,表示当读信号nOE变为高电平后,片选信号还要维持多长时间,1个时钟,因为当DM9000C的写信号取消后,数据线上的数据还需要至少3ns才消失;当DM9000C的读信号取消后,数据线上的数据在6ns之内会笑死,取一个宽松值,维持10ns,所以设为01(nOE读写取消后,片选需要维持多长时间)
  • 设置Tcah=0,因为CS和CMD可以同时结束(CS片选变为高电平后,地址(也就是CMD)需要维持多长时间)

 

代码如下图,在init入口函数中设置

S3C2440 DM9000C网卡移植(二十六)

(PS:若DM9000C无法驱动,可能是Tacc时间太短,导致读取不到数据,可以将Tacc设大一点)

与硬件相关的部分已经改好了,接下来开始编译

 

6、编译测试

编译之前,首先添加该驱动需要的内核头文件:

#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch-s3c2410/regs-mem.h>

编译无误后,便开始测试DM9000C驱动程序:

1)把已经修改好的驱动程序dm9dev9000c.c放到内核的drivers/net目录下,来替换原来内核的DM9000C

2)修改drivers/net/Makefile

obj-$(CONFIG_DM9000) += dm9000.o
改为(如下图所示)
obj-$(CONFIG_DM9000) += dm9dev9000c.o

S3C2440 DM9000C网卡移植(二十六)

 

3)make uImage

如下图,说明新的驱动已编译进内核

S3C2440 DM9000C网卡移植(二十六)

 

4)使用新内核启动

ifconfig eth0 192.168.1.17

ping 192.168.1.3

如下图,可以ping通,说明移植成功

S3C2440 DM9000C网卡移植(二十六)