linux网卡驱动移植
这里重要的是物理层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中添加
- static struct map_desc smdk2410_iodesc[] __initdata = {
- [0] = {
- .virtual = (unsigned long)S3C24XX_VA_DM9000,
- .pfn = __phys_to_pfn(S3C24XX_PA_DM9000),
- .length = SZ_1M,
- .type = MT_DEVICE,
- },
- };
这样在程序中访问S3C24XX_PA_DM9000,S3C24XX_PA_DM9000
+ 0x4对应的物理地址,就直接转换到相应的虚拟地址了。至此DM9000A平台设备的添加和IO地址的静态映射完成。然后就是修改DM9000A中的MAC地址等了。
修改drivers/net/dm9000.c 文件,增加3行:
- #include <mach/regs-gpio.h>
- #include <mach/irqs.h>
- #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,中断为上升沿触发。
在这个函数的最后需要修改:
- if (!is_valid_ether_addr(ndev->dev_addr)) {
- /* try reading from mac */
- mac_src = "chip";
- for (i = 0; i < 6; i++)
- //ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
- ndev->dev_addr[i] = mac_addr[i];
- }
在文件系统中添加网络配置文件,使系统在开机过程中自动完成对网卡的配置
1)在文件系统/etc/net.conf文件中添加内容
- IPADDR=192.168.0.105
- NETMASK=255.255.255.0
- GATEWAY=192.168.0.1
- MAC=00:11:22:33:44:55
2)在文件系统/sbin/目录下新建一个可执行的脚本文件net_config,注意文件的权限(可执行)
- #!/bin/sh
- echo Try to bring eth0 interface up ...>/dev/s3c2410_serial0
- if [ -f /etc/net.conf ] ; then
- source /etc/net.conf
- ifconfig eth0 down
- ifconfig eth0 hw ether $MAC
- echo ifconfig eth0 hw ether $MAC >/dev/s3c2410_serial0
- ifconfig eth0 $IPADDR netmask $NETMASK up
- echo ifconfig eth0 $IPADDR netmask $NETMASK up >/dev/s3c2410_serial0
- route add default gw $GATEWAY
- echo add default gw $GATEWAY >/dev/s3c2410_serial0
- else
- ifconfig eth0 hw ether 00:11:22:33:44:55
- ifconfig eth0 192.168.1.105 netmask 255.255.255.0 up
- route add default gw 192.168.0.1
- echo ifconfig eth0 hw ether 00:11:22:33:44:55 >/dev/s3c2410_serial0
- echo ifconfig eth0 192.168.0.105 netmask 255.255.255.0 up >/dev/s3c2410_serial0
- echo route add default gw 192.168.0.1 >/dev/s3c2410_serial0
- fi
- echo Done > /dev/s3c2410_serial0
3)在文件系统/etc/init.d/rcS文件中添加网络配置语句
- /sbin/ifconfig lo 127.0.0.1 #设置本地回环设备的IP地址
- 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) 中的初始化代码:
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)
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), }; |
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是一个宏
1
2
|
#define DEFINE_RES_MEM(_start, _size) \ DEFINE_RES_MEM_NAMED((_start), (_size), NULL) |
,DEFINE_RES_MEM(S5PV210_PA_SROM_BANK1, 4)展开后为:
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数组来表示:
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,该结构体定义如下:
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网卡驱动移植的更多相关文章
- Linux网卡驱动移植--Dm9000网卡驱动分析
1. Linux网络体系结构由以下5部分组成 ① 系统调用接口: 位于Linux网络子系统的顶部,为应用程序提供访问内核网络子系统的方法,主要指socket系统调用. ② 协议无关接口: 实现一组基于 ...
- 【Linux驱动】TQ2440 DM9000E网卡驱动移植(Linux-2.6.30.4)
花了一天的时间研究了一下Linux-2.6.30.4版本号内核下关于TQ2440 DM9000E的网卡驱动移植.总结一下自己的收获. 事实上.在Linux-2.6.30.4版本号内核下有关于网卡驱动, ...
- AM335x(TQ335x)学习笔记——Nand&&网卡驱动移植
移植完成声卡驱动之后本想再接再励,移植网卡驱动,但没想到的是TI维护的内核太健壮,移植网卡驱动跟之前移植按键驱动一样简单,Nand驱动也是如此,于是,本人将Nand和网卡放在同一篇文章中介绍.介绍之前 ...
- AM335x(TQ335x)学习笔记——Nand&&网卡驱动移植
移植完毕声卡驱动之后本想再接再励,移植网卡驱动,但没想到的是TI维护的内核太健壮,移植网卡驱动跟之前移植按键驱动一样简单,Nand驱动也是如此,于是,本人将Nand和网卡放在同一篇文章中介绍.介绍之前 ...
- linux4.1内核配置以及编译及千兆网卡dp83867网卡驱动移植
一 内核配置编译 1首先解压内核 tar jxvf linux-at91-4.1.tar.bz2: 2下载编译链 在ubuntu命令行中输入sudo apt-get install gcc-arm- ...
- linux enc28j60网卡驱动移植(硬件spi和模拟spi)
本来想移植DM9000网卡的驱动,无奈硬件出了点问题,通过杜邦线链接开发板和DM9000网卡模块,系统上电,还没加载网卡驱动就直接崩溃了,找不到原因...刚好手上有一个enc28j60的网卡模块,于是 ...
- mini2440移植uboot-2008.10 (二) DM9000网卡驱动移植
还是利用 mini2440移植uboot-2008.10 (一) 修改好的代码 通过观察可以发现,mini2400使用的网卡芯片是DM9000,在uboot-2008.10源码中已经支持该芯片的驱动 ...
- u-boot 移植 --->5、友善之臂Tiny210底板王网卡驱动移植
网卡芯片的工作原理 DM9000AE具有以下主要性能: ①48管脚的LQFP封装,管脚少体积小: ②支持8/16位数据总线: ③适用于10Base-T和100Base-T,10/100M自适应,适应不 ...
- Linux网卡驱动安装、防火墙原理
安装网卡驱动程序: 需要检查是否安装kernel依赖包: rpm –q kernel-devel #检查kernel依赖包是否安装 yum –y install kernel-devel 检查gcc和 ...
随机推荐
- 【Python】我的Python学习笔记【1】【using Python 2】
1.模块格式 #!/usr/bin/env python # -*- coding: utf-8 -*- ... ...def main(): ...... ... if __name__=='__m ...
- Chrom 浏览器一些命令
https://webkit.org/build-tools/ 开发环境搭建 开源:http://www.17ky.net/kyxm/4_0_3_2_0_0/ http://www.chromium ...
- HashCode
如果一个类的对象要用做hashMap的key,那么一定要注意覆盖该类的equals和hashCode方法. equals()是基类Object的方法,用于判断对象是否有相同地址及是否为同一对象 pub ...
- 解决打开CHM文件后,右侧空白
在网上下了一个chm的文件,打开后只有目录,右侧不显示内容. 不知道是文件有问题,还是系统有问题. <ignore_js_op> 右键点击文件–属性 看到 最下面有一个提示 说是这个文件是 ...
- MySQL数据库一个字段对应多个值得模糊查询
当一个字段想模糊查询出多个字段的时候,正常情况下一般会这么作 select * from a where name like 'a%' or name like 'b%' ....or ...; 但是 ...
- vs 2015 写php太爽了,毕竟我接触的第一款ide就是vs啊
- Android Activity的加载模式和onActivityResult方法之间的冲突
前言 今天在调试程序时,发现在某一Activity上点击返回键会调用该Activity的onActivityResult()方法.我一开始用log,后来用断点跟踪调试半天,还是百思不得其解.因为之前其 ...
- python中Scikit-Learn机器学习模块
Scikit-Learn是基于python的机器学习模块,基于BSD开源许可证.这个项目最早由DavidCournapeau 在2007 年发起的,目前也是由社区自愿者进行维护. Scikit-Lea ...
- GIT ON WINDOWS
https://help.github.com/articles/generating-an-ssh-key/
- jquery checkbox勾选/取消勾选的诡异问题
<form> 你爱好的运动是?<input type="checkbox" id="CheckedAll" />全选/全不选<br ...