网卡DM9000的驱动移植

时间:2021-02-17 17:12:54

    废话不说,直奔主题吧。

要想成功移植DM9000的驱动,首先应该了解Linux内核中platform驱动模型架构和网卡DM9000与cpu的硬件连接,

一、硬件链接情况

    DM9000在电路板上的连接中与编程相关的如下:
1)EECS拉高:16bit模式;
2)INT连接到2440 EINT18:INT脚为低时为有效中断信号,中断线为EINT18
3)cs连接到2440的nGCS4,CMD连接2440地址总线ADDR[2]:知道上面这些信息已经足够移植驱动了。

二、platform驱动模型

      从Linux 2.6起引入了一套新的驱动管理和注册机制:Platform_devicePlatform_driverLinux中大部分的设备驱动,都可以使用这套机制, 设备用Platform_device表示,驱动用Platform_driver进行注册。

    Linux platform driver机制和传统的device driver 机制(通过driver_register函数进行注册)相比,一个十分明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性(这些标准接口是安全的)

    Platform机制的本身使用并不复杂,由两部分组成:platform_deviceplatfrom_driver通过Platform机制开发发底层驱动的大致流程为:  定义 platform_device à 注册 platform_device à 定义 platform_driver à注册 platform_driver

    首先要确认的就是设备的资源信息,例如设备的地址,中断号等。

2.6内核中platform设备用结构体platform_device来描述,该结构体定义在kernel/include/linux/platform_device.h中,

struct platform_device {

 const char * name;

 u32  id;

 struct device dev;

 u32  num_resources;

 struct resource * resource;

};

 

该结构一个重要的元素是resource,该元素存入了最为重要的设备资源信息,定义在kernel/include/linux/ioport.h中,

struct resource {

 const char *name;

 unsigned long start, end;

 unsigned long flags;

 struct resource *parent, *sibling, *child;

};

 

一个独立的挂接在cpu总线上的设备单元,一般都需要一段线性的地址空间来描述设备自身,linux是怎么管理所有的这些外部"物理地址范围段",进而给用户和linux自身一个比较好的观察4G总线上挂接的一个个设备实体的简洁、统一级联视图的呢?
    linux
采用struct resource结构体来描述一个挂接在cpu总线上的设备实体(32cpu的总线地址范围是
0~4G):
resource->start
描述设备实体在cpu总线上的线性起始物理地址
;
resource->end
-描述设备实体在cpu总线上的线性结尾物理地址
;
resource->name
描述这个设备实体的名称,这个名字开发人员可以随意起,但最好贴切
;
resource->flag
描述这个设备实体的一些共性和特性的标志位;

 

问题:我怎样知道设备实体在cpu总线上的线性起始物理地址跟线性结尾物理地址?

通过查看原理图吗??如果是,那具体应该怎样分析呢?

三、现在分析dm9000在Linux内核中的结构。

    static struct platform_device与static struct platform_resources结构体在arch/arm/plat-s3c24xx/devs.c中定义,在arch/arm/plat-s3c/include/plat/devs.h中声明,在arch/arm/mach-s3c2440/mach-smdk2440.c中使用(通过函数:platform_add_devices()注册进内核)。

至于platform_driver的实现就是在dm900.c中实现了。

四、移植

网卡DM9000的驱动移植

 

从上图可以看出

a. dm9000的访问地址为BANK4的基址(也许是通过上面的nGCS4看出来的)。(这个我是不明白的)
b. 只有一根地址线ADDR2。
c. 总线位宽为16位,有nWAIT信号。
d. 使用中断引脚为EINT18(使用LAN_INT实现的)。

一 增加DM9000平台设备
增加平台设备前首先要先定义该平台设备,这主要修改arch/arm/plat-s3c24xx/devs.c文件。
1.添加头文件 ,在devs.c文件的头文件引入处添加如下代码:

#include <linux/dm9000.h>

2.定义dm9000平台资源 ,在devs.c文件的合适处添加如下代码(其实看一下源文件就知道合适的意思):

 

 

 

   

 

NOTE:
a.s3c_dm9k_resource数组定义了3个资源:两个内存空间和一个中断号。数组项0、1定义了访问dm9000时使用的地址。在dm9000的芯片手册上有如下的介绍:

    CMD Command Type
         When high, the access of this command cycle is DATA port
         When low, the access of this command cycle is ADDRESS port

所以数组项0、1的.start域就容易理解了,S3C2410_CS4中addr2为0,表示传输地址;S3C2410_CS4 + 4中addr2为1,表示传输数据。数组项[2]定义的中断号就较容易理解。
b.结构s3c_dm9k_platdata中指定了数据总线宽度为16。
c.结构s3c_device_dm9k就是dm9000的平台设备,其中.resource和.dev项分别指向前面定义的s3c_dm9k_resource和s3c_dm9k_platdata。

3.把定义的平台设备加入到内核设备列表中 ,在common-smdk.c文件的smdk_devs数组中添加一下代码:(我的为mach-mini2440.c文件mini2440_devices数组)

&s3c_device_dm9k,

这样,系统启动时就会把这个数组中的设备注册到内核中。

二 修改dm9000.c文件
对dm9000的枚举最终由dm9000_probe函数来实现。
1.添加头文件 ,在dm9000.c的头文件引入处增加以下代码,定义了一些寄存器的宏定义:

view plain copy to clipboard print ?
#if defined(CONFIG_ARCH_S3C2410)   
#include <mach/regs-mem.h>   
#endif   

view plaincopy to clipboardprint?
#if defined(CONFIG_ARCH_S3C2410)  
#include <mach/regs-mem.h>  
#endif 
#if defined(CONFIG_ARCH_S3C2410)
#include <mach/regs-mem.h>
#endif
 

2.修改probe函数 ,通过设置存储控制器使BANK4可用,修改后的dm9000_probe函数如下,其中修改的地方都由CONFIG_ARCH_S3C2410包括:

 

 

a.第24-27行定义了两个变量,用来保存BWSCON和BANKCON4的值,下面将会用到。

b.第32-39对BANK4进行了设置。首先设置BWSCON,

9对BANK4进行了设置。首先设置BWSCON,


view plain copy to clipboard print ?

 

主要是设置了总线宽度16,nWAIT,ST。(具体的可以参考s3c2440数据手册的BUS WIDTH & WAIT CONTROL REGISTER (BWSCON))。然后设置BANKCON4的时间参数,值为0×1f7c(pmc:normal Tacp:6clk Tcah:4clk Tcoh:1clk Tacc:14clk Tcos:4clk 具体可以参考s3c2440数据手册的BANK CONTROL REGISTER)

c.第209-216的代码是我自己给注释的,据其意思,上面首先给MAC赋值,然后检测合法性,但经实践,判断语句总成立,所以在linux启动注册dm9000时总输出Invalid ethernet MAC address.反正后面也会再次给MAC地址赋值,所以干脆把这几行代码注释掉。

d.第218-227行就是给MAC地址赋值的,听说赋什么值都可以,有这么神奇吗?

e.第266-269行恢复寄存器原来的值。

f.以上的步骤和代码都是参考书上的,但可惜的是,按照上面步骤去修改,系统能成功加载dm9000驱动,但无法ping通,这个事确实让我很苦恼,上网找了很多资料,最后发现大多数都需要调用writel来设置BWSCON、GPFCON和中断等。所以无计之下参考了mini2440中的一段代码,出自附送光盘的无操作系统代码测试的dm9000部分。

到此 ,代码的移植到此为止,然后是配置内核,以使用dm9000。在

-> Device Drivers                                                   
        --> Network device support                                       
           --> Network device support (NETDEVICES [=y])                      
             --> Ethernet (10 or 100Mbit) 处将DM9000网卡选为编译进内核。
然后在/etc/init.d/rcS文件的开始处加入

ifconfig
 eth0 192.168.1.22<
pre>
当然,ip地址是因人而定的,尽量设为和PC在同一个网段。重新将内核下载到开发板后启动