上一篇,总结linux2.6.20.3的移植,在此,并将cs8900的移植过程进行简单的记录,并将我读取的cs8900网卡初始化的流程附上。
移植过程参照ARM_Linux_Kernel_Porting_(MBA2410).pdf(我上一篇引导部分的内容这里也有,早知道就看看它就没必要自己花时间跟了),并修改了一些不合适的问题,linux 2.6.20.3参照此步骤,网卡是绝对可以驱动得上的。但是必需要注意网卡硬件的布线,比如片选引脚以及中断引脚等。
以下的修改内容蓝色为添加,红色为原有的,该色为要被替换的。
(1)修改 arch/arm/mach-s3c2410/Kconfig
找到config ARCH_SMDK2410修改为如下内容
config ARCH_SMDK2410
bool "SMDK2410/A9M2410"
select CPU_S3C2410
select MACH_SMDK
select NET_PCI
select ISA
help
Say Y here if you are using the SMDK2410 or the derived module A9M2410
<http://www.fsforth.de>
|
(2)修改include/asm-arm/arch-s3c2410/map.h
添加如下的宏定义
/* CS8900 */
#define S3C24XX_VA_CS8900 S3C2410_ADDR(0x01300000)
#define S3C2410_PA_CS8900 (0x19000000)
#define S3C24XX_SZ_CS8900 SZ_1M
#define S3C24XX_PA_CS8900 S3C2410_PA_CS8900
|
(3)修改arch/arm/mach-s3c2410/mach-s3c2410.c
在static struct map_desc smdk2410_iodesc[] __initdata作如下修改。
static struct map_desc smdk2410_iodesc[] __initdata = {
IODESC_ENT(CS8900)
};
|
|
(4)修改drivers/net/cs89x0.c文件
155 #endif
156 (加入)
#ifdef CONFIG_ARCH_S3C2410
#include <asm/ arch/map.h>
#include <asm/ arch/irqs.h>
#include <asm/ arch/regs-mem.h>
#include <asm/ arch/regs-gpio.h>
#endif
191 #elif defined(CONFIG_ARCH_PNX010X)
192 #include <asm/irq.h>
193 #include <asm/arch/gpio.h>
194 #define CIRRUS_DEFAULT_BASE IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x2
00000) /* = Physical address 0x48200000 */
195 #define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_
1 /* Event inputs bank 1 - ID 35/bit 3 */
196 static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0};
197 static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
#elif defined(CONFIG_ARCH_S3C2410)
static unsigned int netcard_portlist[] __initdata = { S3C24XX_VA_CS8900 + DEFAULTIOBASE, 0};
static unsigned int cs8900_irq_map[] = { IRQ_EINT9, 0, 0, 0 };
#ifdef request_region
#undef request_region
#endif
#ifdef release_region
#undef release_region
#endif
#define request_region(a, s, n) request_mem_region(a, s, n)
#define release_region(a, s) release_mem_region(a, s)
198 #else
199 static unsigned int netcard_portlist[] __initdata =
200 { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0,
0x2c0, 0x2e0, 0};
201 static unsigned int cs8900_irq_map[] = {10,11,12,5};
202 #endif
:
:
325 io = dev->base_addr;
326 irq = dev->irq;
327
#ifdef CONFIG_ARCH_S3C2410 __raw_writel((__raw_readl(S3C2410_GPGCON)&~(0x3<<2))|(0x2<<2),S3C2410_GPGCON);
__raw_writel((__raw_readl(S3C2410_EXTINT1)&~(0x7<<4))|(0x4<<4),S3C2410_EXTINT1);
#endif
328 if (net_debug)
329 printk("cs89x0:cs89x0_probe(0x%x)\n", io);
:
:
350 return ERR_PTR(err);
351 }
352 #endif
353
#if defined(CONFIG_ARCH_S3C2410)
static u16
readword(unsigned long base_addr, int portno)
{
return __raw_readw(base_addr + portno);
}
static void
writeword(unsigned long base_addr, int portno, u16 value)
{
__raw_writew(value, base_addr + portno);
}
#elif defined(CONFIG_MACH_IXDP2351)
#if defined(CONFIG_MACH_IXDP2351) //本句删除
:
:
633 reset_chip(dev);
634
#ifdef CONFIG_ARCH_S3C2410
lp->force = FORCE_RJ45;
lp->auto_neg_cnf = IMM_BIT;
dev->dev_addr[0] = 0x09;
dev->dev_addr[1] = 0x90;
dev->dev_addr[2] = 0x99;
dev->dev_addr[3] = 0x09;
dev->dev_addr[4] = 0x90;
dev->dev_addr[5] = 0x99;
#endif
:
:
#if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X)//该句删除
#if !defined(CONFIG_ARCH_S3C2410) && !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X)
1314 if (((1 << dev->irq) & lp->irq_map) == 0) {
1315 printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
1316 dev->name, dev->irq, lp->irq_map);
|
附上补丁,该补丁是直接针对linux2.6.20.3内核的移植以及在友善之臂cs8900网卡的驱动,patch上后make zImage就可以编译并运行。
|
文件:
|
sbc2410-linux2.6.20.3-with-cs8900.patch.tar.gz
|
大小:
|
8KB
|
下载:
|
下载
|
|
u-boot引导参数:
setenv bootargs root=/dev/nfs rw nfsroot=192.168.1.20:/nfsroot ip=192.168.1.12:192.168.1.20::255.255.255.0:::off mem=64M
|
cs8900初始化代码分析
整个代码分析由上叙述的的修改过程作为指导
static struct map_desc smdk2410_iodesc[] __initdata = {
IODESC_ENT(CS8900)
};
让我们看一下IODESC_ENT(CS8900)宏定义在arch/arm/mach-s3c2410/cup.h中的代码部分
#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
|
经过宏替换,原来的部分将被替换为如下的式子
static struct map_desc smdk2410_iodesc[] __initdata = {
{(unsigned long)S3C24XX_VA_CS8900,
__phys_to_pfn(S3C24XX_PA_CS8900)
S3C24XX_SZ_CS8900,
MT_DEVICE};
};
|
|
而其中的那些宏也就是我们在include/asm-arm/arch-s3c2410/map.h定义的那4个宏
#define S3C24XX_VA_CS8900 S3C2410_ADDR(0x01300000)
#define S3C2410_PA_CS8900 (0x19000000)
#define S3C24XX_SZ_CS8900 SZ_1M
#define S3C24XX_PA_CS8900 S3C2410_PA_CS8900
其中 S3C24XX_VA_CS8900 是CS8900的物理地址映射到虚拟内存页上的地址
S3C2410_PA_CS8900 是实际CS8900所在的物理地址
S3C24XX_SZ_CS8900 是为CS8900申请的虚拟内存空间的大小,这里设置为1M.
smdk2410_iodesc[]结构体数组会在系统为设备io的时候进行调用,该部分调用在以下的文件中:
arch/arm/mach-s3c2410/mach-smdk2410.c 中的smdk2410_map_io 函数内,函数实现如下:
static void __init smdk2410_map_io(void)
{
s3c24xx_init_io(smdk2410_iodesc,ARRAY_SIZE(smdk2410_iodesc));
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(smdk2410_uartcfgs,ARRAY_SIZE(smdk2410_uartcfgs));
s3c24xx_set_board(&smdk2410_board);
}
|
该函数会在系统读取完s3c2410的cpuId后执行运行。
当系统启动后,需要初始化CS8900该部分工作从 drivers/net/Space.c里的net_olddevs_init(void)函数开始。
static int __init net_olddevs_init(void)
{
int num;
#ifdef CONFIG_SBNI
for (num = 0; num < 8; ++num)
sbni_probe(num);
#endif
#ifdef CONFIG_TR
for (num = 0; num < 8; ++num)
if (!trif_probe(num))
trif_probe2(num);
#endif
for (num = 0; num < 8; ++num)
ethif_probe2(num);
#ifdef CONFIG_COPS
cops_probe(0);
cops_probe(1);
cops_probe(2);
#endif
#ifdef CONFIG_LTPC
ltpc_probe();
#endif
return 0;
}
|
如上代码的标红语句ethif_probe2(num);这个语句用来查询系统中所存在的网卡设备最多支持8个设备。
该函数也定义在Space.c中
static void __init ethif_probe2(int unit)
{
unsigned long base_addr = netdev_boot_base("eth", unit);
if (base_addr == 1)
return;
(void)(probe_list2(unit, m68k_probes, base_addr == 0) &&
probe_list2(unit, eisa_probes, base_addr == 0) &&
probe_list2(unit, mca_probes, base_addr == 0) &&
probe_list2(unit, isa_probes, base_addr == 0) &&
probe_list2(unit, parport_probes, base_addr == 0));
}
|
在上面的代码中有一个比较特别的函数probe_list2,这个函数用来调用特定的网卡设备所对应的初始化函数,而这个初始化函数能否被调用又是由系统编译前的裁减工作所确定的。以我们当前as8900网卡为例,来说明这点
static struct devprobe2 isa_probes[] __initdata = {
:
:
#ifdef CONFIG_CS89x0
{cs89x0_probe, 0},
#endif
:
:
}
|
因此在函数probe_list2内实际调用的初始化函数为cs89x0_probe函数。probe_list2的代码如下:
static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe)
{
struct net_device *dev;
for (; p->probe; p++) {
if (autoprobe && p->status)
continue;
dev = p->probe(unit);//该部分就实际调用cs89x0_probe
if (!IS_ERR(dev))
return 0;
if (autoprobe)
p->status = PTR_ERR(dev);
}
return -ENODEV;
}
|
我们随后就可以进入drivers/net/cs89x0.c文件中超找该函数cs89x0_probe。该函数的主要代码流程将以伪代码的方式给出:
(1)调用netdev_boot_setup_check(dev);遍历已有的网络设备,以确定当前要初始化的设备是否已经存在。(这些设备可以通过在引导过程中传入网络设置参数进行初始化设置)
(2)初始化CS8900的功能引脚。(这部分是由我们自己添加的)
(3)cs89x0_probe1(dev, *port, 0)调用该函数进行初始化探测工作,包括设备ID,初始化芯片,设置MAC地址(由我们添加),分配内存空间。
(4)当成功初始化设备后返回一个net_device的结构,作为这个设别的标识。
|
以上写的并不够详细,因为本身也没有过多的对它进行研究,只是在移植的过程中调试流程时的记录文档,作为备份以后补全。