这里重要的是物理层PHY receiver,MAC(media access control)层,这里与软件中的协议栈不同,在硬件上MAC是PHY的下一层。DM9000A将MAC和PHY做到一起,也可以像IIS设备那样,SOC内有IIS的控制器,而声卡UDA1341放在片外。网卡当然也有这种设计,它是把PHY的下层MAC放入SOC内,片外的是PHY,当然我暂时还没见过这种的。DM9000A的输入是并行的总线,可以和CPU直接IO。而IIS那种需要通过:CPU CORE BUS->I2S控制器->外设。通过对比,应该了解DM9000A怎样进行IO了吧。其中PHY receiver中的AUTO-MDIX控制网卡的自适应,也就是说它能自动检测连接的是什么速度的网络,切换100,10。如果双方都是自适应的,那就依据误码率来选择。图中的EEPROM当然存放的是MAC的地址,那么驱动从哪里得到MAC地址的?1)你手工设置的,然后他给你写入到EEPROM里2)要么就是EEPROM里面应该好了。图中的MII是一种称为媒体独立接口的东西,是为了和PHY连接而设计的。

再来看一下上边这个DM9000A的原理图,它的CMD引脚接在CPU的ADDR2上。这里的地址线和数据线是进行复用的。当CMD为0时,SD0~SD15传的是地址,当CMD为1时,SD0~SD15传的是数据。

DM9000A的驱动作为platform_driver注册到内核中,根据Linux设备驱动模型,还应该有一个platform_device,但是源码里没有这个,这就需要我们自己来添加了,在arch/arm/plat-s3c24xx/devs.c中,添加:

#include <linux/dm9000.h>   

/* DM9000 Net Card */
static struct resource s3c_dm9000_resource[] = {
[] = {
.start = S3C24XX_PA_DM9000,
.end = S3C24XX_PA_DM9000+ 0x3,
.flags = IORESOURCE_MEM
},
[]={
.start = S3C24XX_PA_DM9000 + 0x4, //CMD pin is A2
.end = S3C24XX_PA_DM9000 + 0x4 + 0x3,
.flags = IORESOURCE_MEM
},
[] = {
.start = IRQ_EINT7,
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ
},
}; static struct dm9000_plat_data s3c_device_dm9000_platdata = {
.flags= DM9000_PLATF_16BITONLY,
}; struct platform_device s3c_device_dm9000 = {
.name= "dm9000",
.id= ,
.num_resources= ARRAY_SIZE(s3c_dm9000_resource),
.resource= s3c_dm9000_resource,
.dev= {
.platform_data = &s3c_device_dm9000_platdata,
}
};
EXPORT_SYMBOL(s3c_device_dm9000);

注意这里第一个IO内存资源的范围是从S3C24XX_PA_DM9000~ S3C24XX_PA_DM9000+ 0x3,第二个IO内存资源的范围是从S3C24XX_PA_DM9000 + 0x4~ S3C24XX_PA_DM9000 + 0x4 + 0x3。这相当于两个32位的寄存器。一个是地址寄存器,一个是数据寄存器。向地址寄存器中写入0x1相当于选中了offset为1的NCR。向数据寄存器中写入数据他会自动写入TX RAM中。什么是TX RAM在DM9000A的驱动框架源码分析文档中已经解释了,这里就不再赘述。在这个文件中添加了平台设备的资源和平台设备。那么这个平台设备又是什么时候注册进内核的呢?我们继续往下看。在设备列表添加对DM9000A设备的支持,在arch/arm/mach-s3c2440/mach-smdk2440.c文件中,添加红色这一行:

static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_rtc,
&s3c_device_dm9000,
};

那么这些platform_device是什么时候注册的呢,看这个文件下边的代码,很明了了,在系统初始化的时候会注册这个设备列表中的每一个设备。

static void __init smdk2440_machine_init(void)
{
s3c24xx_fb_set_platdata(&smdk2440_fb_info);
s3c_i2c0_set_platdata(NULL);
platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
smdk_machine_init();
}
MACHINE_START(S3C2440, "SMDK2440")
/* Maintainer: Ben Dooks <ben@fluff.org> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> ) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END

然后修改arch/arm/plat-s3c24xx/include/mach/devs.h,添加:

extern struct platform_device s3c_device_dm9000;

修改arch/arm/mach-s3c2410/include/mach/map.h 文件

  • /* DM9000 */
  • #define   S3C24XX_PA_DM9000 0x20000000
  • #define   S3C24XX_VA_DM9000 0xE0000000

这里设定了网卡的物理地址和虚拟地址,在arch/arm/mach-s3c2410/mach-smdk2410.c中进行静态映射,在static
struct platform_device *smdk2410_devices[] __initdata中添加

  1. static struct map_desc smdk2410_iodesc[] __initdata = {
  2. [0] = {
  3. .virtual   = (unsigned long)S3C24XX_VA_DM9000,
  4. .pfn       = __phys_to_pfn(S3C24XX_PA_DM9000),
  5. .length     = SZ_1M,
  6. .type     = MT_DEVICE,
  7. },
  8. };

这样在程序中访问S3C24XX_PA_DM9000,S3C24XX_PA_DM9000
+ 0x4对应的物理地址,就直接转换到相应的虚拟地址了。至此DM9000A平台设备的添加和IO地址的静态映射完成。然后就是修改DM9000A中的MAC地址等了。

修改drivers/net/dm9000.c 文件,增加3行:

  1. #include <mach/regs-gpio.h>
  2. #include <mach/irqs.h>
  3. #include <mach/hardware.h>

修改dm9000_probe函数,添加:

unsigned char mac_addr[]={0x00,0x11,0x22,0x33,0x44,0x55};
static void *bwscon;
static void *gpfcon;
static void *extint0;
static void *intmsk;
#define BWSCON (0x48000000)
#define GPFCON (0x56000050)
#define EXTINT0 (0x56000088)
#define INTMSK (0x4A000008) bwscon=ioremap_nocache(BWSCON,0x0000004);
gpfcon=ioremap_nocache(GPFCON,0x0000004);
extint0=ioremap_nocache(EXTINT0,0x0000004);
intmsk=ioremap_nocache(INTMSK,0x0000004); writel(readl(bwscon)|0xc0000,bwscon);
writel( (readl(gpfcon) & ~(0x3 << )) | (0x2 << ), gpfcon);
writel( readl(gpfcon) | (0x1 << ), gpfcon); // Disable pull-up
writel( (readl(extint0) & ~(0xf << )) | (0x4 << ), extint0); //rising edge
writel( (readl(intmsk)) & ~0x80, intmsk);

这里主要设置了总线宽度&等待寄存器,设置相应的GPIO引脚为EXINT7,中断为上升沿触发。

在这个函数的最后需要修改:

  1. if (!is_valid_ether_addr(ndev->dev_addr)) {
  2. /* try reading from mac */
  3. mac_src = "chip";
  4. for (i = 0; i < 6; i++)
  5. //ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
  6. ndev->dev_addr[i] = mac_addr[i];
  7. }

在文件系统中添加网络配置文件,使系统在开机过程中自动完成对网卡的配置

1)在文件系统/etc/net.conf文件中添加内容

  1. IPADDR=192.168.0.105
  2. NETMASK=255.255.255.0
  3. GATEWAY=192.168.0.1
  4. MAC=00:11:22:33:44:55

2)在文件系统/sbin/目录下新建一个可执行的脚本文件net_config,注意文件的权限(可执行)

  1. #!/bin/sh
  2. echo Try to bring eth0 interface up ...>/dev/s3c2410_serial0
  3. if [ -f /etc/net.conf ] ; then
  4. source /etc/net.conf
  5. ifconfig eth0 down
  6. ifconfig eth0 hw ether $MAC
  7. echo ifconfig eth0 hw ether $MAC >/dev/s3c2410_serial0
  8. ifconfig eth0 $IPADDR netmask $NETMASK up
  9. echo ifconfig eth0 $IPADDR netmask $NETMASK up >/dev/s3c2410_serial0
  10. route add default gw $GATEWAY
  11. echo add default gw $GATEWAY >/dev/s3c2410_serial0
  12. else
  13. ifconfig eth0 hw ether 00:11:22:33:44:55
  14. ifconfig eth0 192.168.1.105 netmask 255.255.255.0 up
  15. route add default gw 192.168.0.1
  16. echo ifconfig eth0 hw ether 00:11:22:33:44:55 >/dev/s3c2410_serial0
  17. echo ifconfig eth0 192.168.0.105 netmask 255.255.255.0 up >/dev/s3c2410_serial0
  18. echo route add default gw 192.168.0.1 >/dev/s3c2410_serial0
  19. fi
  20. echo Done > /dev/s3c2410_serial0

3)在文件系统/etc/init.d/rcS文件中添加网络配置语句

  1. /sbin/ifconfig lo 127.0.0.1     #设置本地回环设备的IP地址
  2. net_config&                #执行上面的net_config文件对网卡进行设置

在文件系统中添加完上述网卡配置信息后重新编译文件系统下载到开发板,系统上电启动后就会对网卡自动配置,并执行#ifconfig命令可以看到网卡的配置信息

测试与主机的通信,开发板的IP地址可以在/etc/net.conf中修改

s5pv210网卡驱动移植:http://www.openedv.com/thread-46879-1-1.html

实际上给内核移植DM9000驱动时,修改的代码不超过到5行,但是为什么这样改,一定要弄明白。 首先看改的代码: 因为板子上DM9000接在BANK1位置,所以在Map.h (arch\arm\mach-s5pv210\include\mach) 中添加S5PV210_PA_SROM_BANK1的地址定义

......

#define S5PV210_PA_SROM_BANK5 0xA8000000 #define S5PV210_PA_SROM_BANK1 0x88000000 ...... 因为u-boot中已经对DM9000已经初始化了,所以要屏蔽掉Mach-smdkv210.c (arch\arm\mach-s5pv210) 中的初始化代码:

[C] 纯文本查看 复制代码
1
2
3
4
5
static void __init smdkv210_machine_init(void)
{
    s3c_pm_init();
 
    /*smdkv210_dm9000_init();*/

修改platform-device中dm9000的配置,Mach-smdkv210.c (arch\arm\mach-s5pv210)

[C] 纯文本查看 复制代码
1
2
3
4
5
6
static struct resource smdkv210_dm9000_resources[] = {
    [0] = DEFINE_RES_MEM(S5PV210_PA_SROM_BANK1, 4),
    [1] = DEFINE_RES_MEM(S5PV210_PA_SROM_BANK1 + 4, 4),
    [2] = DEFINE_RES_NAMED(IRQ_EINT(10), 1, NULL, IORESOURCE_IRQ \
                | IORESOURCE_IRQ_HIGHLEVEL),
};
旧的代码为:
[C] 纯文本查看 复制代码
1
2
3
4
5
6
static struct resource smdkv210_dm9000_resources[] = {
    [0] = DEFINE_RES_MEM(S5PV210_PA_SROM_BANK5, 1),
    [1] = DEFINE_RES_MEM(S5PV210_PA_SROM_BANK5 + 2, 1),
    [2] = DEFINE_RES_NAMED(IRQ_EINT(9), 1, NULL, IORESOURCE_IRQ \
                | IORESOURCE_IRQ_HIGHLEVEL),
};

这里DEFINE_RES_MEM是一个宏

[C] 纯文本查看 复制代码
1
2
#define DEFINE_RES_MEM(_start, _size)                   \
    DEFINE_RES_MEM_NAMED((_start), (_size), NULL)

,DEFINE_RES_MEM(S5PV210_PA_SROM_BANK1, 4)展开后为:

[C] 纯文本查看 复制代码
1
2
3
4
5
6
{                               \
    .start = (S5PV210_PA_SROM_BANK1),                   \
    .end = (S5PV210_PA_SROM_BANK1) + (4) - 1,               \
    .name = (NULL),                 \
    .flags = (IORESOURCE_MEM),                  \
}

首先了解一下linux的platform-deivce驱动,linux 2.6之后的内核用platform_device结构体来描述设备资源,有了platform_device,就可以用platform_add_devices添加设备了,smdkv210_machine_init会调用platform_add_devices来添加所有设备。smdkv210所有的设备用smdkv210_devices数组来表示:

[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static struct platform_device *smdkv210_devices[] __initdata = {
    &s3c_device_adc,
    &s3c_device_cfcon,
    &s3c_device_fb,
    &s3c_device_hsmmc0,
    &s3c_device_hsmmc1,
    &s3c_device_hsmmc2,
    &s3c_device_hsmmc3,
    &s3c_device_i2c0,
    &s3c_device_i2c1,
    &s3c_device_i2c2,
    &s3c_device_rtc,
    &s3c_device_ts,
    &s3c_device_usb_hsotg,
    &s3c_device_wdt,
    &s5p_device_fimc0,
    &s5p_device_fimc1,
    &s5p_device_fimc2,
    &s5p_device_fimc_md,
    &s5p_device_jpeg,
    &s5p_device_mfc,
    &s5p_device_mfc_l,
    &s5p_device_mfc_r,
    &s5pv210_device_ac97,
    &s5pv210_device_iis0,
    &s5pv210_device_spdif,
    &samsung_asoc_idma,
    &samsung_device_keypad,
    &smdkv210_dm9000,
    &smdkv210_lcd_lte480wv,
};

可见,其中包含了smdkv210_dm9000,该结构体定义如下:

[C] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
9
static struct platform_device smdkv210_dm9000 = {
    .name       = \"dm9000\",
    .id     = -1,
    .num_resources  = ARRAY_SIZE(smdkv210_dm9000_resources),
    .resource   = smdkv210_dm9000_resources,
    .dev        = {
        .platform_data  = &smdkv210_dm9000_platdata,
    },
};

看到smdkv210_dm9000_resources了吧,所以platform-device使用resource的配置信息来配置设备资源。 回过头来继续分析smdkv210_dm9000_resources,这是个resource类型的数组,resource包含start,end,name,flag 4个成员。 因为DM9000是作为SROM(一个外部存储器)使用的,有2个端口DATA和INDEX,INDEX用来指定地址,DATA用来收发数据。 smdkv210_dm9000_resources的第一组元素就用来定义INDEX端口地址,第二组元素用来定义DATA端口地址,第三组元素用来定义中断号及中断类型。明白了这些数据的作用,就可以按照之前移植U-boot网卡驱动的方法修改这些代码了,即: INDEX端口的start为S5PV210_PA_SROM_BANK1  ,end为S5PV210_PA_SROM_BANK1  + 4,故size为4; DATA的端口start为S5PV210_PA_SROM_BANK1  + 4,SIZE为4。 中断号为10(根据原理图)。 在移植NFS根文件系统后,启动会出现dm9000 dm9000: read wrong id 0x01010101 的错误,这是一个小bug,在DM9000.c中读取ID的函数之前加上延时udelay(150)即可。 udelay(150)添加位置位于 iow(db, DM9000_NCR, NCR_MAC_LBK | NCR_RST); 之后即可,这是因为复位后要延时一小段时间才能正常读ID。

linux网卡驱动移植的更多相关文章

  1. Linux网卡驱动移植--Dm9000网卡驱动分析

    1. Linux网络体系结构由以下5部分组成 ① 系统调用接口: 位于Linux网络子系统的顶部,为应用程序提供访问内核网络子系统的方法,主要指socket系统调用. ② 协议无关接口: 实现一组基于 ...

  2. 【Linux驱动】TQ2440 DM9000E网卡驱动移植(Linux-2.6.30.4)

    花了一天的时间研究了一下Linux-2.6.30.4版本号内核下关于TQ2440 DM9000E的网卡驱动移植.总结一下自己的收获. 事实上.在Linux-2.6.30.4版本号内核下有关于网卡驱动, ...

  3. AM335x(TQ335x)学习笔记——Nand&&网卡驱动移植

    移植完成声卡驱动之后本想再接再励,移植网卡驱动,但没想到的是TI维护的内核太健壮,移植网卡驱动跟之前移植按键驱动一样简单,Nand驱动也是如此,于是,本人将Nand和网卡放在同一篇文章中介绍.介绍之前 ...

  4. AM335x(TQ335x)学习笔记——Nand&amp;&amp;网卡驱动移植

    移植完毕声卡驱动之后本想再接再励,移植网卡驱动,但没想到的是TI维护的内核太健壮,移植网卡驱动跟之前移植按键驱动一样简单,Nand驱动也是如此,于是,本人将Nand和网卡放在同一篇文章中介绍.介绍之前 ...

  5. linux4.1内核配置以及编译及千兆网卡dp83867网卡驱动移植

    一  内核配置编译 1首先解压内核 tar jxvf linux-at91-4.1.tar.bz2: 2下载编译链 在ubuntu命令行中输入sudo apt-get install gcc-arm- ...

  6. linux enc28j60网卡驱动移植(硬件spi和模拟spi)

    本来想移植DM9000网卡的驱动,无奈硬件出了点问题,通过杜邦线链接开发板和DM9000网卡模块,系统上电,还没加载网卡驱动就直接崩溃了,找不到原因...刚好手上有一个enc28j60的网卡模块,于是 ...

  7. mini2440移植uboot-2008.10 (二) DM9000网卡驱动移植

    还是利用 mini2440移植uboot-2008.10 (一)  修改好的代码 通过观察可以发现,mini2400使用的网卡芯片是DM9000,在uboot-2008.10源码中已经支持该芯片的驱动 ...

  8. u-boot 移植 --->5、友善之臂Tiny210底板王网卡驱动移植

    网卡芯片的工作原理 DM9000AE具有以下主要性能: ①48管脚的LQFP封装,管脚少体积小: ②支持8/16位数据总线: ③适用于10Base-T和100Base-T,10/100M自适应,适应不 ...

  9. Linux网卡驱动安装、防火墙原理

    安装网卡驱动程序: 需要检查是否安装kernel依赖包: rpm –q kernel-devel #检查kernel依赖包是否安装 yum –y install kernel-devel 检查gcc和 ...

随机推荐

  1. Chrom 浏览器一些命令

    https://webkit.org/build-tools/  开发环境搭建 开源:http://www.17ky.net/kyxm/4_0_3_2_0_0/ http://www.chromium ...

  2. Java程序员开发参考资源

    构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...

  3. 解决安装完centos6.6之后/etc/sysconfig/目录下没有iptables 的问题

    我在安装完成centos6.6之后对防火墙进行配置,但是发现在/etc/sysconfig目录下没有iptables,心里犯嘀咕,随后就写了一条命令,保存下试试,谁知道成功了! 如图 没有发现ipta ...

  4. Java类实例化时候的加载顺序

    面试试题中经常考到此问题,现在做进一步的总结: public class Student { public Student(String name){ System.out.println(name) ...

  5. opengl视图变换 投影变换推导

    视图变换在opengl中,视图变换的输入是:(1)眼睛位置(或者说相机位置)eys:(2)眼睛朝向的中心center,(就是眼睛朝哪里看);(3)头的方向up.任何一点经过视图变换后都会转化到眼睛坐标 ...

  6. 遗传算法在JobShop中的应用研究(part 2:编码)

    编码 在上一篇博客中我们讨论了车间调度问题的编码,具体说就是根据工件的个数和每个工件的工序数来生成12122这样的数字排列,具体的说一个工件包含多少道工序,那么这个工件的编号就出现多少次.从12122 ...

  7. Redis - 发布和订阅

    一.概述 1). 发布和订阅是一种消息通信模式. 2). 优点:使消息订阅者和消息发布者耦合度降低,类似设计模式中的观察者模式. 二.发布和订阅 订阅命令: // 订阅一个或多个频道 // 返回值:v ...

  8. 关于autoptr

    参考自: http://www.cppblog.com/expter/archive/2009/03/29/78270.html auto_ptr是什么. 解释1.auto_ptr是一个管理指针的对象 ...

  9. awk命令简单介绍

    简介 awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再 ...

  10. selenium 安装与 chromedriver安装

    直接使用pip安装 pip slenium 用 Chrome 浏览器来测试   from selenium import webdriver browser = webdriver.Chrome() ...