uClinux下移植Ne2000兼容的 网卡驱动程序 |uClinux,Ne2000, 网卡驱动程序 ...
=>中国源码:全球著名开源项目大本营 作者: 前一段时间,拿着tpu一个移植好了的uClinux在S3C44B0(ARM7TDMI核的嵌入式处理器) 上的版本,把它成功的跑在了我自己的S3C44B0的板子上,这也就算是平生在uClinux下 作的第一个工作吧。接下来就是添加网卡驱动,我用的是RTL8019AS--比较常用的ISA接 口的以太网芯片。下面就从一个新手的角度来说说我的移植过程吧,其实很简单,我的 整个摸索+移植的过程也就花了2天的时间,我尽量写的详细(罗嗦?)一点,希望对像 我这样的新手入门有所帮助,错误之处在所难免,欢迎指正。 开始的时候,我也是摸不着头脑,不知道该从什么地方入手。用SoureInsight把整个 uClinux内核的源码都添加进来,熟悉一下linux的内核(其实就是在里面瞎撞,也不怎么 能看懂)。按照linux内核目录的分类,很自然的就找到Ne2000网卡的驱动就是 ./drivers/net/ne.c,和它相关的还有8390.h和8390.c。看看代码,逐渐的就明白了: 首先,在Ne.c中函数ne_probe就是网卡的检测函数,如果检测到Ne2000兼容的网卡 就return 开始写到: #if ………… #elif static if return if dev->base_addr dev->irq once++; } #endif 就明白了,可以把网卡的基地址、中断号都放到这里面定义。我也跟着照葫芦画瓢,添 加了一个: #elif static if return if dev->base_addr dev->irq once++; } 其中:ARM_NE2000_BASE和ARM_NE2000_IRQ是在配置内核的时候定义的,这个以后再说。 接下来,具体的工作就转移到了ne_probe1函数里面做。用SourceInight跟进来看(这个 软件太好用了,忍不住在这里再坐一会广告)。Ne_probe1中,一开始就是 reg0 if ret goto } 很容易理解,就是读一下网卡的基地址,对我来说也就是RTL8019的REG0,如果是0xff, 说明没有检测到网卡,返回错误。好了,在下面添加一行 printk("begin //--add 来证明我们的想法是正确的,程序如果能读取8019的REG0,就应该显示出这一行。可是 ,那个ne_probe是谁调用的呢?还是用SourceInsight去找,用jamp 太容易了,立刻就看到了,网卡的检测是从./drivers/net/Space.c的ethif_probe函数 中实现的,关键代码: if return eisa_probes在前面定义成全局: static #ifdef {de4x5_probe, #endif ………… {NULL, }; 我也照着添加了: if return 并定义: static #ifdef {ne_probe, #endif {NULL, }; 这样,编译内核启动,果然,显示出了输出结果。 继续分析修改ne.c中ne_probe1的代码(关键的东东全在这里面呢)。接下来就是 outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, regd outb_p(0xff, 读取REGD中的数据,这里,再仔细跟踪一下outb_p这个函数,在x86中,这个就是一个IO 口的输出函数,在S3C44B0是存储器和IO统一编址的(或者说不分存储器还是IO),经过 了几次宏定义以后,很快找到如下宏代码: (*(volatile 和我想的一样,就是靠这个访问外部总线的。我的8019在S3C44B0的Bank 线模式,算了一下,起始基地址就是0x0a000600。 这里,需要说明一下我的硬件配置和连接,8019工作在16位模式下,S3C44B0的Bank5配 置成16位模式,数据线一对一的连接,地址线错开一位--8019的A0连接S3C44B0的A1…… 这样,8019的基地址(Reg0的地址)是0x0a000600,Reg1的地址就是0x0a000602……地 址不是连续增加的,所以,对应的驱动程序要做相应的修改。查找E8390_CMD的定义,发 现,在8390.h中有: #define */ /* #define RD #define …… 而EI_SHIFT根据不同的配置有两种定义,如下: #if defined(CONFIG_ARIADNE2) defined(CONFIG_HYDRA) defined(CONFIG_ARM_ETHERH) #define #else #define #endif 看来,在8390的驱动中已经考虑到了不连续增长的地址的问题了,继续跟踪查看ei_loca l->regoffset[x]的定义就比较麻烦了。干脆,我用一个笨方法,直接添加: #elif threewater #define 对应的,在ne.c也有类似的定义问题: #define #define #define #define 添加成: #ifdef #define #define #define |