Linux3.4.2移植CS8900网卡驱动到优龙FS2410开发板
一、S3C2410和CS8900的硬件连接
FS2410开发板的原理图我没有找到,但可看参考资料2,里面写的非常详细
二、移植过程
a) 配置内核支持S3C2410
选好Samsung S3C24XX SoCs后,会自动返回到上一级菜单(即前一张图),然后选择:
b) 配置内核支持CS89x0网卡
Device Drivers-->Network device support-->Ethernet driver support—>
c) 修改drivers/net/ethenet/cirrus/cs89x0.c:
(1)在文件开头增加以下几行,它们在宏CONFIG_ARCH_S3C24XX被定义时起作用,表示作用于FS2410开发板
183 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; 184 #elif defined(CONFIG_ARCH_S3C24XX) 185 #include <asm/irq.h> 186 #include <mach/regs-mem.h> 187 #define S3C24XX_PA_CS8900 0x19000000 /* 物理基地址 */ 188 static unsigned int netcard_portlist[] __initdata = {0, 0}; /* 在下面进行设置 */ 189 static unsigned int cs8900_irq_map[] = {IRQ_EINT9, 0, 0, 0}; /* 中断号*/ 190 #else 191 #ifndef CONFIG_CS89x0_PLATFORM 192 static unsigned int netcard_portlist[] __used __initdata =
(2)修改入口函数cs89x0_probe
以下使用宏CONFIG_ARCH_S3C24XX包裹起来的代码是新加的
311 struct net_device * __init cs89x0_probe(int unit) 312 { 313 struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); 314 unsigned *port; 315 int err = 0; 316 int irq; 317 int io; 318 #if defined(CONFIG_ARCH_S3C24XX) 319 unsigned int oldval_bwscon; /* 用来保存BWSCON寄存器的值 */ 320 unsigned int oldval_bankcon3; /* 用来保存S3C2410_BANKCON3寄存器的值 */ 321 #endif 322 if (!dev) 323 return ERR_PTR(-ENODEV); 324 325 sprintf(dev->name, "eth%d", unit); 326 netdev_boot_setup_check(dev); 327 io = dev->base_addr; 328 irq = dev->irq; 329 #if defined(CONFIG_ARCH_S3C24XX) 330 // cs89x0_probe会被调用多次,我们只需要1次,根据netcard_portlist[0]的值忽略后面的调用 331 if (netcard_portlist[0]) 332 return -ENODEV; 333 // 将CS8900A的物理地址转换为虚拟地址,0x300是CS8900A内部的IO空间的偏移地址 334 netcard_portlist[0] = (unsigned int)ioremap(S3C24XX_PA_CS8900, SZ_1M) + 0x300; 335 /* 设置默认MAC地址, 336 * MAC地址可以由CS8900A外接的EEPROM设定(有些单板没接EEPROM), 337 * 或者启动系统后使用ifconfig修改 338 */ 339 dev->dev_addr[0] = 0x08; 340 dev->dev_addr[1] = 0x89; 341 dev->dev_addr[2] = 0x89; 342 dev->dev_addr[3] = 0x89; 343 dev->dev_addr[4] = 0x89; 344 dev->dev_addr[5] = 0x89; 345 /* 设置Bank3: 总线宽度为16, 使能nWAIT, 使能UB/LB。by www.100ask.net */ 346 oldval_bwscon = *((volatile unsigned int *)S3C2410_BWSCON); 347 *((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<12)) \ 348 | S3C2410_BWSCON_DW3_16 | S3C2410_BWSCON_WS3 | S3C2410_BWSCON_ST3; 349 /* 设置BANK3的时间参数, by www.100ask.net */ 350 oldval_bankcon3 = *((volatile unsigned int *)S3C2410_BANKCON3); 351 *((volatile unsigned int *)S3C2410_BANKCON3) = 0x1f7c; 352 #endif 353 if (net_debug) 354 printk("cs89x0:cs89x0_probe(0x%x)\n", io); 355 356 if (io > 0x1ff) { /* Check a single specified location. */ 357 err = cs89x0_probe1(dev, io, 0); 358 } else if (io != 0) { /* Don't probe at all. */ 359 err = -ENXIO; 360 } else { 361 for (port = netcard_portlist; *port; port++) { 362 if (cs89x0_probe1(dev, *port, 0) == 0) 363 break; 364 dev->irq = irq; 365 } 366 if (!*port) 367 err = -ENODEV; 368 } 369 if (err) 370 goto out; 371 return dev; 372 out: 373 #if defined(CONFIG_ARCH_S3C24XX) 374 iounmap(netcard_portlist[0]); 375 netcard_portlist[0] = 0; 376 377 /* 恢复寄存器原来的值 */ 378 *((volatile unsigned int *)S3C2410_BWSCON) = oldval_bwscon; 379 *((volatile unsigned int *)S3C2410_BANKCON3) = oldval_bankcon3; 380 #endif 381 free_netdev(dev); 382 printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n"); 383 return ERR_PTR(err); 384 } 385 //#endif 多了一个 386 #endif
(3)修改模块入口函数init_module
以下使用宏CONFIG_ARCH_S3C24XX包裹起来的代码是新加的
1879 int __init init_module(void) 1880 { 1881 struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); 1882 struct net_local *lp; 1883 int ret = 0; 1884 #if defined(CONFIG_ARCH_S3C24XX) 1885 unsigned int oldval_bwscon; /* 用来保存BWSCON寄存器的值 */ 1886 unsigned int oldval_bankcon3; /* 用来保存S3C2410_BANKCON3寄存器的值 */ 1887 #endif 1888 #if DEBUGGING 1889 net_debug = debug; 1890 #else 1891 debug = 0; 1892 #endif 1893 if (!dev) 1894 return -ENOMEM; 1895 1896 #if defined(CONFIG_ARCH_S3C24XX) 1897 // 将CS8900A的物理地址转换为虚拟地址,0x300是CS8900A内部的IO空间的偏移地址 1898 dev->base_addr = io = (unsigned int)ioremap(S3C24XX_PA_CS8900, SZ_1M) + 0x300; 1899 dev->irq = irq = cs8900_irq_map[0]; /* 中断号 */ 1900 1901 /* 设置默认MAC地址, 1902 * MAC地址可以由CS8900A外接的EEPROM设定(有些单板没接EEPROM), 1903 * 或者启动系统后使用ifconfig修改 1904 */ 1905 dev->dev_addr[0] = 0x08; 1906 dev->dev_addr[1] = 0x89; 1907 dev->dev_addr[2] = 0x89; 1908 dev->dev_addr[3] = 0x89; 1909 dev->dev_addr[4] = 0x89; 1910 dev->dev_addr[5] = 0x89; 1911 1912 /* 设置Bank3: 总线宽度为16, 使能nWAIT, 使能UB/LB。by www.100ask.net */ 1913 oldval_bwscon = *((volatile unsigned int *)S3C2410_BWSCON); 1914 *((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<12)) \ 1915 | S3C2410_BWSCON_DW3_16 | S3C2410_BWSCON_WS3 | S3C2410_BWSCON_ST3; 1916 1917 /* 设置BANK3的时间参数, by www.100ask.net */ 1918 oldval_bankcon3 = *((volatile unsigned int *)S3C2410_BANKCON3); 1919 *((volatile unsigned int *)S3C2410_BANKCON3) = 0x1f7c; 1920 #else 1921 dev->irq = irq; 1922 dev->base_addr = io; 1923 #endif … … 1971 out: 1972 #if defined(CONFIG_ARCH_S3C24XX) 1973 iounmap(dev->base_addr); 1974 1975 /* 恢复寄存器原来的值 */ 1976 *((volatile unsigned int *)S3C2410_BWSCON) = oldval_bwscon; 1977 *((volatile unsigned int *)S3C2410_BANKCON3) = oldval_bankcon3; 1978 #endif 1979 free_netdev(dev); 1980 return ret; 1981 }
(4)修改模块退出函数cleanup_module
以下使用宏CONFIG_ARCH_S3C24XX包裹起来的代码是新加的
1983 void __exit 1984 cleanup_module(void) 1985 { 1986 unregister_netdev(dev_cs89x0); 1987 writeword(dev_cs89x0->base_addr, ADD_PORT, PP_ChipID); 1988 release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT); 1989 #if defined(CONFIG_ARCH_S3C24XX) 1990 iounmap(dev_cs89x0->base_addr); 1991 #endif 1992 free_netdev(dev_cs89x0); 1993 } 1994 #endif /* MODULE && !CONFIG_CS89x0_PLATFORM */ 1995
(5)修改net_open
1240 net_open(struct net_device *dev) 1241 { 1242 struct net_local *lp = netdev_priv(dev); 1243 int result = 0; 1244 int i; 1245 int ret; 1246 #if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX010X) && !defined(CONFIG_ARCH_S3C24XX) /* uses irq#1, so this won't work */ 1247 if (dev->irq < 2) { 1248 /* Allow interrupts to be generated by the chip */ 1249 /* Cirrus' release had this: */ 1250 #if 0 1251 writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); 1252 #endif 1253 /* And 2.3.47 had this: */ 1254 writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); ... ... 1273 } 1274 else 1275 #endif 1276 { 1277 #if !defined(CS89x0_NONISA_IRQ) && !defined(CONFIG_CS89x0_PLATFORM)&& !defined(CONFIG_ARCH_S3C24XX) 1278 if (((1 << dev->irq) & lp->irq_map) == 0) { 1279 printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", 1280 dev->name, dev->irq, lp->irq_map); 1281 ret = -EAGAIN; 1282 goto bad_out; 1283 } 1284 #endif 1285 /* FIXME: Cirrus' release had this: */ 1286 writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); 1287 /* And 2.3.47 had this: */ 1288 #if 0 1289 writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); 1290 #endif 1291 write_irq(dev, lp->chip_type, dev->irq); 1292 #if defined(CONFIG_ARCH_S3C24XX) 1293 ret = request_irq(dev->irq, &net_interrupt, IRQF_TRIGGER_RISING, dev->name, dev); 1294 #else 1295 ret = request_irq(dev->irq, net_interrupt, 0, dev->name, dev); 1296 #endif 1297 if (ret) { 1298 printk(KERN_ERR "cs89x0: request_irq(%d) failed\n", dev->irq); 1299 goto bad_out; 1300 } 1301 } ... ... 1358 /* check to make sure that they have the "right" hardware available */ 1359 switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) { 1360 case A_CNF_MEDIA_10B_T: result = lp->adapter_cnf & A_CNF_10B_T; break; 1361 case A_CNF_MEDIA_AUI: result = lp->adapter_cnf & A_CNF_AUI; break; 1362 case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break; 1363 default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2); 1364 } 1365 #if defined(CONFIG_ARCH_PNX010X) || defined(CONFIG_ARCH_S3C24XX) 1366 result = A_CNF_10B_T; 1367 #endif 1368 if (!result) { 1369 printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name); 1370 release_dma: ... ... 1478 }
(6)全局变量static int io 修改为static unsigned int io;
原因请看参考资料1
最后,编译内核,执行make uImage。
三、参考资料
1、《嵌入式linux应用开发完全手册》韦东山
2、《FS2410中CS8900A IO模式驱动分析》杨志平