编写的dm9000ep驱动(2.6.13)

来源:互联网 发布:淘宝怎么货到付款啊 编辑:程序博客网 时间:2024/06/02 02:35
the code behind is a some error ,the hwaddr must written to the relevantregesiters in the init function .this is important andessential.
最近手头刚好有个开发板,也还有点时间,就试着写了一下它上面的网卡驱动,当然也是参考了其现有的驱动再写的,程序如下:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include<linux/netdevice.h>
#include<linux/etherdevice.h>
#include <linux/skbuff.h>
#include <asm/irq.h>
#include <asm/io.h>

static void *bwscon;
static void *gpfcon;
static void *extint0;
static void *intmsk;
#defineBWSCON   (0x48000000)
#defineGPFCON   (0x56000050)
#defineEXTINT0   (0x56000088)
#defineINTMSK   (0x4A000008)

#defineBWSCON   (0x48000000)
#defineGPFCON   (0x56000050)
#defineEXTINT0   (0x56000088)
#defineINTMSK   (0x4A000008)

#defineDM9000_MIN_IO   0x20000300   //--
#defineDM9000_MAX_IO   0x20000370   //--

#defineDM9000_VID_L      0x28
#defineDM9000_VID_H      0x29
#defineDM9000_PID_L      0x2A
#defineDM9000_PID_H      0x2B

#defineDM9000_PKT_MAX   1536       //Receivedpacket max size
#defineDM9000_PKT_RDY   0x01       //Packetready to receive

#define DMFE_TIMER_WUT jiffies+(HZ*2)   //timer wakeup time : 2 second 
#define DMFE_TX_TIMEOUT(HZ*2)       //tx packettime-out time 1.5 s"

struct dm9000x{
    u32ioaddr;       // RegisterI/O base address
    u32iodata;       // Data I/Oaddress
    u16irq;       //IRQ
    u8iomode;       // 0:16bits1:word  2:byte
    u8opmode;
    u16 Preg0,Preg4;

    u16tx_pkt_cnt;
    u16sent_pkt_len, queue_pkt_len;
    u8device_wait_reset;   //device state
    u8nic_type;          // NICtype

    spinlock_tlock;
};

static struct net_device *xnet_dev = NULL;

int xnet_probe(struct net_device *dev);
static int xnet_open(struct net_device *dev);
static int xnet_stop(struct net_device *dev);
static int xnet_xmit(struct sk_buff *skb, struct net_device*dev);
static irqreturn_t xnet_interrupt(int irq, void *dev_id, structpt_regs *regs);
static void do_init_dm9000x(struct net_device *dev);
static void do_xnet_tx(void);
static void do_xnet_rx(void);

static void iowt(struct dm9000x *dm9x, int reg, u8value);
static u8 iord(struct dm9000x *dm9x, int reg);
static u16 phy_read(struct dm9000x *dm9x, int reg);
static void phy_write(struct dm9000x *dm9x, int reg, u16value);

int xnet_probe(struct net_device *dev)
{
    int i =0;
    u32id_val;
    u32iobase;
    structdm9000x *dm9x;
    unsignedchar mac_add[6] = {0x00, 0x13, 0xf6, 0x6c, 0x87, 0x89};

    bwscon =ioremap_nocache(BWSCON,0x0000004);   //总线位宽和等待状态控制器
    gpfcon =ioremap_nocache(GPFCON,0x0000004);   //Port F 控制寄存器
    extint0 =ioremap_nocache(EXTINT0,0x0000004);   //外部中断控制
    intmsk =ioremap_nocache(INTMSK,0x0000004);   //中断控制

   writel(readl(bwscon) | 0xc0000,bwscon);      //允许等待,使用UB/LB
   //设置GFP7为外部中断模式 EINT7
    writel((readl(gpfcon) & ~(0x3<< 14)) | (0x2<< 14), gpfcon);
    //设置EINT7 为falling edge triggered 
    writel((readl(extint0) & ~(0xf<< 28)) | (0x4<< 28),extint0); 
   //中断掩码设置1为屏蔽,这里设置开启EINT4~7
    writel((readl(intmsk))  & ~0x80,intmsk);    

    iobase =ioremap(DM9000_MIN_IO,0x400);      //进行地址隐射

   outb(DM9000_VID_L, iobase);
    id_val =inb(iobase + 4);
   outb(DM9000_VID_H, iobase);
    id_val |=inb(iobase + 4) << 8;
   outb(DM9000_PID_L, iobase);
    id_val |=inb(iobase + 4) << 16;
   outb(DM9000_PID_H, iobase);
    id_val |=inb(iobase + 4) << 24;
    
    if (id_val== 0x90000a46) {
      printk("id_val: %x, iobase: %p \n", id_val, (void*)iobase);
       
       dm9x = (void*)kmalloc(sizeof(struct dm9000x), GFP_KERNEL);
      //memset(dm9x,'0', sizeof(struct dm9000x));
       //dm9x =(void *) (kmalloc(sizeof (struct dm9000x), GFP_KERNEL));
       memset(dm9x,0, sizeof (struct dm9000x));
      dev->priv = dm9x;
       
      dm9x->ioaddr       =iobase;
      dm9x->iodata       = iobase +4;
      ether_setup(dev);
       
      dev->base_addr   = iobase;
      dev->irq       =IRQ_EINT7;
      dev->open       =&xnet_open;
      dev->stop       =&xnet_stop;
      dev->hard_start_xmit  =&xnet_xmit;
      SET_MODULE_OWNER(dev);
       for (i = 0;i < 6; i++)
         dev->dev_addr[i] = mac_add[i];
      request_region(iobase, 2,dev->name);    
      
    return0;
}

static void do_init_dm9000x(struct net_device *dev)
{
    u16phy_reg3;
    u16 phy_reg0= 0x1000;   //Auto-negotiation & non-duplux mode
    u16 phy_reg4= 0x01e1;   //Default non flow control
    structdm9000x *dm9x = (struct dm9000x*)dev->priv;

    //set theinternal PHY power-on, GPIOs normal, and wait2ms 
    iowt(dm9x,0x1F, 0);       //GPR(reg_1Fh)bit GPIO0=0 pre-activate PHY 
   udelay(20);          //wait 2msfor PHY power-on ready 
    
    //0x00network ctrl reg bit[0]:soft reset bit[1:2]:01 MAC interloopback
    iowt(dm9x,0x00,3);    
   udelay(20);

    //setGPIO0=1 then GPIO0=0 to turn off and on the internalPHY 
    iowt(dm9x,0x1F, 1);     //GPR(reg_1Fh) bit[0] GPIO0=1 turn-offPHY  
    iowt(dm9x,0x1F, 0);       //GPR(reg_1Fh) bit[0] GPIO0=0 activatePHY  
   udelay(1000);          //wait 4mslinking PHY (AUTO sense) if RX/TX 
   udelay(1000);
   udelay(1000);
   udelay(1000);
    
   dm9x->iomode = iord(dm9x, 0xFE)>> 6; //ISR bit[7:6] I/Omode
    
   //Full-Duplex Mode. Read only on Internal PHY mode. R/W on ExternalPHY mode 
    iowt(dm9x,0x00,0x80);    
    phy_reg3 =phy_read(dm9x, 3);
   dm9x->nic_type = 0;
   printk("IOmode: %x phy_reg3: %x \n", dm9x->iomode,phy_reg3);
    iowt(dm9x,0x00, 0x00);

   dm9x->opmode =0;    
   phy_write(dm9x, 0, phy_reg0);
   phy_write(dm9x, 4, 0x0400 | phy_reg4);
   dm9x->Preg0 = phy_reg0;
   dm9x->Preg4 = phy_reg4 + 0x0400;

    //Programoperating register 
    iowt(dm9x,0x00, 0x08);
    iowt(dm9x,0x02, 0x00);      
    iowt(dm9x,0x2f, 0x00);      
    iowt(dm9x,0x01,0x2c);   
    iowt(dm9x,0xfe,0x0f);   
    iowt(dm9x,0x08, 0x37);
    iowt(dm9x,0x09,0x38);   
    iowt(dm9x,0x0a,0x29);   
    
    // ActivateDM9000 
    iowt(dm9x,0x05, 0x30 |1);    //RXenable 
    iowt(dm9x,0xff, 0x83);   //Enable TX/RX interrupt mask
    
   dm9x->tx_pkt_cnt   = 0;
   dm9x->queue_pkt_len   = 0;
   dev->trans_start   = 0;
    
   netif_carrier_on(dev);
   spin_lock_init(&dm9x->lock);
    printk("doinit dm9000x xnte dev! \n");
}

static void do_xnet_tx(void)
{
    structnet_device *dev = xnet_dev;
    structdm9000x *dm9x = (struct dm9000x*)dev->priv;
    inttx_status = iord(dm9x,0x01);       //Got TXstatus
    
    if(tx_status & 0xc){          //One packetsent complete
      dm9x->tx_pkt_cnt--;
      dev->trans_start = 0;
    
       if(dm9x->tx_pkt_cnt > 0){       //Queuepacket check & send
          //Set TXlength to DM9000
          iowt(dm9x,0xfc, dm9x->queue_pkt_len &0xff);
          iowt(dm9x,0xfd, (dm9x->queue_pkt_len>> 8) &0xff);

          //Issue TXpolling command
          iowt(dm9x,0x2, 0x1);       //Clearedafter TX complete
         dev->trans_start =jiffies;   //saved the time stamp
       }
      netif_wake_queue(dev);
    }
   printk("xnet_tx_done the xnet dev! \n");
}

static void do_xnet_rx(void)
{
    structnet_device *dev = xnet_dev;
    structdm9000x *dm9x = (struct dm9000x*)dev->priv;
    structsk_buff *skb;
    u8 rxbyte,*rdptr;
    u16 i,RxStatus, RxLen, GoodPacket, tmplen;
    
    do{
       iord(dm9x,0xf0);       //Dummyread
       rxbyte =inb(dm9x->iodata);   //Got most updated data
       if (rxbyte== DM9000_PKT_RDY) { // packet ready to receive check
          GoodPacket =1;
          outb(0xf2,dm9x->ioaddr);
          RxStatus =RxLen = (u16) 0;
          RxStatus =inw(dm9x->iodata);
          outb(0xf2,dm9x->ioaddr);
          RxLen =inw(dm9x->iodata);

         
          if (RxLen< 0x40) {
             GoodPacket =0;
          } else if(RxLen > DM9000_PKT_MAX) {
            printk("<DM9000> RST: RXLen:%x(%x)\n", RxLen, RxStatus);
            dm9x->device_wait_reset = 1;
          }
          if (RxStatus& 0xbf00) GoodPacket = 0;
          if(!dm9x->device_wait_reset){
            if(GoodPacket && ((skb =dev_alloc_skb(RxLen + 4)) != NULL)){
               skb->dev = dev;
               skb_reserve(skb, 2);
                rdptr = (u8*) skb_put(skb, RxLen - 4);
                tmplen =(RxLen + 1) / 2;
                for (i = 0;i < tmplen; i++){
                   ((u16 *)rdptr)[i] = inw(dm9x->iodata);
                   //printk("%x",((u16 *) rdptr)[i]);
                }
                
               skb->protocol = eth_type_trans(skb, dev);
               netif_rx(skb);
             } else{      
                tmplen =(RxLen + 1) / 2;
                for (i = 0;i < tmplen; i++)
                  inw(dm9x->iodata);
            
                  
       } else if(rxbyte > DM9000_PKT_RDY) {
          // Statuscheck: this byte must be 0 or 1
          printk("RXSRAM 1st byte(x) != 01, must reset.\n", rxbyte);
          iowt(dm9x,0x05, 0x00);       // StopDevice
          iowt(dm9x,0xfe, 0x80);       // Stop INTrequest
         dm9x->device_wait_reset = 1;
         //dm9x->reset_rx_status++;
       }
    } while(rxbyte == DM9000_PKT_RDY &&!dm9x->device_wait_reset); 
   printk("xnet_packet_receive the xnet dev! %x\n",dm9x->ioaddr);
}

static irqreturn_t xnet_interrupt(int irq, void *dev_id, structpt_regs *regs)
{
    structnet_device *dev =dev_id;    
    structdm9000x *dm9x;
    intint_status;
    u8reg_save;

    dm9x =(struct dm9000x *)dev->priv;
   spin_lock_irq(&dm9x->lock);

    //Saveprevious register address 
    reg_save =inb(dm9x->ioaddr);
    //Disableall interrupt
    iowt(dm9x,0xff, 0x80);

    //Got DM9000interrupt status 
    int_status =iord(dm9x,0xfe);       //GotISR 
    iowt(dm9x,0xfe,int_status);       //Clear ISRstatus

    if(int_status & 0x02){    //TrnasmitInterrupt check
      do_xnet_tx();
    }
    if(int_status & 0x01){    //Receivedthe coming packet
      do_xnet_rx();
    }
    //Re-enableinterrupt mask
    iowt(dm9x,0xff, 0x83);

    //Restoreprevious register address
   outb(reg_save, dm9x->ioaddr);

   spin_unlock_irq(&dm9x->lock);

   printk("interrupt the xnet dev!  %x\n",dm9x->ioaddr);
    returnIRQ_HANDLED;
}

static int xnet_open(struct net_device *dev)
{
    //structdm9000x *dm9x = (struct dm9000x*)dev->priv;
    
   if(request_irq(dev->irq,&xnet_interrupt, SA_SHIRQ,dev->name, dev))
       return-EAGAIN;
       
   do_init_dm9000x(dev);

   netif_start_queue(dev);
   enable_irq(dev->irq);

    printk("openthe xnet dev! \n");
    return0;
}

static int xnet_stop(struct net_device *dev)
{
    structdm9000x *dm9x = (struct dm9000x*)dev->priv;

   netif_stop_queue(dev);
   free_irq(dev->irq, dev);

   
   phy_write(dm9x, 0x00,0x8000);   
    iowt(dm9x,0x1f,0x01);   
    iowt(dm9x,0xff,0x80);   
    iowt(dm9x,0x05,0x00);   

    printk("stopthe xnet dev! \n");
    return0;
}

static int xnet_xmit(struct sk_buff *skb, struct net_device*dev)
{
    structdm9000x *dm9x = (struct dm9000x*)dev->priv;
    char*data;
    int i,len;

    if(dm9x->tx_pkt_cnt > 1) return1;

   netif_stop_queue(dev);
    iowt(dm9x,0xff, 0x80);   //Disable all interrupt
    data = (char*)skb->data;
    outb(0xf8,dm9x->ioaddr);

    len =(skb->len + 1) / 2;
    for (i = 0;i < len; i++){
       outw(((u16*) data)[i], dm9x->iodata);
       //printk("%x",((u16 *) data)[i]);
    }

    // TXcontrol: First packet immediately send, second packetqueue 
    if(dm9x->tx_pkt_cnt ==0){          // FirstPacket
      dm9x->tx_pkt_cnt++;
       // Set TXlength to DM9000
       iowt(dm9x,0xfc, skb->len & 0xff);
       iowt(dm9x,0xfd, (skb->len >> 8)& 0xff);
       // Issue TXpolling command
       iowt(dm9x,0x2, 0x1);          //Clearedafter TX complete
       // saved thetime stamp
      dev->trans_start = jiffies;
    } else{                //Secondpacket
      dm9x->tx_pkt_cnt++;
      dm9x->queue_pkt_len =skb->len;
    }

   dev_kfree_skb(skb);

    if(dm9x->tx_pkt_cnt == 1)netif_wake_queue(dev);
    //Re-enableinterrupt
    iowt(dm9x,0xff, 0x83);

    printk("hardstart xmit the xnet dev!\n");    
    return0;
}

static void iowt(struct dm9000x *dm9x, int reg, u8 value)
{
    outb(reg,dm9x->ioaddr);
    outb(value,dm9x->iodata);
}

static u8 iord(struct dm9000x *dm9x, int reg)
{
    outb(reg,dm9x->ioaddr);
    returninb(dm9x->iodata);
}

//Read a word from phyxcer
static u16 phy_read(struct dm9000x *dm9x, int reg)
{
    //Fill thephyxcer register into REG_0C
    //0x0CEEPROM & PHY Address Register bit[7:6]:01 selectPHY
   //bit[5:0]:address of PHY or EEPROM
    iowt(dm9x,0xc, 0x40 | reg);
    iowt(dm9x,0xb, 0xc);   //Issue phyxcer read command
   udelay(100);          //Wait readcomplete
    iowt(dm9x,0xb, 0x0);   //Clear phyxcer read command

    //The readdata keeps on REG_0D(L) & REG_0E(H)
    return(iord(dm9x, 0xe) << 8) | iord(dm9x,0xd);
}

static void phy_write(struct dm9000x *dm9x, int reg, u16value)
{
    //Fill thephyxcer register into REG_0C
    iowt(dm9x,0xc, 0x40 | reg);

    //Fill thewritten data into REG_0D(L) & REG_0E(H)
    iowt(dm9x,0xd, (value & 0xff));
    iowt(dm9x,0xe, ((value >> 8) &0xff));

    iowt(dm9x,0xb, 0xa);   //Issue phyxcer write command 
   udelay(500);          //Wait writecomplete 
    iowt(dm9x,0xb, 0x0);   //Clear phyxcer write command
}

static int __init xnet_dev_init(void)
{
    int err =0;

    xnet_dev =alloc_etherdev(sizeof(struct net_device));
   xnet_dev->init = xnet_probe;
    
    err =dev_alloc_name(xnet_dev, "eth%d");
    if (err< 0)
       returnerr;
    err =register_netdev(xnet_dev);
    if (err< 0)
       returnerr;
    printk("initthe xnet dev! \n");

    return0;
}

static void __exit xnet_dev_exit(void)
{
   unregister_netdev(xnet_dev);
   kfree(xnet_dev->priv);
   memset(xnet_dev, 0, sizeof (*xnet_dev));
    printk("xnetdev exit!! \n");
}

module_init(xnet_dev_init);
module_exit(xnet_dev_exit);

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Helight.Xu");
0 0
原创粉丝点击