码迷,mamicode.com
首页 > 其他好文 > 详细

DM9000C网卡驱动程序编写与测试

时间:2019-07-28 17:50:10      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:长度   出现   man   rdp   RoCE   mii-tool   ast   info   连接   

  • 一般网卡驱动程序厂商会给我们提供一份模板驱动,我们的工作就是需要根据自己的需要更改这个模板驱动

1、DM9000C的硬件连接

硬件连接图如下所示:它接在S3C2440的BANK4内存控制器上,它只占用8个字节的长度,并且是16bit的位宽。

技术图片

 

下面介绍一下DM9000C的主要引脚的功能:SD0-SD15位16bit的数据引脚接口;IOR为读使能信号,低电平有效;IOW为写使能信号,低电平有效;CS为片选信号,低电平有效;CMD为数据与索引选择信号,高电平表数据,低电平表索引,它连接到S3C2440的LADDR2地址引脚;INT表示中断引脚数据发送成功或接收到数据可以产生中断,高电平有效,所以对于S3C2440来说需要设置上升沿触发来触发中断。

 

2、DM9000C的驱动代码编写

直接贴上修改好的代码:此代码是在厂家提供的驱动源码基础上依照S3C2440的应用修改的。

   1 /*
   2 
   3   dm9ks.c: Version 2.08 2007/02/12 
   4   
   5         A Davicom DM9000/DM9010 ISA NIC fast Ethernet driver for Linux.
   6 
   7     This program is free software; you can redistribute it and/or
   8     modify it under the terms of the GNU General Public License
   9     as published by the Free Software Foundation; either version 2
  10     of the License, or (at your option) any later version.
  11 
  12     This program is distributed in the hope that it will be useful,
  13     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15     GNU General Public License for more details.
  16 
  17 
  18   (C)Copyright 1997-2007 DAVICOM Semiconductor,Inc. All Rights Reserved.
  19 
  20 V2.00 Spenser - 01/10/2005
  21             - Modification for PXA270 MAINSTONE.
  22             - Modified dmfe_tx_done().
  23             - Add dmfe_timeout().
  24 V2.01    10/07/2005    -Modified dmfe_timer()
  25             -Dected network speed 10/100M
  26 V2.02    10/12/2005    -Use link change to chage db->Speed
  27             -dmfe_open() wait for Link OK  
  28 V2.03    11/22/2005    -Power-off and Power-on PHY in dmfe_init_dm9000()
  29             -support IOL
  30 V2.04    12/13/2005    -delay 1.6s between power-on and power-off in 
  31              dmfe_init_dm9000()
  32             -set LED mode 1 in dmfe_init_dm9000()
  33             -add data bus driving capability in dmfe_init_dm9000()
  34              (optional)
  35 10/3/2006    -Add DM8606 read/write function by MDC and MDIO
  36 V2.06    01/03/2007    -CONT_RX_PKT_CNT=0xFFFF
  37             -modify dmfe_tx_done function
  38             -check RX FIFO pointer
  39             -if using physical address, re-define I/O function
  40             -add db->cont_rx_pkt_cnt=0 at the front of dmfe_packet_receive()
  41 V2.08    02/12/2007    -module parameter macro
  42             2.4  MODULE_PARM
  43             2.6  module_param
  44             -remove #include <linux/config>
  45               -fix dmfe_interrupt for kernel 2.6.20                  
  46 V2.09 05/24/2007    -support ethtool and mii-tool
  47 05/30/2007    -fix the driver bug when ifconfig eth0 (-)promisc and (-)allmulti.
  48 06/05/2007    -fix dm9000b issue(ex. 10M TX idle=65mA, 10M harmonic)
  49             -add flow control function (option)
  50 10/01/2007  -Add #include <asm/uaccess.h>
  51             -Modyfy dmfe_do_ioctl for kernel 2.6.7
  52 11/23/2007    -Add TDBUG to check TX FIFO pointer shift
  53             - Remove check_rx_ready() 
  54           - Add #define CHECKSUM to modify CHECKSUM function    
  55 12/20/2007  -Modify TX timeout routine(+)check TCR&0x01 
  56 
  57 */
  58 
  59 //#define CHECKSUM
  60 //#define TDBUG        /* check TX FIFO pointer */
  61 //#define RDBUG   /* check RX FIFO pointer */
  62 //#define DM8606
  63 
  64 #define DRV_NAME    "dm9KS"
  65 #define DRV_VERSION    "2.09"
  66 #define DRV_RELDATE    "2007-11-22"
  67 
  68 #ifdef MODVERSIONS
  69 #include <linux/modversions.h>
  70 #endif
  71 
  72 //#include <linux/config.h>
  73 #include <linux/init.h>                
  74 #include <linux/delay.h>
  75 #include <linux/module.h>
  76 #include <linux/ioport.h>
  77 #include <linux/netdevice.h>
  78 #include <linux/etherdevice.h>
  79 #include <linux/skbuff.h>
  80 #include <linux/version.h>
  81 #include <asm/dma.h>
  82 #include <linux/spinlock.h>
  83 #include <linux/crc32.h>
  84 #include <linux/mii.h>
  85 #include <linux/ethtool.h>
  86 #include <asm/uaccess.h>
  87 
  88 #ifdef CONFIG_ARCH_MAINSTONE
  89 #include <asm/io.h>
  90 #include <asm/hardware.h>
  91 #include <asm/irq.h>
  92 #endif
  93 
  94 #include <asm/delay.h>
  95 #include <asm/irq.h>
  96 #include <asm/io.h>
  97 #include <asm/arch-s3c2410/regs-mem.h>
  98 
  99 
 100 /* Board/System/Debug information/definition ---------------- */
 101 
 102 #define DM9KS_ID        0x90000A46
 103 #define DM9010_ID        0x90100A46
 104 /*-------register name-----------------------*/
 105 #define DM9KS_NCR        0x00    /* Network control Reg.*/
 106 #define DM9KS_NSR        0x01    /* Network Status Reg.*/
 107 #define DM9KS_TCR        0x02    /* TX control Reg.*/
 108 #define DM9KS_RXCR        0x05    /* RX control Reg.*/
 109 #define DM9KS_BPTR        0x08
 110 #define DM9KS_FCTR        0x09
 111 #define DM9KS_FCR            0x0a
 112 #define DM9KS_EPCR        0x0b
 113 #define DM9KS_EPAR        0x0c
 114 #define DM9KS_EPDRL        0x0d
 115 #define DM9KS_EPDRH        0x0e
 116 #define DM9KS_GPR            0x1f    /* General purpose register */
 117 #define DM9KS_CHIPR        0x2c
 118 #define DM9KS_TCR2        0x2d
 119 #define DM9KS_SMCR        0x2f     /* Special Mode Control Reg.*/
 120 #define DM9KS_ETXCSR    0x30    /* Early Transmit control/status Reg.*/
 121 #define    DM9KS_TCCR        0x31    /* Checksum cntrol Reg. */
 122 #define DM9KS_RCSR        0x32    /* Receive Checksum status Reg.*/
 123 #define DM9KS_BUSCR        0x38
 124 #define DM9KS_MRCMDX    0xf0
 125 #define DM9KS_MRCMD        0xf2
 126 #define DM9KS_MDRAL        0xf4
 127 #define DM9KS_MDRAH        0xf5
 128 #define DM9KS_MWCMD        0xf8
 129 #define DM9KS_MDWAL        0xfa
 130 #define DM9KS_MDWAH        0xfb
 131 #define DM9KS_TXPLL        0xfc
 132 #define DM9KS_TXPLH        0xfd
 133 #define DM9KS_ISR            0xfe
 134 #define DM9KS_IMR            0xff
 135 /*---------------------------------------------*/
 136 #define DM9KS_REG05        0x30    /* SKIP_CRC/SKIP_LONG */ 
 137 #define DM9KS_REGFF        0xA3    /* IMR */
 138 #define DM9KS_DISINTR    0x80
 139 
 140 #define DM9KS_PHY            0x40    /* PHY address 0x01 */
 141 #define DM9KS_PKT_RDY        0x01    /* Packet ready to receive */
 142 
 143 /* Added for PXA of MAINSTONE */
 144 #ifdef CONFIG_ARCH_MAINSTONE
 145 #include <asm/arch/mainstone.h>
 146 #define DM9KS_MIN_IO        (MST_ETH_PHYS + 0x300)
 147 #define DM9KS_MAX_IO            (MST_ETH_PHYS + 0x370)
 148 #define DM9K_IRQ        MAINSTONE_IRQ(3)
 149 #else
 150 #define DM9KS_MIN_IO        0x300
 151 #define DM9KS_MAX_IO        0x370
 152 #define DM9KS_IRQ        3
 153 #endif
 154 
 155 #define DM9KS_VID_L        0x28
 156 #define DM9KS_VID_H        0x29
 157 #define DM9KS_PID_L        0x2A
 158 #define DM9KS_PID_H        0x2B
 159 
 160 #define DM9KS_RX_INTR        0x01
 161 #define DM9KS_TX_INTR        0x02
 162 #define DM9KS_LINK_INTR        0x20
 163 
 164 #define DM9KS_DWORD_MODE    1
 165 #define DM9KS_BYTE_MODE        2
 166 #define DM9KS_WORD_MODE        0
 167 
 168 #define TRUE            1
 169 #define FALSE            0
 170 /* Number of continuous Rx packets */
 171 #define CONT_RX_PKT_CNT        0xFFFF
 172 
 173 #define DMFE_TIMER_WUT  jiffies+(HZ*5)    /* timer wakeup time : 5 second */
 174 
 175 #ifdef DM9KS_DEBUG
 176 #define DMFE_DBUG(dbug_now, msg, vaule) 177 if (dmfe_debug||dbug_now) printk(KERN_ERR "dmfe: %s %x\n", msg, vaule)
 178 #else
 179 #define DMFE_DBUG(dbug_now, msg, vaule) 180 if (dbug_now) printk(KERN_ERR "dmfe: %s %x\n", msg, vaule)
 181 #endif
 182 
 183 #ifndef CONFIG_ARCH_MAINSTONE
 184 #pragma pack(push, 1)
 185 #endif
 186 
 187 typedef struct _RX_DESC
 188 {
 189     u8 rxbyte;
 190     u8 status;
 191     u16 length;
 192 }RX_DESC;
 193 
 194 typedef union{
 195     u8 buf[4];
 196     RX_DESC desc;
 197 } rx_t;
 198 #ifndef CONFIG_ARCH_MAINSTONE
 199 #pragma pack(pop)
 200 #endif
 201 
 202 enum DM9KS_PHY_mode {
 203     DM9KS_10MHD   = 0, 
 204     DM9KS_100MHD  = 1, 
 205     DM9KS_10MFD   = 4,
 206     DM9KS_100MFD  = 5, 
 207     DM9KS_AUTO    = 8, 
 208 };
 209 
 210 /* Structure/enum declaration ------------------------------- */
 211 typedef struct board_info { 
 212     u32 io_addr;/* Register I/O base address */
 213     u32 io_data;/* Data I/O address */
 214     u8 op_mode;/* PHY operation mode */
 215     u8 io_mode;/* 0:word, 2:byte */
 216     u8 Speed;    /* current speed */
 217     u8 chip_revision;
 218     int rx_csum;/* 0:disable, 1:enable */
 219     
 220     u32 reset_counter;/* counter: RESET */ 
 221     u32 reset_tx_timeout;/* RESET caused by TX Timeout */
 222     int tx_pkt_cnt;
 223     int cont_rx_pkt_cnt;/* current number of continuos rx packets  */
 224     struct net_device_stats stats;
 225     
 226     struct timer_list timer;
 227     unsigned char srom[128];
 228     spinlock_t lock;
 229     struct mii_if_info mii;
 230 } board_info_t;
 231 /* Global variable declaration ----------------------------- */
 232 /*static int dmfe_debug = 0;*/
 233 static struct net_device * dmfe_dev = NULL;
 234 static struct ethtool_ops dmfe_ethtool_ops;
 235 /* For module input parameter */
 236 static int mode       = DM9KS_AUTO;  
 237 static int media_mode = DM9KS_AUTO;
 238 static int  irq        = DM9KS_IRQ;
 239 static int iobase     = DM9KS_MIN_IO;
 240 
 241 #if 0  // use physical address; Not virtual address
 242 #ifdef outb
 243     #undef outb
 244 #endif
 245 #ifdef outw
 246     #undef outw
 247 #endif
 248 #ifdef outl
 249     #undef outl
 250 #endif
 251 #ifdef inb
 252     #undef inb
 253 #endif
 254 #ifdef inw
 255     #undef inw
 256 #endif
 257 #ifdef inl
 258     #undef inl
 259 #endif
 260 void outb(u8 reg, u32 ioaddr)
 261 {
 262     (*(volatile u8 *)(ioaddr)) = reg;
 263 }
 264 void outw(u16 reg, u32 ioaddr)
 265 {
 266     (*(volatile u16 *)(ioaddr)) = reg;
 267 }
 268 void outl(u32 reg, u32 ioaddr)
 269 {
 270     (*(volatile u32 *)(ioaddr)) = reg;
 271 }
 272 u8 inb(u32 ioaddr)
 273 {
 274     return (*(volatile u8 *)(ioaddr));
 275 }
 276 u16 inw(u32 ioaddr)
 277 {
 278     return (*(volatile u16 *)(ioaddr));
 279 }
 280 u32 inl(u32 ioaddr)
 281 {
 282     return (*(volatile u32 *)(ioaddr));
 283 }
 284 #endif
 285 
 286 /* function declaration ------------------------------------- */
 287 int dmfe_probe1(struct net_device *);
 288 static int dmfe_open(struct net_device *);
 289 static int dmfe_start_xmit(struct sk_buff *, struct net_device *);
 290 static void dmfe_tx_done(unsigned long);
 291 static void dmfe_packet_receive(struct net_device *);
 292 static int dmfe_stop(struct net_device *);
 293 static struct net_device_stats * dmfe_get_stats(struct net_device *); 
 294 static int dmfe_do_ioctl(struct net_device *, struct ifreq *, int);
 295 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 296 static void dmfe_interrupt(int , void *, struct pt_regs *); 
 297 #else
 298     #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
 299     static irqreturn_t dmfe_interrupt(int , void *, struct pt_regs *);
 300     #else
 301     static irqreturn_t dmfe_interrupt(int , void *);/* for kernel 2.6.20 */
 302     #endif
 303 #endif
 304 static void dmfe_timer(unsigned long);
 305 static void dmfe_init_dm9000(struct net_device *);
 306 static unsigned long cal_CRC(unsigned char *, unsigned int, u8);
 307 u8 ior(board_info_t *, int);
 308 void iow(board_info_t *, int, u8);
 309 static u16 phy_read(board_info_t *, int);
 310 static void phy_write(board_info_t *, int, u16);
 311 static u16 read_srom_word(board_info_t *, int);
 312 static void dm9000_hash_table(struct net_device *);
 313 static void dmfe_timeout(struct net_device *);
 314 static void dmfe_reset(struct net_device *);
 315 static int mdio_read(struct net_device *, int, int);
 316 static void mdio_write(struct net_device *, int, int, int);
 317 static void dmfe_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
 318 static int dmfe_get_settings(struct net_device *, struct ethtool_cmd *);
 319 static int dmfe_set_settings(struct net_device *, struct ethtool_cmd *);
 320 static u32 dmfe_get_link(struct net_device *);
 321 static int dmfe_nway_reset(struct net_device *);
 322 static uint32_t dmfe_get_rx_csum(struct net_device *);
 323 static uint32_t dmfe_get_tx_csum(struct net_device *);
 324 static int dmfe_set_rx_csum(struct net_device *, uint32_t );
 325 static int dmfe_set_tx_csum(struct net_device *, uint32_t );
 326 
 327 #ifdef DM8606
 328 #include "dm8606.h"
 329 #endif
 330 
 331 //DECLARE_TASKLET(dmfe_tx_tasklet,dmfe_tx_done,0);
 332 
 333 /* DM9000 network baord routine ---------------------------- */
 334 
 335 /*
 336   Search DM9000 board, allocate space and register it
 337 */
 338 
 339 struct net_device * __init dmfe_probe(void)
 340 {
 341     struct net_device *dev;
 342     int err;
 343     
 344     DMFE_DBUG(0, "dmfe_probe()",0);
 345 
 346 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 347     dev = init_etherdev(NULL, sizeof(struct board_info));
 348     //ether_setup(dev);        
 349 #else
 350     dev= alloc_etherdev(sizeof(struct board_info));
 351 #endif
 352 
 353     if(!dev)
 354         return ERR_PTR(-ENOMEM);
 355 
 356          SET_MODULE_OWNER(dev);
 357     err = dmfe_probe1(dev);
 358     if (err)
 359         goto out;
 360 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
 361     err = register_netdev(dev);
 362     if (err)
 363         goto out1;
 364 #endif
 365     return dev;
 366 out1:
 367     release_region(dev->base_addr,2);
 368 out:
 369 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 370     kfree(dev);
 371 #else
 372     free_netdev(dev);
 373 #endif
 374     return ERR_PTR(err);
 375 }
 376 
 377 int __init dmfe_probe1(struct net_device *dev)
 378 {
 379     struct board_info *db;    /* Point a board information structure */
 380     u32 id_val;
 381     u16 i, dm9000_found = FALSE;
 382     u8 MAC_addr[6]={0x00,0x60,0x6E,0x33,0x44,0x55};
 383     u8 HasEEPROM=0,chip_info;
 384     DMFE_DBUG(0, "dmfe_probe1()",0);
 385 
 386     /* Search All DM9000 serial NIC */
 387     do {
 388         outb(DM9KS_VID_L, iobase); /* DM9000C的索引寄存器(cmd引脚为0)   */
 389         id_val = inb(iobase + 4);  /* 读DM9000C的数据寄存器(cmd引脚为1) */
 390         outb(DM9KS_VID_H, iobase);
 391         id_val |= inb(iobase + 4) << 8;
 392         outb(DM9KS_PID_L, iobase);
 393         id_val |= inb(iobase + 4) << 16;
 394         outb(DM9KS_PID_H, iobase);
 395         id_val |= inb(iobase + 4) << 24;
 396 
 397         if (id_val == DM9KS_ID || id_val == DM9010_ID) {
 398             
 399             /* Request IO from system */
 400             if(!request_region(iobase, 2, dev->name))
 401                 return -ENODEV;
 402 
 403             printk(KERN_ERR"<DM9KS> I/O: %x, VID: %x \n",iobase, id_val);
 404             dm9000_found = TRUE;
 405 
 406             /* Allocated board information structure */
 407             memset(dev->priv, 0, sizeof(struct board_info));
 408             db = (board_info_t *)dev->priv;
 409             dmfe_dev    = dev;
 410             db->io_addr  = iobase;
 411             db->io_data = iobase + 4;   
 412             db->chip_revision = ior(db, DM9KS_CHIPR);
 413             
 414             chip_info = ior(db,0x43);
 415             
 416             /* andy */
 417             //if((db->chip_revision!=0x1A) || ((chip_info&(1<<5))!=0) || ((chip_info&(1<<2))!=1)) return -ENODEV;
 418                         
 419             /* driver system function */                
 420             dev->base_addr         = iobase;
 421             dev->irq         = irq;
 422             dev->open         = &dmfe_open;
 423             dev->hard_start_xmit     = &dmfe_start_xmit;
 424             dev->watchdog_timeo    = 5*HZ;    
 425             dev->tx_timeout        = dmfe_timeout;
 426             dev->stop         = &dmfe_stop;
 427             dev->get_stats         = &dmfe_get_stats;
 428             dev->set_multicast_list = &dm9000_hash_table;
 429             dev->do_ioctl         = &dmfe_do_ioctl;
 430 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,28)
 431             dev->ethtool_ops = &dmfe_ethtool_ops;
 432 #endif
 433 #ifdef CHECKSUM
 434             //dev->features |=  NETIF_F_IP_CSUM;
 435             dev->features |=  NETIF_F_IP_CSUM|NETIF_F_SG;
 436 #endif
 437             db->mii.dev = dev;
 438             db->mii.mdio_read = mdio_read;
 439             db->mii.mdio_write = mdio_write;
 440             db->mii.phy_id = 1;
 441 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)
 442             db->mii.phy_id_mask = 0x1F; 
 443             db->mii.reg_num_mask = 0x1F; 
 444 #endif
 445             //db->msg_enable =(debug == 0 ? DMFE_DEF_MSG_ENABLE : ((1 << debug) - 1));
 446             
 447             /* Read SROM content */
 448             for (i=0; i<64; i++)
 449                 ((u16 *)db->srom)[i] = read_srom_word(db, i);
 450 
 451             /* Get the PID and VID from EEPROM to check */
 452             id_val = (((u16 *)db->srom)[4])|(((u16 *)db->srom)[5]<<16); 
 453             printk("id_val=%x\n", id_val);
 454             if (id_val == DM9KS_ID || id_val == DM9010_ID) 
 455                 HasEEPROM =1;
 456             
 457             /* Set Node Address */
 458             for (i=0; i<6; i++)
 459             {
 460                 if (HasEEPROM) /* use EEPROM */
 461                     dev->dev_addr[i] = db->srom[i];
 462                 else    /* No EEPROM */
 463                     dev->dev_addr[i] = MAC_addr[i];
 464             }
 465         }//end of if()
 466         iobase += 0x10;
 467     }while(!dm9000_found && iobase <= DM9KS_MAX_IO);
 468 
 469     return dm9000_found ? 0:-ENODEV;
 470 }
 471 
 472 
 473 /*
 474   Open the interface.
 475   The interface is opened whenever "ifconfig" actives it.
 476 */
 477 static int dmfe_open(struct net_device *dev)
 478 {
 479     board_info_t *db = (board_info_t *)dev->priv;
 480     u8 reg_nsr;
 481     int i;
 482     DMFE_DBUG(0, "dmfe_open", 0);
 483     
 484     /* andy */
 485     if (request_irq(dev->irq,&dmfe_interrupt,IRQF_TRIGGER_RISING,dev->name,dev)) 
 486         return -EAGAIN;
 487 
 488     /* Initilize DM910X board */
 489     dmfe_init_dm9000(dev);
 490 #ifdef DM8606
 491     // control DM8606
 492     printk("[8606]reg0=0x%04x\n",dm8606_read(db,0));
 493     printk("[8606]reg1=0x%04x\n",dm8606_read(db,0x1));
 494 #endif 
 495     /* Init driver variable */
 496     db->reset_counter     = 0;
 497     db->reset_tx_timeout     = 0;
 498     db->cont_rx_pkt_cnt    = 0;
 499     
 500     /* check link state and media speed */
 501     db->Speed =10;
 502     i=0;
 503     do {
 504         reg_nsr = ior(db,DM9KS_NSR);
 505         if(reg_nsr & 0x40) /* link OK!! */
 506         {
 507             /* wait for detected Speed */
 508             mdelay(200);
 509             reg_nsr = ior(db,DM9KS_NSR);
 510             if(reg_nsr & 0x80)
 511                 db->Speed =10;
 512             else
 513                 db->Speed =100;
 514             break;
 515         }
 516         i++;
 517         mdelay(1);
 518     }while(i<3000);    /* wait 3 second  */
 519     //printk("i=%d  Speed=%d\n",i,db->Speed);    
 520     /* set and active a timer process */
 521     init_timer(&db->timer);
 522     db->timer.expires     = DMFE_TIMER_WUT;
 523     db->timer.data         = (unsigned long)dev;
 524     db->timer.function     = &dmfe_timer;
 525     add_timer(&db->timer);    //Move to DM9000 initiallization was finished.
 526      
 527     netif_start_queue(dev);
 528 
 529     return 0;
 530 }
 531 
 532 /* Set PHY operationg mode
 533 */
 534 static void set_PHY_mode(board_info_t *db)
 535 {
 536 #ifndef DM8606
 537     u16 phy_reg0 = 0x1000;/* Auto-negotiation*/
 538     u16 phy_reg4 = 0x01e1;
 539 
 540     if ( !(db->op_mode & DM9KS_AUTO) ) // op_mode didn‘t auto sense */
 541     { 
 542         switch(db->op_mode) {
 543             case DM9KS_10MHD:  phy_reg4 = 0x21; 
 544                                        phy_reg0 = 0x1000;
 545                        break;
 546             case DM9KS_10MFD:  phy_reg4 = 0x41; 
 547                        phy_reg0 = 0x1100;
 548                                        break;
 549             case DM9KS_100MHD: phy_reg4 = 0x81; 
 550                        phy_reg0 = 0x3000;
 551                            break;
 552             case DM9KS_100MFD: phy_reg4 = 0x101; 
 553                        phy_reg0 = 0x3100;
 554                           break;
 555             default: 
 556                        break;
 557         } // end of switch
 558     } // end of if
 559 #ifdef FLOW_CONTROL
 560     phy_write(db, 4, phy_reg4|(1<<10));
 561 #else
 562     phy_write(db, 4, phy_reg4);
 563 #endif //end of FLOW_CONTROL
 564     phy_write(db, 0, phy_reg0|0x200);
 565 #else
 566     /* Fiber mode */
 567     phy_write(db, 16, 0x4014);
 568     phy_write(db, 0, 0x2100);
 569 #endif //end of DM8606
 570 
 571     if (db->chip_revision == 0x1A)
 572     {
 573         //set 10M TX idle =65mA (TX 100% utility is 160mA)
 574         phy_write(db,20, phy_read(db,20)|(1<<11)|(1<<10));
 575         
 576         //:fix harmonic
 577         //For short code:
 578         //PHY_REG 27 (1Bh) <- 0000h
 579         phy_write(db, 27, 0x0000);
 580         //PHY_REG 27 (1Bh) <- AA00h
 581         phy_write(db, 27, 0xaa00);
 582 
 583         //PHY_REG 27 (1Bh) <- 0017h
 584         phy_write(db, 27, 0x0017);
 585         //PHY_REG 27 (1Bh) <- AA17h
 586         phy_write(db, 27, 0xaa17);
 587 
 588         //PHY_REG 27 (1Bh) <- 002Fh
 589         phy_write(db, 27, 0x002f);
 590         //PHY_REG 27 (1Bh) <- AA2Fh
 591         phy_write(db, 27, 0xaa2f);
 592         
 593         //PHY_REG 27 (1Bh) <- 0037h
 594         phy_write(db, 27, 0x0037);
 595         //PHY_REG 27 (1Bh) <- AA37h
 596         phy_write(db, 27, 0xaa37);
 597         
 598         //PHY_REG 27 (1Bh) <- 0040h
 599         phy_write(db, 27, 0x0040);
 600         //PHY_REG 27 (1Bh) <- AA40h
 601         phy_write(db, 27, 0xaa40);
 602         
 603         //For long code:
 604         //PHY_REG 27 (1Bh) <- 0050h
 605         phy_write(db, 27, 0x0050);
 606         //PHY_REG 27 (1Bh) <- AA50h
 607         phy_write(db, 27, 0xaa50);
 608         
 609         //PHY_REG 27 (1Bh) <- 006Bh
 610         phy_write(db, 27, 0x006b);
 611         //PHY_REG 27 (1Bh) <- AA6Bh
 612         phy_write(db, 27, 0xaa6b);
 613         
 614         //PHY_REG 27 (1Bh) <- 007Dh
 615         phy_write(db, 27, 0x007d);
 616         //PHY_REG 27 (1Bh) <- AA7Dh
 617         phy_write(db, 27, 0xaa7d);
 618         
 619         //PHY_REG 27 (1Bh) <- 008Dh
 620         phy_write(db, 27, 0x008d);
 621         //PHY_REG 27 (1Bh) <- AA8Dh
 622         phy_write(db, 27, 0xaa8d);
 623         
 624         //PHY_REG 27 (1Bh) <- 009Ch
 625         phy_write(db, 27, 0x009c);
 626         //PHY_REG 27 (1Bh) <- AA9Ch
 627         phy_write(db, 27, 0xaa9c);
 628         
 629         //PHY_REG 27 (1Bh) <- 00A3h
 630         phy_write(db, 27, 0x00a3);
 631         //PHY_REG 27 (1Bh) <- AAA3h
 632         phy_write(db, 27, 0xaaa3);
 633         
 634         //PHY_REG 27 (1Bh) <- 00B1h
 635         phy_write(db, 27, 0x00b1);
 636         //PHY_REG 27 (1Bh) <- AAB1h
 637         phy_write(db, 27, 0xaab1);
 638         
 639         //PHY_REG 27 (1Bh) <- 00C0h
 640         phy_write(db, 27, 0x00c0);
 641         //PHY_REG 27 (1Bh) <- AAC0h
 642         phy_write(db, 27, 0xaac0);
 643         
 644         //PHY_REG 27 (1Bh) <- 00D2h
 645         phy_write(db, 27, 0x00d2);
 646         //PHY_REG 27 (1Bh) <- AAD2h
 647         phy_write(db, 27, 0xaad2);
 648         
 649         //PHY_REG 27 (1Bh) <- 00E0h
 650         phy_write(db, 27, 0x00e0);
 651         //PHY_REG 27 (1Bh) <- AAE0h
 652         phy_write(db, 27, 0xaae0);
 653         //PHY_REG 27 (1Bh) <- 0000h
 654         phy_write(db, 27, 0x0000);
 655     }
 656 }
 657 
 658 /* 
 659     Initilize dm9000 board
 660 */
 661 static void dmfe_init_dm9000(struct net_device *dev)
 662 {
 663     board_info_t *db = (board_info_t *)dev->priv;
 664     DMFE_DBUG(0, "dmfe_init_dm9000()", 0);
 665 
 666     spin_lock_init(&db->lock);
 667     
 668     iow(db, DM9KS_GPR, 0);    /* GPR (reg_1Fh)bit GPIO0=0 pre-activate PHY */
 669     mdelay(20);        /* wait for PHY power-on ready */
 670 
 671     /* do a software reset and wait 20us */
 672     iow(db, DM9KS_NCR, 3);
 673     udelay(20);        /* wait 20us at least for software reset ok */
 674     iow(db, DM9KS_NCR, 3);    /* NCR (reg_00h) bit[0] RST=1 & Loopback=1, reset on */
 675     udelay(20);        /* wait 20us at least for software reset ok */
 676 
 677     /* I/O mode */
 678     db->io_mode = ior(db, DM9KS_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */
 679 
 680     /* Set PHY */
 681     db->op_mode = media_mode;
 682     set_PHY_mode(db);
 683 
 684     /* Program operating register */
 685     iow(db, DM9KS_NCR, 0);
 686     iow(db, DM9KS_TCR, 0);        /* TX Polling clear */
 687     iow(db, DM9KS_BPTR, 0x3f);    /* Less 3kb, 600us */
 688     iow(db, DM9KS_SMCR, 0);        /* Special Mode */
 689     iow(db, DM9KS_NSR, 0x2c);    /* clear TX status */
 690     iow(db, DM9KS_ISR, 0x0f);     /* Clear interrupt status */
 691     iow(db, DM9KS_TCR2, 0x80);    /* Set LED mode 1 */
 692     if (db->chip_revision == 0x1A){ 
 693         /* Data bus current driving/sinking capability  */
 694         iow(db, DM9KS_BUSCR, 0x01);    /* default: 2mA */
 695     }
 696 #ifdef FLOW_CONTROL
 697     iow(db, DM9KS_BPTR, 0x37);
 698     iow(db, DM9KS_FCTR, 0x38);
 699     iow(db, DM9KS_FCR, 0x29);
 700 #endif
 701 
 702 #ifdef DM8606
 703     iow(db,0x34,1);
 704 #endif
 705 
 706     if (dev->features & NETIF_F_HW_CSUM){
 707         printk(KERN_INFO "DM9KS:enable TX checksum\n");
 708         iow(db, DM9KS_TCCR, 0x07);    /* TX UDP/TCP/IP checksum enable */
 709     }
 710     if (db->rx_csum){
 711         printk(KERN_INFO "DM9KS:enable RX checksum\n");
 712         iow(db, DM9KS_RCSR, 0x02);    /* RX checksum enable */
 713     }
 714 
 715 #ifdef ETRANS
 716     /*If TX loading is heavy, the driver can try to anbel "early transmit".
 717     The programmer can tune the "Early Transmit Threshold" to get 
 718     the optimization. (DM9KS_ETXCSR.[1-0])
 719     
 720     Side Effect: It will happen "Transmit under-run". When TX under-run
 721     always happens, the programmer can increase the value of "Early 
 722     Transmit Threshold". */
 723     iow(db, DM9KS_ETXCSR, 0x83);
 724 #endif
 725  
 726     /* Set address filter table */
 727     dm9000_hash_table(dev);
 728 
 729     /* Activate DM9000/DM9010 */
 730     iow(db, DM9KS_IMR, DM9KS_REGFF); /* Enable TX/RX interrupt mask */
 731     iow(db, DM9KS_RXCR, DM9KS_REG05 | 1);    /* RX enable */
 732     
 733     /* Init Driver variable */
 734     db->tx_pkt_cnt         = 0;
 735         
 736     netif_carrier_on(dev);
 737 
 738 }
 739 
 740 /*
 741   Hardware start transmission.
 742   Send a packet to media from the upper layer.
 743 */
 744 static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
 745 {
 746     board_info_t *db = (board_info_t *)dev->priv;
 747     char * data_ptr;
 748     int i, tmplen;
 749     u16 MDWAH, MDWAL;
 750     
 751     #ifdef TDBUG /* check TX FIFO pointer */
 752             u16 MDWAH1, MDWAL1;
 753             u16 tx_ptr;
 754     #endif
 755     
 756     DMFE_DBUG(0, "dmfe_start_xmit", 0);
 757     if (db->chip_revision != 0x1A)
 758     {    
 759         if(db->Speed == 10)
 760             {if (db->tx_pkt_cnt >= 1) return 1;}
 761         else
 762             {if (db->tx_pkt_cnt >= 2) return 1;}
 763     }else
 764         if (db->tx_pkt_cnt >= 2) return 1;
 765     
 766     /* packet counting */
 767     db->tx_pkt_cnt++;
 768 
 769     db->stats.tx_packets++;
 770     db->stats.tx_bytes+=skb->len;
 771     if (db->chip_revision != 0x1A)
 772     {
 773         if (db->Speed == 10)
 774             {if (db->tx_pkt_cnt >= 1) netif_stop_queue(dev);}
 775         else
 776             {if (db->tx_pkt_cnt >= 2) netif_stop_queue(dev);}
 777     }else
 778         if (db->tx_pkt_cnt >= 2) netif_stop_queue(dev);        
 779 
 780     /* Disable all interrupt */
 781     iow(db, DM9KS_IMR, DM9KS_DISINTR);
 782 
 783     MDWAH = ior(db,DM9KS_MDWAH);
 784     MDWAL = ior(db,DM9KS_MDWAL);
 785 
 786     /* Set TX length to reg. 0xfc & 0xfd */
 787     iow(db, DM9KS_TXPLL, (skb->len & 0xff));
 788     iow(db, DM9KS_TXPLH, (skb->len >> 8) & 0xff);
 789 
 790     /* Move data to TX SRAM */
 791     data_ptr = (char *)skb->data;
 792     
 793     outb(DM9KS_MWCMD, db->io_addr); // Write data into SRAM trigger
 794     switch(db->io_mode)
 795     {
 796         case DM9KS_BYTE_MODE:
 797             for (i = 0; i < skb->len; i++)
 798                 outb((data_ptr[i] & 0xff), db->io_data);
 799             break;
 800         case DM9KS_WORD_MODE:
 801             tmplen = (skb->len + 1) / 2;
 802             for (i = 0; i < tmplen; i++)
 803         outw(((u16 *)data_ptr)[i], db->io_data);
 804       break;
 805     case DM9KS_DWORD_MODE:
 806       tmplen = (skb->len + 3) / 4;            
 807             for (i = 0; i< tmplen; i++)
 808                 outl(((u32 *)data_ptr)[i], db->io_data);
 809             break;
 810     }
 811     
 812 #ifndef ETRANS
 813     /* Issue TX polling command */
 814     iow(db, DM9KS_TCR, 0x1); /* Cleared after TX complete*/
 815 #endif
 816 
 817     #ifdef TDBUG /* check TX FIFO pointer */
 818             MDWAH1 = ior(db,DM9KS_MDWAH);
 819             MDWAL1 = ior(db,DM9KS_MDWAL);
 820             tx_ptr = (MDWAH<<8)|MDWAL;
 821             switch (db->io_mode)
 822             {
 823                 case DM9KS_BYTE_MODE:
 824                     tx_ptr += skb->len;
 825                     break;
 826                 case DM9KS_WORD_MODE:
 827                     tx_ptr += ((skb->len + 1) / 2)*2;
 828                     break;
 829                 case DM9KS_DWORD_MODE:
 830                     tx_ptr += ((skb->len+3)/4)*4;
 831                     break;
 832             }
 833             if (tx_ptr > 0x0bff)
 834                     tx_ptr -= 0x0c00;
 835             if (tx_ptr != ((MDWAH1<<8)|MDWAL1))
 836                     printk("[dm9ks:TX FIFO ERROR\n");
 837     #endif
 838     /* Saved the time stamp */
 839     dev->trans_start = jiffies;
 840     db->cont_rx_pkt_cnt =0;
 841 
 842     /* Free this SKB */
 843     dev_kfree_skb(skb);
 844 
 845     /* Re-enable interrupt */
 846     iow(db, DM9KS_IMR, DM9KS_REGFF);
 847 
 848     return 0;
 849 }
 850 
 851 /*
 852   Stop the interface.
 853   The interface is stopped when it is brought.
 854 */
 855 static int dmfe_stop(struct net_device *dev)
 856 {
 857     board_info_t *db = (board_info_t *)dev->priv;
 858     DMFE_DBUG(0, "dmfe_stop", 0);
 859 
 860     /* deleted timer */
 861     del_timer(&db->timer);
 862 
 863     netif_stop_queue(dev); 
 864 
 865     /* free interrupt */
 866     free_irq(dev->irq, dev);
 867 
 868     /* RESET devie */
 869     phy_write(db, 0x00, 0x8000);    /* PHY RESET */
 870     //iow(db, DM9KS_GPR, 0x01);     /* Power-Down PHY */
 871     iow(db, DM9KS_IMR, DM9KS_DISINTR);    /* Disable all interrupt */
 872     iow(db, DM9KS_RXCR, 0x00);    /* Disable RX */
 873 
 874     /* Dump Statistic counter */
 875 #if FALSE
 876     printk("\nRX FIFO OVERFLOW %lx\n", db->stats.rx_fifo_errors);
 877     printk("RX CRC %lx\n", db->stats.rx_crc_errors);
 878     printk("RX LEN Err %lx\n", db->stats.rx_length_errors);
 879     printk("RESET %x\n", db->reset_counter);
 880     printk("RESET: TX Timeout %x\n", db->reset_tx_timeout);
 881     printk("g_TX_nsr %x\n", g_TX_nsr);
 882 #endif
 883 
 884     return 0;
 885 }
 886 
 887 static void dmfe_tx_done(unsigned long unused)
 888 {
 889     struct net_device *dev = dmfe_dev;
 890     board_info_t *db = (board_info_t *)dev->priv;
 891     int  nsr;
 892 
 893     DMFE_DBUG(0, "dmfe_tx_done()", 0);
 894     
 895     nsr = ior(db, DM9KS_NSR);
 896     if (nsr & 0x0c)
 897     {
 898         if(nsr & 0x04) db->tx_pkt_cnt--;
 899         if(nsr & 0x08) db->tx_pkt_cnt--;
 900         if(db->tx_pkt_cnt < 0)
 901         {
 902             printk(KERN_DEBUG "DM9KS:tx_pkt_cnt ERROR!!\n");
 903             while(ior(db,DM9KS_TCR) & 0x1){}
 904             db->tx_pkt_cnt = 0;
 905         }
 906             
 907     }else{
 908         while(ior(db,DM9KS_TCR) & 0x1){}
 909         db->tx_pkt_cnt = 0;
 910     }
 911         
 912     netif_wake_queue(dev);
 913     
 914     return;
 915 }
 916 
 917 /*
 918   DM9000 insterrupt handler
 919   receive the packet to upper layer, free the transmitted packet
 920 */
 921 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 922 static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 923 #else
 924     #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
 925     static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 926     #else
 927     static irqreturn_t dmfe_interrupt(int irq, void *dev_id) /* for kernel 2.6.20*/
 928     #endif
 929 #endif
 930 {
 931     struct net_device *dev = dev_id;
 932     board_info_t *db;
 933     int int_status,i;
 934     u8 reg_save;
 935 
 936     DMFE_DBUG(0, "dmfe_interrupt()", 0);
 937 
 938     /* A real interrupt coming */
 939     db = (board_info_t *)dev->priv;
 940     spin_lock(&db->lock);
 941 
 942     /* Save previous register address */
 943     reg_save = inb(db->io_addr);
 944 
 945     /* Disable all interrupt */
 946     iow(db, DM9KS_IMR, DM9KS_DISINTR); 
 947 
 948     /* Got DM9000/DM9010 interrupt status */
 949     int_status = ior(db, DM9KS_ISR);        /* Got ISR */
 950     iow(db, DM9KS_ISR, int_status);        /* Clear ISR status */ 
 951 
 952     /* Link status change */
 953     if (int_status & DM9KS_LINK_INTR) 
 954     {
 955         netif_stop_queue(dev);
 956         for(i=0; i<500; i++) /*wait link OK, waiting time =0.5s */
 957         {
 958             phy_read(db,0x1);
 959             if(phy_read(db,0x1) & 0x4) /*Link OK*/
 960             {
 961                 /* wait for detected Speed */
 962                 for(i=0; i<200;i++)
 963                     udelay(1000);
 964                 /* set media speed */
 965                 if(phy_read(db,0)&0x2000) db->Speed =100;
 966                 else db->Speed =10;
 967                 break;
 968             }
 969             udelay(1000);
 970         }
 971         netif_wake_queue(dev);
 972         //printk("[INTR]i=%d speed=%d\n",i, (int)(db->Speed));    
 973     }
 974     /* Received the coming packet */
 975     if (int_status & DM9KS_RX_INTR) 
 976         dmfe_packet_receive(dev);
 977 
 978     /* Trnasmit Interrupt check */
 979     if (int_status & DM9KS_TX_INTR)
 980         dmfe_tx_done(0);
 981     
 982     if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT)
 983     {
 984         iow(db, DM9KS_IMR, 0xa2);
 985     }
 986     else
 987     {
 988         /* Re-enable interrupt mask */ 
 989         iow(db, DM9KS_IMR, DM9KS_REGFF);
 990     }
 991     
 992     /* Restore previous register address */
 993     outb(reg_save, db->io_addr); 
 994 
 995     spin_unlock(&db->lock); 
 996 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
 997     return IRQ_HANDLED;
 998 #endif
 999 }
1000 
1001 /*
1002   Get statistics from driver.
1003 */
1004 static struct net_device_stats * dmfe_get_stats(struct net_device *dev)
1005 {
1006     board_info_t *db = (board_info_t *)dev->priv;
1007     DMFE_DBUG(0, "dmfe_get_stats", 0);
1008     return &db->stats;
1009 }
1010 /*
1011  *    Process the ethtool ioctl command
1012  */
1013 static int dmfe_ethtool_ioctl(struct net_device *dev, void *useraddr)
1014 {
1015     //struct dmfe_board_info *db = dev->priv;
1016     struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
1017     u32 ethcmd;
1018 
1019     if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
1020         return -EFAULT;
1021 
1022     switch (ethcmd) 
1023     {
1024         case ETHTOOL_GDRVINFO:
1025             strcpy(info.driver, DRV_NAME);
1026             strcpy(info.version, DRV_VERSION);
1027 
1028             sprintf(info.bus_info, "ISA 0x%lx %d",dev->base_addr, dev->irq);
1029             if (copy_to_user(useraddr, &info, sizeof(info)))
1030                 return -EFAULT;
1031             return 0;
1032     }
1033 
1034     return -EOPNOTSUPP;
1035 }
1036 /*
1037   Process the upper socket ioctl command
1038 */
1039 static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1040 {
1041     board_info_t *db = (board_info_t *)dev->priv;
1042     #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) /* for kernel 2.6.7 */
1043     struct mii_ioctl_data *data=(struct mii_ioctl_data *)&ifr->ifr_data; 
1044     #endif
1045   int rc=0;
1046         
1047     DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
1048     
1049         if (!netif_running(dev))
1050             return -EINVAL;
1051 
1052         if (cmd == SIOCETHTOOL)
1053         rc = dmfe_ethtool_ioctl(dev, (void *) ifr->ifr_data);
1054     else {
1055         spin_lock_irq(&db->lock);
1056         #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) /* for kernel 2.6.7 */
1057             rc = generic_mii_ioctl(&db->mii, data, cmd, NULL);
1058         #else
1059             rc = generic_mii_ioctl(&db->mii, if_mii(ifr), cmd, NULL);
1060         #endif
1061         spin_unlock_irq(&db->lock);
1062     }
1063 
1064     return rc;
1065 }
1066 
1067 /* Our watchdog timed out. Called by the networking layer */
1068 static void dmfe_timeout(struct net_device *dev)
1069 {
1070     board_info_t *db = (board_info_t *)dev->priv;
1071     int i;
1072     
1073     DMFE_DBUG(0, "dmfe_TX_timeout()", 0);
1074     printk("TX time-out -- dmfe_timeout().\n");
1075     db->reset_tx_timeout++;
1076     db->stats.tx_errors++;
1077     
1078 #if FALSE
1079     printk("TX packet count = %d\n", db->tx_pkt_cnt);    
1080     printk("TX timeout = %d\n", db->reset_tx_timeout);    
1081     printk("22H=0x%02x  23H=0x%02x\n",ior(db,0x22),ior(db,0x23));
1082     printk("faH=0x%02x  fbH=0x%02x\n",ior(db,0xfa),ior(db,0xfb));
1083 #endif
1084 
1085     i=0;
1086 
1087     while((i++<100)&&(ior(db,DM9KS_TCR) & 0x01))
1088     {
1089         udelay(30);
1090     }
1091         
1092     if(i<100)
1093     {
1094             db->tx_pkt_cnt = 0;
1095             netif_wake_queue(dev);
1096     }
1097     else
1098     {
1099             dmfe_reset(dev);
1100     }
1101 
1102 }
1103 
1104 static void dmfe_reset(struct net_device * dev)
1105 {
1106     board_info_t *db = (board_info_t *)dev->priv;
1107     u8 reg_save;
1108     int i;
1109     /* Save previous register address */
1110     reg_save = inb(db->io_addr);
1111 
1112     netif_stop_queue(dev); 
1113     db->reset_counter++;
1114     dmfe_init_dm9000(dev);
1115     
1116     db->Speed =10;
1117     for(i=0; i<1000; i++) /*wait link OK, waiting time=1 second */
1118     {
1119         if(phy_read(db,0x1) & 0x4) /*Link OK*/
1120         {
1121             if(phy_read(db,0)&0x2000) db->Speed =100;
1122             else db->Speed =10;
1123             break;
1124         }
1125         udelay(1000);
1126     }
1127     
1128     netif_wake_queue(dev);
1129     
1130     /* Restore previous register address */
1131     outb(reg_save, db->io_addr);
1132 
1133 }
1134 /*
1135   A periodic timer routine
1136 */
1137 static void dmfe_timer(unsigned long data)
1138 {
1139     struct net_device * dev = (struct net_device *)data;
1140     board_info_t *db = (board_info_t *)dev->priv;
1141     DMFE_DBUG(0, "dmfe_timer()", 0);
1142     
1143     if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT)
1144     {
1145         db->cont_rx_pkt_cnt=0;
1146         iow(db, DM9KS_IMR, DM9KS_REGFF);
1147     }
1148     /* Set timer again */
1149     db->timer.expires = DMFE_TIMER_WUT;
1150     add_timer(&db->timer);
1151     
1152     return;
1153 }
1154 
1155 
1156 /*
1157   Received a packet and pass to upper layer
1158 */
1159 static void dmfe_packet_receive(struct net_device *dev)
1160 {
1161     board_info_t *db = (board_info_t *)dev->priv;
1162     struct sk_buff *skb;
1163     u8 rxbyte;
1164     u16 i, GoodPacket, tmplen = 0, MDRAH, MDRAL;
1165     u32 tmpdata;
1166 
1167     rx_t rx;
1168 
1169     u16 * ptr = (u16*)&rx;
1170     u8* rdptr;
1171 
1172     DMFE_DBUG(0, "dmfe_packet_receive()", 0);
1173 
1174     db->cont_rx_pkt_cnt=0;
1175     
1176     do {
1177         /*store the value of Memory Data Read address register*/
1178         MDRAH=ior(db, DM9KS_MDRAH);
1179         MDRAL=ior(db, DM9KS_MDRAL);
1180         
1181         ior(db, DM9KS_MRCMDX);        /* Dummy read */
1182         rxbyte = inb(db->io_data);    /* Got most updated data */
1183 
1184 #ifdef CHECKSUM    
1185         if (rxbyte&0x2)            /* check RX byte */
1186         {    
1187       printk("dm9ks: abnormal!\n");
1188             dmfe_reset(dev); 
1189             break;    
1190     }else { 
1191       if (!(rxbyte&0x1))
1192                 break;    
1193     }        
1194 #else
1195         if (rxbyte==0)
1196             break;
1197         
1198         if (rxbyte>1)
1199         {    
1200       printk("dm9ks: Rxbyte error!\n");
1201           dmfe_reset(dev);
1202       break;    
1203     }
1204 #endif
1205 
1206         /* A packet ready now  & Get status/length */
1207         GoodPacket = TRUE;
1208         outb(DM9KS_MRCMD, db->io_addr);
1209 
1210         /* Read packet status & length */
1211         switch (db->io_mode) 
1212             {
1213               case DM9KS_BYTE_MODE: 
1214                      *ptr = inb(db->io_data) + 
1215                                (inb(db->io_data) << 8);
1216                     *(ptr+1) = inb(db->io_data) + 
1217                         (inb(db->io_data) << 8);
1218                     break;
1219               case DM9KS_WORD_MODE:
1220                     *ptr = inw(db->io_data);
1221                     *(ptr+1)    = inw(db->io_data);
1222                     break;
1223               case DM9KS_DWORD_MODE:
1224                     tmpdata  = inl(db->io_data);
1225                     *ptr = tmpdata;
1226                     *(ptr+1)    = tmpdata >> 16;
1227                     break;
1228               default:
1229                     break;
1230             }
1231 
1232         /* Packet status check */
1233         if (rx.desc.status & 0xbf)
1234         {
1235             GoodPacket = FALSE;
1236             if (rx.desc.status & 0x01) 
1237             {
1238                 db->stats.rx_fifo_errors++;
1239                 printk(KERN_INFO"<RX FIFO error>\n");
1240             }
1241             if (rx.desc.status & 0x02) 
1242             {
1243                 db->stats.rx_crc_errors++;
1244                 printk(KERN_INFO"<RX CRC error>\n");
1245             }
1246             if (rx.desc.status & 0x80) 
1247             {
1248                 db->stats.rx_length_errors++;
1249                 printk(KERN_INFO"<RX Length error>\n");
1250             }
1251             if (rx.desc.status & 0x08)
1252                 printk(KERN_INFO"<Physical Layer error>\n");
1253         }
1254 
1255         if (!GoodPacket)
1256         {
1257             // drop this packet!!!
1258             switch (db->io_mode)
1259             {
1260                 case DM9KS_BYTE_MODE:
1261                      for (i=0; i<rx.desc.length; i++)
1262                         inb(db->io_data);
1263                     break;
1264                 case DM9KS_WORD_MODE:
1265                     tmplen = (rx.desc.length + 1) / 2;
1266                     for (i = 0; i < tmplen; i++)
1267                         inw(db->io_data);
1268                     break;
1269                 case DM9KS_DWORD_MODE:
1270                     tmplen = (rx.desc.length + 3) / 4;
1271                     for (i = 0; i < tmplen; i++)
1272                         inl(db->io_data);
1273                     break;
1274             }
1275             continue;/*next the packet*/
1276         }
1277         
1278         skb = dev_alloc_skb(rx.desc.length+4);
1279         if (skb == NULL )
1280         {    
1281             printk(KERN_INFO "%s: Memory squeeze.\n", dev->name);
1282             /*re-load the value into Memory data read address register*/
1283             iow(db,DM9KS_MDRAH,MDRAH);
1284             iow(db,DM9KS_MDRAL,MDRAL);
1285             return;
1286         }
1287         else
1288         {
1289             /* Move data from DM9000 */
1290             skb->dev = dev;
1291             skb_reserve(skb, 2);
1292             rdptr = (u8*)skb_put(skb, rx.desc.length - 4);
1293             
1294             /* Read received packet from RX SARM */
1295             switch (db->io_mode)
1296             {
1297                 case DM9KS_BYTE_MODE:
1298                      for (i=0; i<rx.desc.length; i++)
1299                         rdptr[i]=inb(db->io_data);
1300                     break;
1301                 case DM9KS_WORD_MODE:
1302                     tmplen = (rx.desc.length + 1) / 2;
1303                     for (i = 0; i < tmplen; i++)
1304                         ((u16 *)rdptr)[i] = inw(db->io_data);
1305                     break;
1306                 case DM9KS_DWORD_MODE:
1307                     tmplen = (rx.desc.length + 3) / 4;
1308                     for (i = 0; i < tmplen; i++)
1309                         ((u32 *)rdptr)[i] = inl(db->io_data);
1310                     break;
1311             }
1312         
1313             /* Pass to upper layer */
1314             skb->protocol = eth_type_trans(skb,dev);
1315 
1316 #ifdef CHECKSUM
1317         if((rxbyte&0xe0)==0)    /* receive packet no checksum fail */
1318                 skb->ip_summed = CHECKSUM_UNNECESSARY;
1319 #endif
1320         
1321             netif_rx(skb);
1322             dev->last_rx=jiffies;
1323             db->stats.rx_packets++;
1324             db->stats.rx_bytes += rx.desc.length;
1325             db->cont_rx_pkt_cnt++;
1326 #ifdef RDBG /* check RX FIFO pointer */
1327             u16 MDRAH1, MDRAL1;
1328             u16 tmp_ptr;
1329             MDRAH1 = ior(db,DM9KS_MDRAH);
1330             MDRAL1 = ior(db,DM9KS_MDRAL);
1331             tmp_ptr = (MDRAH<<8)|MDRAL;
1332             switch (db->io_mode)
1333             {
1334                 case DM9KS_BYTE_MODE:
1335                     tmp_ptr += rx.desc.length+4;
1336                     break;
1337                 case DM9KS_WORD_MODE:
1338                     tmp_ptr += ((rx.desc.length+1)/2)*2+4;
1339                     break;
1340                 case DM9KS_DWORD_MODE:
1341                     tmp_ptr += ((rx.desc.length+3)/4)*4+4;
1342                     break;
1343             }
1344             if (tmp_ptr >=0x4000)
1345                 tmp_ptr = (tmp_ptr - 0x4000) + 0xc00;
1346             if (tmp_ptr != ((MDRAH1<<8)|MDRAL1))
1347                 printk("[dm9ks:RX FIFO ERROR\n");
1348 #endif
1349                 
1350             if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT)
1351             {
1352                 dmfe_tx_done(0);
1353                 break;
1354             }
1355         }
1356             
1357     }while((rxbyte & 0x01) == DM9KS_PKT_RDY);
1358     DMFE_DBUG(0, "[END]dmfe_packet_receive()", 0);
1359     
1360 }
1361 
1362 /*
1363   Read a word data from SROM
1364 */
1365 static u16 read_srom_word(board_info_t *db, int offset)
1366 {
1367     iow(db, DM9KS_EPAR, offset);
1368     iow(db, DM9KS_EPCR, 0x4);
1369     while(ior(db, DM9KS_EPCR)&0x1);    /* Wait read complete */
1370     iow(db, DM9KS_EPCR, 0x0);
1371     return (ior(db, DM9KS_EPDRL) + (ior(db, DM9KS_EPDRH) << 8) );
1372 }
1373 
1374 /*
1375   Set DM9000/DM9010 multicast address
1376 */
1377 static void dm9000_hash_table(struct net_device *dev)
1378 {
1379     board_info_t *db = (board_info_t *)dev->priv;
1380     struct dev_mc_list *mcptr = dev->mc_list;
1381     int mc_cnt = dev->mc_count;
1382     u32 hash_val;
1383     u16 i, oft, hash_table[4];
1384 
1385     DMFE_DBUG(0, "dm9000_hash_table()", 0);
1386 
1387     /* enable promiscuous mode */
1388     if (dev->flags & IFF_PROMISC){
1389         //printk(KERN_INFO "DM9KS:enable promiscuous mode\n");
1390         iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)|(1<<1));
1391         return;
1392     }else{
1393         //printk(KERN_INFO "DM9KS:disable promiscuous mode\n");
1394         iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)&(~(1<<1)));
1395     }
1396         
1397     /* Receive all multicast packets */
1398     if (dev->flags & IFF_ALLMULTI){
1399         //printk(KERN_INFO "DM9KS:Pass all multicast\n");
1400         iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)|(1<<3));
1401     }else{
1402         //printk(KERN_INFO "DM9KS:Disable pass all multicast\n");
1403         iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)&(~(1<<3)));
1404     }
1405     
1406     /* Set Node address */
1407     for (i = 0, oft = 0x10; i < 6; i++, oft++)
1408         iow(db, oft, dev->dev_addr[i]);
1409 
1410     /* Clear Hash Table */
1411     for (i = 0; i < 4; i++)
1412         hash_table[i] = 0x0;
1413 
1414     /* broadcast address */
1415     hash_table[3] = 0x8000;
1416 
1417     /* the multicast address in Hash Table : 64 bits */
1418     for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
1419         hash_val = cal_CRC((char *)mcptr->dmi_addr, 6, 0) & 0x3f; 
1420         hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
1421     }
1422 
1423     /* Write the hash table to MAC MD table */
1424     for (i = 0, oft = 0x16; i < 4; i++) {
1425         iow(db, oft++, hash_table[i] & 0xff);
1426         iow(db, oft++, (hash_table[i] >> 8) & 0xff);
1427     }
1428 }
1429 
1430 /*
1431   Calculate the CRC valude of the Rx packet
1432   flag = 1 : return the reverse CRC (for the received packet CRC)
1433          0 : return the normal CRC (for Hash Table index)
1434 */
1435 static unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
1436 {    
1437     u32 crc = ether_crc_le(Len, Data);
1438 
1439     if (flag) 
1440         return ~crc;
1441         
1442     return crc;     
1443 }
1444 
1445 static int mdio_read(struct net_device *dev, int phy_id, int location)
1446 {
1447     board_info_t *db = (board_info_t *)dev->priv;
1448     return phy_read(db, location);
1449 }
1450 
1451 static void mdio_write(struct net_device *dev, int phy_id, int location, int val)
1452 {
1453     board_info_t *db = (board_info_t *)dev->priv;
1454     phy_write(db, location, val);
1455 }
1456 
1457 /*
1458    Read a byte from I/O port
1459 */
1460 u8 ior(board_info_t *db, int reg)
1461 {
1462     outb(reg, db->io_addr);
1463     return inb(db->io_data);
1464 }
1465 
1466 /*
1467    Write a byte to I/O port
1468 */
1469 void iow(board_info_t *db, int reg, u8 value)
1470 {
1471     outb(reg, db->io_addr);
1472     outb(value, db->io_data);
1473 }
1474 
1475 /*
1476    Read a word from phyxcer
1477 */
1478 static u16 phy_read(board_info_t *db, int reg)
1479 {
1480     /* Fill the phyxcer register into REG_0C */
1481     iow(db, DM9KS_EPAR, DM9KS_PHY | reg);
1482 
1483     iow(db, DM9KS_EPCR, 0xc);     /* Issue phyxcer read command */
1484     while(ior(db, DM9KS_EPCR)&0x1);    /* Wait read complete */
1485     iow(db, DM9KS_EPCR, 0x0);     /* Clear phyxcer read command */
1486 
1487     /* The read data keeps on REG_0D & REG_0E */
1488     return ( ior(db, DM9KS_EPDRH) << 8 ) | ior(db, DM9KS_EPDRL);
1489     
1490 }
1491 
1492 /*
1493    Write a word to phyxcer
1494 */
1495 static void phy_write(board_info_t *db, int reg, u16 value)
1496 {
1497     /* Fill the phyxcer register into REG_0C */
1498     iow(db, DM9KS_EPAR, DM9KS_PHY | reg);
1499 
1500     /* Fill the written data into REG_0D & REG_0E */
1501     iow(db, DM9KS_EPDRL, (value & 0xff));
1502     iow(db, DM9KS_EPDRH, ( (value >> 8) & 0xff));
1503 
1504     iow(db, DM9KS_EPCR, 0xa);    /* Issue phyxcer write command */
1505     while(ior(db, DM9KS_EPCR)&0x1);    /* Wait read complete */
1506     iow(db, DM9KS_EPCR, 0x0);    /* Clear phyxcer write command */
1507 }
1508 //====dmfe_ethtool_ops member functions====
1509 static void dmfe_get_drvinfo(struct net_device *dev,
1510                    struct ethtool_drvinfo *info)
1511 {
1512     //board_info_t *db = (board_info_t *)dev->priv;
1513     strcpy(info->driver, DRV_NAME);
1514     strcpy(info->version, DRV_VERSION);
1515     sprintf(info->bus_info, "ISA 0x%lx irq=%d",dev->base_addr, dev->irq);
1516 }
1517 static int dmfe_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1518 {
1519     board_info_t *db = (board_info_t *)dev->priv;
1520     spin_lock_irq(&db->lock);
1521     mii_ethtool_gset(&db->mii, cmd);
1522     spin_unlock_irq(&db->lock);
1523     return 0;
1524 }
1525 static int dmfe_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1526 {
1527     board_info_t *db = (board_info_t *)dev->priv;
1528     int rc;
1529 
1530     spin_lock_irq(&db->lock);
1531     rc = mii_ethtool_sset(&db->mii, cmd);
1532     spin_unlock_irq(&db->lock);
1533     return rc;
1534 }
1535 /*
1536 * Check the link state
1537 */
1538 static u32 dmfe_get_link(struct net_device *dev)
1539 {
1540     board_info_t *db = (board_info_t *)dev->priv;
1541     return mii_link_ok(&db->mii);
1542 }
1543 
1544 /*
1545 * Reset Auto-negitiation
1546 */
1547 static int dmfe_nway_reset(struct net_device *dev)
1548 {
1549     board_info_t *db = (board_info_t *)dev->priv;
1550     return mii_nway_restart(&db->mii);
1551 }
1552 /*
1553 * Get RX checksum offload state
1554 */
1555 static uint32_t dmfe_get_rx_csum(struct net_device *dev)
1556 {
1557     board_info_t *db = (board_info_t *)dev->priv;
1558     return db->rx_csum;
1559 }
1560 /*
1561 * Get TX checksum offload state
1562 */
1563 static uint32_t dmfe_get_tx_csum(struct net_device *dev)
1564 {
1565     return (dev->features & NETIF_F_HW_CSUM) != 0;
1566 }
1567 /* 
1568 * Enable/Disable RX checksum offload
1569 */
1570 static int dmfe_set_rx_csum(struct net_device *dev, uint32_t data)
1571 {
1572 #ifdef CHECKSUM
1573     board_info_t *db = (board_info_t *)dev->priv;
1574     db->rx_csum = data;
1575 
1576     if(netif_running(dev)) {
1577         dmfe_stop(dev);
1578         dmfe_open(dev);
1579     } else
1580         dmfe_init_dm9000(dev);
1581 #else
1582     printk(KERN_ERR "DM9:Don‘t support checksum\n");
1583 #endif
1584     return 0;
1585 }
1586 /* 
1587 * Enable/Disable TX checksum offload
1588 */
1589 static int dmfe_set_tx_csum(struct net_device *dev, uint32_t data)
1590 {
1591 #ifdef CHECKSUM
1592     if (data)
1593         dev->features |= NETIF_F_HW_CSUM;
1594     else
1595         dev->features &= ~NETIF_F_HW_CSUM;
1596 #else
1597     printk(KERN_ERR "DM9:Don‘t support checksum\n");
1598 #endif
1599 
1600     return 0;
1601 }
1602 //=========================================
1603 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,28)  /* for kernel 2.4.28 */
1604 static struct ethtool_ops dmfe_ethtool_ops = {
1605     .get_drvinfo        = dmfe_get_drvinfo,
1606     .get_settings        = dmfe_get_settings,
1607     .set_settings        = dmfe_set_settings,
1608     .get_link            = dmfe_get_link,
1609     .nway_reset        = dmfe_nway_reset,
1610     .get_rx_csum        = dmfe_get_rx_csum,
1611     .set_rx_csum        = dmfe_set_rx_csum,
1612     .get_tx_csum        = dmfe_get_tx_csum,
1613     .set_tx_csum        = dmfe_set_tx_csum,
1614 };
1615 #endif
1616 
1617 //#ifdef MODULE
1618 
1619 MODULE_LICENSE("GPL");
1620 MODULE_DESCRIPTION("Davicom DM9000/DM9010 ISA/uP Fast Ethernet Driver");
1621 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) 
1622 MODULE_PARM(mode, "i");
1623 MODULE_PARM(irq, "i");
1624 MODULE_PARM(iobase, "i");
1625 #else
1626 module_param(mode, int, 0);
1627 module_param(irq, int, 0);
1628 module_param(iobase, int, 0);
1629 #endif           
1630 MODULE_PARM_DESC(mode,"Media Speed, 0:10MHD, 1:10MFD, 4:100MHD, 5:100MFD");
1631 MODULE_PARM_DESC(irq,"EtherLink IRQ number");
1632 MODULE_PARM_DESC(iobase, "EtherLink I/O base address");
1633 
1634 /* Description: 
1635    when user used insmod to add module, system invoked init_module()
1636    to initilize and register.
1637 */
1638 int __init dm9000c_init(void)
1639 {
1640     volatile unsigned long *bwscon;   // 0x48000000
1641     volatile unsigned long *bankcon4; // 0x48000014
1642     unsigned long val;
1643     
1644     iobase = (int)ioremap(0x20000000, 1024); /* andy */
1645     irq = IRQ_EINT7;                    /* andy */
1646     
1647     /* 设置S3C2440的memory control */
1648     bwscon   = ioremap(0x48000000,4);
1649     bankcon4 = ioremap(0x48000014,4);
1650     
1651     /* DW4[17:16] :01-16bit
1652      * WS4[18]    :0-wait disable
1653      * ST4[19]    :0
1654      */
1655     val = *bwscon;
1656     val &= ~(0xf<<16);
1657     val |= (1<<16);
1658     *bwscon = val;
1659     
1660     /*
1661      *    Tacs[14:13] : 发出片选信号之前,多长时间内要先发出地址信号
1662      *                  DM9000C的片选信号和CMD信号可以同时发出
1663      *                  所以它设为0            
1664      *  Tcons[12:11]: 发出片选信号之后,多长时间才能发出读信号nOE
1665      *                   DM9000C的T1>=0ns,所以它设为0
1666      *    Tacc[10:8]  : 读写信号的脉冲长度,
1667      *                  DM9000C的T2>=20ns,所以它设为001,表示2个hclk周期,hclk=100Mhz,就是20ns
1668      *  Tcoh[7:6]   : 当读信号nOE变为高电平后,片选信号还要维持多长时间
1669                       DM9000C进行写操作时,nWE变为高电平之后,数据线上的数据还要最少维持3ns
1670                       DM9000C进行读操作时,nOE变为高电平之后,数据线上的数据在6ns之后会消失
1671      *                  我们取一个宽松值:让片选信号在nOE为高电平之后,再维持10ns
1672      *                  所以设为01
1673      *  Tcch[5:4]   : 当片选信号变为高电平之后,地址信号还要维持多长时间
1674      *                  DM9000C的片选信号和CMD信号可以同时出现,同时消失
1675      *                  所以设为0
1676      *  PMC{1:0]    : 00-正常模式
1677      */
1678      *bankcon4 = (1<<6) | (1<<8);
1679      
1680          
1681         
1682     iounmap(bwscon);
1683     iounmap(bankcon4);
1684     
1685     switch(mode) {
1686         case DM9KS_10MHD:
1687         case DM9KS_100MHD:
1688         case DM9KS_10MFD:
1689         case DM9KS_100MFD:
1690             media_mode = mode;
1691             break;
1692         default:
1693             media_mode = DM9KS_AUTO;
1694     }
1695     dmfe_dev = dmfe_probe();
1696     if(IS_ERR(dmfe_dev))
1697         return PTR_ERR(dmfe_dev);
1698     return 0;
1699 }
1700 /* Description: 
1701    when user used rmmod to delete module, system invoked clean_module()
1702    to  un-register DEVICE.
1703 */
1704 void __exit dm9000c_exit(void)
1705 {
1706     struct net_device *dev = dmfe_dev;
1707     DMFE_DBUG(0, "clean_module()", 0);
1708 
1709     unregister_netdev(dmfe_dev);
1710     release_region(dev->base_addr, 2);
1711 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1712     kfree(dev);
1713 #else
1714     free_netdev(dev);
1715 #endif
1716     
1717     iounmap((void *)iobase);
1718     DMFE_DBUG(0, "clean_module() exit", 0);
1719 }
1720 
1721 module_init(dm9000c_init);
1722 module_exit(dm9000c_exit);
1723 
1724 //#endif

 

下面分析主要修改的几个部分:

  • 1、将入口函数与出口函数改为模块,增加1721行与1722行,增加协议。去掉模块的宏定义1617、1724行
  • 2、看到dm9000c_init->dmfe_probe->dmfe_probe1中的416行,由于所有使用的dm9000c芯片版本号不满足此条件,所以直接去掉这一行注释掉。
  • 3、看到dmfe_open函数,这个函数在ifconfig后会被调用。里面的485行,更改中断方式为上升沿触发;看到dm9000c_init的1645行,更改中断引脚IRQ_EINT7
  • 4、更改网卡芯片数据地址,看到dm9000c_init的1644行,将实际地址0x20000000转换为虚拟地址后赋给iobase ,存储控制器的BANK4所控制的存储地址为0x20000000

  • 5、最后设置bwscon、bankcon4两个寄存器的值,他们可以控制BANK4的位宽、时序等信息。它的设置全部在dm9000c_init中。这里以读数据的Tacc时间参数做一下介绍,时序的参数是怎么设置的。直接贴图,其中左边为S3C2440的可以设置时间,右边是DM9000C需要设置的时间,可以看到Tacc时间对应的是DM9000C的T2参数,它主要至少10ns,那么我们设它为20ns,HCLK为100Mhz,那么设置20ns需要2个时钟周期,所以Tacc[10:8]=001b。

 技术图片技术图片

技术图片

 

 3、DM9000C的驱动测试

1、把dm9dev9000c.c放到内核的drivers/net目录下
2、修改drivers/net/Makefile

obj-$(CONFIG_DM9000) += dm9000.o
改为
obj-$(CONFIG_DM9000) += dm9dev9000c.o
3、make uImage
使用新内核启动
4、
使用NFS启动
或挂接块设备文件系统的话,那么需要再内核启动后
ifconfig eth0 192.168.1.17
ping 192.168.1.1

 

到这里,DM9000C的代码测试成功。

 

DM9000C网卡驱动程序编写与测试

标签:长度   出现   man   rdp   RoCE   mii-tool   ast   info   连接   

原文地址:https://www.cnblogs.com/andyfly/p/11259515.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!