[转]inux3.1.8内核移植到gt2440CS8900A驱动移植

一.   根据原理图,确认网卡的地址和中断号
地址:0x19000000

中断号: EINT9

二.   修改drivers/net/cs89x0.c,指定CS8900A使用的资源
#elif defined(CONFIG_ARCH_S3C2410)
#include
#include3c2410/regs-mem.h>
#define S3C24XX_PA_CS8900   0x19000000
static unsigned int netcard_portlist[] __initdate = {0, 0};
static unsigned int cs8900_irq_map[] = {IRQ_EINT9, 0, 0, 0};
#else

三.   修改入口函数cs89x0_probe
1.      
#if defined(CONFIG_ARCH_S3C2410)
       unsigned int oldval_bwscon;
       unsigned int oldval_bankcon3;
#endif

2.  设置MAC,总线宽度等:

#if defined(CONFIG_ARCH_S3C2410)if(netcard_portlist[0])return -ENODEV;netcard_portlist[0] = (unsigned int)ioremap(S3C24XX_PA_CS8900, SZ_1M) + 0x300;
dev->dev_addr[0] = 0x08;dev->dev_addr[1] = 0x89;dev->dev_addr[2] = 0x89;dev->dev_addr[3] = 0x89;dev->dev_addr[4] = 0x89;dev->dev_addr[5] = 0x89;
oldval_bwscon = *((volatile unsigned int *)S3C2410_BWSCON);*((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<12)) | S3C2410_BWSCON_DW3_16 | S3C2410_BWSCON_WS3 | S3C2410_BWSCON_ST3;oldval_bankcon3 = *((volatile unsigned int *)S3C2410_BANKCON3);*((volatile unsigned int *)S3C2410_BANKCON3) = 0x1f7c;

#endif

3.   出错退出

out:
#if defined(CONFIG_ARCH_S3C2410)
       iounmap(netcard_portlist[0]);
       netcard_portlist[0] = 0;
       *((volatile unsigned int *)S3C2410_BWSCON) = oldval_bwscon;
        *((volatile unsigned int *)S3C2410_BANKCON3) = oldval_bankcon3;
#endif

       free_netdev(dev);

修改后函数cs89x0_probe为:

struct net_device * __init cs89x0_probe(int unit)

{

struct net_device *dev = alloc_etherdev(sizeof(struct net_local));

unsigned *port;

int err = 0;

int irq;

unsigned int io;  /*修改*/

/*添加*/

#if defined(CONFIG_ARCH_S3C2410)  

unsigned int oldval_bwscon;

unsigned int oldval_bankcon3;

#endif

if (!dev)

return ERR_PTR(-ENODEV);

sprintf(dev->name, "eth%d", unit);

netdev_boot_setup_check(dev);

io = dev->base_addr;

irq = dev->irq;

/*添加*/

#if defined(CONFIG_ARCH_S3C2410)    

if(netcard_portlist[0])

return -ENODEV;

netcard_portlist[0] = (unsigned int)ioremap(S3C24XX_PA_CS8900, SZ_1M) + 0x300;

dev->dev_addr[0] = 0x08;

dev->dev_addr[1] = 0x89;

dev->dev_addr[2] = 0x89;

dev->dev_addr[3] = 0x89;

dev->dev_addr[4] = 0x89;

dev->dev_addr[5] = 0x89;

oldval_bwscon = *((volatile unsigned int *)S3C2410_BWSCON);

*((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<12)) | S3C2410_BWSCON_DW3_16 | S3C2410_BWSCON_WS3 | S3C2410_BWSCON_ST3;

oldval_bankcon3 = *((volatile unsigned int *)S3C2410_BANKCON3);

*((volatile unsigned int *)S3C2410_BANKCON3) = 0x1f7c;

#endif

if (net_debug)

printk("cs89x0:cs89x0_probe(0x%x)\n", io);

if (io > 0x1ff){/* Check a single specified location. */

err = cs89x0_probe1(dev, io, 0);

} else if (io != 0) {/* Don't probe at all. */

err = -ENXIO;

} else {

for (port = netcard_portlist; *port; port++) {

if (cs89x0_probe1(dev, *port, 0) == 0)

break;

dev->irq = irq;

}

if (!*port)

err = -ENODEV;

}

if (err)

goto out;

return dev;

out:

#if defined(CONFIG_ARCH_S3C2410)   /*添加*/

iounmap(netcard_portlist[0]);

netcard_portlist[0] = 0;

*((volatile unsigned int *)S3C2410_BWSCON) = oldval_bwscon;

*((volatile unsigned int *)S3C2410_BANKCON3) = oldval_bankcon3;

#endif

free_netdev(dev);

printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");

return ERR_PTR(err);

}

四.   注册中断处理程序,指定中断触发方式,修改net_open函数
#if 0
              writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
#endif
              write_irq(dev, lp->chip_type, dev->irq);

#if defined(CONFIG_ARCH_S3C2410)
              ret = request_irq(dev->irq, &net_interrupt, IRQF_TRIGGER_RISING, dev->name, dev);
#else
              ret = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev);
#endif

五.   在drivers/net/cs89x0.c中适当的位置加上CONFIG_ARCH_S3C2410宏编译开关,可以参考CONFIG_ARCH_PNX010X:
1. net_open(struct net_device *dev)
{
       struct net_local *lp = netdev_priv(dev);
       int result = 0;
       int i;
       int ret;

2. #if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X) && !defined(CONFIG_ARCH_S3C2410)
              if (((1 irq) & lp->irq_map) == 0) {
                     printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                               dev->name, dev->irq, lp->irq_map);
                     ret = -EAGAIN;
                     goto bad_out;
              }
#endif

3. #if defined(CONFIG_ARCH_PNX010X) || defined(CONFIG_ARCH_S3C2410)
       result = A_CNF_10B_T;
#endif

修改后net_open为:

static int

net_open(struct net_device *dev)

{

struct net_local *lp = netdev_priv(dev);

int result = 0;

int i;

int ret;

if (dev->irq < 2) {

/* Allow interrupts to be generated by the chip */

/* Cirrus' release had this: */

#if 0

writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );

#endif

/* And 2.3.47 had this: */

writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);

for (i = 2; i < CS8920_NO_INTS; i++) {

if ((1 << i) & lp->irq_map) {

if (request_irq(i, net_interrupt, 0, dev->name, dev) == 0) {

dev->irq = i;

write_irq(dev, lp->chip_type, i);

/* writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); */

break;

}

}

}

if (i >= CS8920_NO_INTS) {

writereg(dev, PP_BusCTL, 0);/* disable interrupts. */

printk(KERN_ERR "cs89x0: can't get an interrupt\n");

ret = -EAGAIN;

goto bad_out;

}

}

else

{

#ifndef CONFIG_CS89x0_NONISA_IRQ

if (((1 << dev->irq) & lp->irq_map) == 0) {

printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",

                               dev->name, dev->irq, lp->irq_map);

ret = -EAGAIN;

goto bad_out;

}

#endif

/* FIXME: Cirrus' release had this: */

writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );

/* And 2.3.47 had this: */

#if 0

writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);

#endif

write_irq(dev, lp->chip_type, dev->irq);

//ret = request_irq(dev->irq, net_interrupt, 0, dev->name, dev);  /*屏蔽掉*/

#if defined(CONFIG_ARCH_S3C2410)                                          /*添加*/

ret = request_irq(dev->irq, &net_interrupt, IRQF_TRIGGER_RISING, dev->name, dev);

#else

ret = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev);

#endif

if (ret) {

printk(KERN_ERR "cs89x0: request_irq(%d) failed\n", dev->irq);

goto bad_out;

}

}

#if ALLOW_DMA

if (lp->use_dma) {

if (lp->isa_config & ANY_ISA_DMA) {

unsigned long flags;

lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL,

get_order(lp->dmasize * 1024));

if (!lp->dma_buff) {

printk(KERN_ERR "%s: cannot get %dK memory for DMA\n", dev->name, lp->dmasize);

goto release_irq;

}

if (net_debug > 1) {

printk("%s: dma %lx %lx\n",

dev->name,

(unsigned long)lp->dma_buff,

(unsigned long)isa_virt_to_bus(lp->dma_buff));

}

if ((unsigned long) lp->dma_buff >= MAX_DMA_ADDRESS ||

   !dma_page_eq(lp->dma_buff, lp->dma_buff+lp->dmasize*1024-1)) {

printk(KERN_ERR "%s: not usable as DMA buffer\n", dev->name);

goto release_irq;

}

memset(lp->dma_buff, 0, lp->dmasize * 1024);/* Why? */

if (request_dma(dev->dma, dev->name)) {

printk(KERN_ERR "%s: cannot get dma channel %d\n", dev->name, dev->dma);

goto release_irq;

}

write_dma(dev, lp->chip_type, dev->dma);

lp->rx_dma_ptr = lp->dma_buff;

lp->end_dma_buff = lp->dma_buff + lp->dmasize*1024;

spin_lock_irqsave(&lp->lock, flags);

disable_dma(dev->dma);

clear_dma_ff(dev->dma);

set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */

set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff));

set_dma_count(dev->dma, lp->dmasize*1024);

enable_dma(dev->dma);

spin_unlock_irqrestore(&lp->lock, flags);

}

}

#endif/* ALLOW_DMA */

/* set the Ethernet address */

for (i=0; i < ETH_ALEN/2; i++)

writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));

/* while we're testing the interface, leave interrupts disabled */

writereg(dev, PP_BusCTL, MEMORY_ON);

/* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */

if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) && (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH))

                lp->linectl = LOW_RX_SQUELCH;

else

                lp->linectl = 0;

        /* check to make sure that they have the "right" hardware available */

switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {

case A_CNF_MEDIA_10B_T: result = lp->adapter_cnf & A_CNF_10B_T; break;

case A_CNF_MEDIA_AUI:   result = lp->adapter_cnf & A_CNF_AUI; break;

case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;

        default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);

        }

#if defined(CONFIG_ARCH_PNX010X) || defined(CONFIG_ARCH_S3C2410)   /*添加*/

result = A_CNF_10B_T;

#endif

        if (!result) {

                printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);

release_dma:

#if ALLOW_DMA

free_dma(dev->dma);

release_irq:

release_dma_buff(lp);

#endif

                writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));

                free_irq(dev->irq, dev);

ret = -EAGAIN;

goto bad_out;

}

        /* set the hardware to the configured choice */

switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {

case A_CNF_MEDIA_10B_T:

                result = detect_tp(dev);

                if (result==DETECTED_NONE) {

                        printk(KERN_WARNING "%s: 10Base-T (RJ-45) has no cable\n", dev->name);

                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */

                                result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */

                }

break;

case A_CNF_MEDIA_AUI:

                result = detect_aui(dev);

                if (result==DETECTED_NONE) {

                        printk(KERN_WARNING "%s: 10Base-5 (AUI) has no cable\n", dev->name);

                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */

                                result = DETECTED_AUI; /* Yes! I don't care if I see a carrrier */

                }

break;

case A_CNF_MEDIA_10B_2:

                result = detect_bnc(dev);

                if (result==DETECTED_NONE) {

                        printk(KERN_WARNING "%s: 10Base-2 (BNC) has no cable\n", dev->name);

                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */

                                result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */

                }

break;

case A_CNF_MEDIA_AUTO:

writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET);

if (lp->adapter_cnf & A_CNF_10B_T)

if ((result = detect_tp(dev)) != DETECTED_NONE)

break;

if (lp->adapter_cnf & A_CNF_AUI)

if ((result = detect_aui(dev)) != DETECTED_NONE)

break;

if (lp->adapter_cnf & A_CNF_10B_2)

if ((result = detect_bnc(dev)) != DETECTED_NONE)

break;

printk(KERN_ERR "%s: no media detected\n", dev->name);

goto release_dma;

}

switch(result) {

case DETECTED_NONE:

printk(KERN_ERR "%s: no network cable attached to configured media\n", dev->name);

goto release_dma;

case DETECTED_RJ45H:

printk(KERN_INFO "%s: using half-duplex 10Base-T (RJ-45)\n", dev->name);

break;

case DETECTED_RJ45F:

printk(KERN_INFO "%s: using full-duplex 10Base-T (RJ-45)\n", dev->name);

break;

case DETECTED_AUI:

printk(KERN_INFO "%s: using 10Base-5 (AUI)\n", dev->name);

break;

case DETECTED_BNC:

printk(KERN_INFO "%s: using 10Base-2 (BNC)\n", dev->name);

break;

}

/* Turn on both receive and transmit operations */

writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);

/* Receive only error free packets addressed to this card */

lp->rx_mode = 0;

writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);

lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;

if (lp->isa_config & STREAM_TRANSFER)

lp->curr_rx_cfg |= RX_STREAM_ENBL;

#if ALLOW_DMA

set_dma_cfg(dev);

#endif

writereg(dev, PP_RxCFG, lp->curr_rx_cfg);

writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |

TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);

writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |

#if ALLOW_DMA

dma_bufcfg(dev) |

#endif

TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);

/* now that we've got our act together, enable everything */

writereg(dev, PP_BusCTL, ENABLE_IRQ

| (dev->mem_start?MEMORY_ON : 0) /* turn memory on */

#if ALLOW_DMA

| dma_busctl(dev)

#endif);

        netif_start_queue(dev);

if (net_debug > 1)

printk("cs89x0: net_open() succeeded\n");

return 0;

bad_out:

return ret;

}

六.   修改cs89x0_probe函数中的  int io 为 unsigned int io;

七.   内核配置文件修改:
修改drivers/net/kconfig中的描述

config CS89x0

tristate "CS89x0 support"

depends on NET_ETHERNET && (ISA || EISA || MACH_IXDP2351 \

|| ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440) ||ARCH_S3C2410

---help---

 Support for CS89x0 chipset based Ethernet cards. If you have a

 network (Ethernet) card of this type, say Y and read the

 Ethernet-HOWTO, available from

 <http://www.tldp.org/docs.html#howto> as well as

 <file:Documentation/networking/cs89x0.txt>.

 To compile this driver as a module, choose M here. The module

 will be called cs89x0.

config CS89x0_NONISA_IRQ

def_bool y

depends on CS89x0 != n

depends on MACH_IXDP2351 || ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440 ||ARCH_S3C2410

/*必须添加ARCH_S3C2410,否则出现eth0: IRQ 53 is not in our map of allowable IRQs, which is 1c20的错误*/

八.   使用CS8900A网卡,在内核目录下执行make menuconfig后,选中

Device Drivers --->

[*] Network device support --->

[*]Ethernet (10 or 100Mbit) --->

< >   DM9000 support                                              

<*>   CS89x0 support  

九.编译

编译出现一下的警告:

drivers/net/cs89x0.c: In function 'cs89x0_probe':

drivers/net/cs89x0.c:335: warning: return makes pointer from integer without a cast

drivers/net/cs89x0.c:373: warning: passing argument 1 of '__iounmap' makes pointer from integer without a cast

十.测试

# ifconfig lo 127.0.0.1

#ifconfig eth0 172.19.69.211

#ping 172.19.69.254

PING 172.19.69.254 (172.19.69.254): 56 data bytes                               

64 bytes from 172.19.69.254: seq=0 ttl=64 time=1.552 ms                         

64 bytes from 172.19.69.254: seq=1 ttl=64 time=1.018 ms                         

64 bytes from 172.19.69.254: seq=2 ttl=64 time=1.028 ms                         

64 bytes from 172.19.69.254: seq=3 ttl=64 time=1.003 ms                         

64 bytes from 172.19.69.254: seq=4 ttl=64 time=0.998 ms                         

64 bytes from 172.19.69.254: seq=5 ttl=64 time=1.019 ms                         

64 bytes from 172.19.69.254: seq=6 ttl=64 time=0.972 ms                                                                                      

--- 172.19.69.254 ping statistics ---                                           

7 packets transmitted, 7 packets received, 0% packet loss                       

round-trip min/avg/max = 0.972/1.084/1.552 ms  

CS8900A驱动移植成功。

原文地址:https://www.cnblogs.com/dolphi/p/2642151.html