实际上给内核移植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) 中的初始化代码:
[mw_shl_code=c,true]static void __init smdkv210_machine_init(void)
{
s3c_pm_init();
/*smdkv210_dm9000_init();*/[/mw_shl_code]
修改platform-device中dm9000的配置,Mach-smdkv210.c (arch\arm\mach-s5pv210)
[mw_shl_code=c,true]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),
};[/mw_shl_code]
旧的代码为:
[mw_shl_code=c,true]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),
};[/mw_shl_code]
这里DEFINE_RES_MEM是一个宏
[mw_shl_code=c,true]#define DEFINE_RES_MEM(_start, _size) \
DEFINE_RES_MEM_NAMED((_start), (_size), NULL)[/mw_shl_code]
,DEFINE_RES_MEM(S5PV210_PA_SROM_BANK1, 4)展开后为:
[mw_shl_code=c,true] { \
.start = (S5PV210_PA_SROM_BANK1), \
.end = (S5PV210_PA_SROM_BANK1) + (4) - 1, \
.name = (NULL), \
.flags = (IORESOURCE_MEM), \
}[/mw_shl_code]
首先了解一下linux的platform-deivce驱动,linux 2.6之后的内核用platform_device结构体来描述设备资源,有了platform_device,就可以用platform_add_devices添加设备了,smdkv210_machine_init会调用platform_add_devices来添加所有设备。smdkv210所有的设备用smdkv210_devices数组来表示:
[mw_shl_code=c,true]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,
};[/mw_shl_code]
可见,其中包含了smdkv210_dm9000,该结构体定义如下:
[mw_shl_code=c,true]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,
},
};[/mw_shl_code]
看到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。
参考资料:
platform_device与platform_driver
http://blog.csdn.net/zhandoushi1982/article/details/5130207
linux driver 注册设备
http://blog.chinaunix.net/uid-9185047-id-445035.html |