DM9000网卡驱动

 


#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/dm9000.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/slab.h>

#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/io.h>

#include "dm9000.h"
/**************************beelike add**************************/
#include <mach/regs-gpio.h>

static char net_mac_addr[]={0x00,0xe0,0x3d,0xf4,0xdd,0xf7};

static void *extint0,*intmsk,*eintmsk;

#define EINTMASK (0x560000a4)
#define EXTINT0 (0x56000088)
#define INTMSK (0x4a000008)
/******************************end add**************************/
#define DM9000_PHY 0x40

#define CARDNAME "dm9000"
#define DRV_VERSION "1.31"

static int watchdog = 5000;
module_param(watchdog,int,0400);
MODULE_PARM_DESC(watchdog,"transmit timeout in milliseconds");

enum dm9000_type{
 TYPE_DM9000E,
 TYPE_DM9000A,
 TYPE_DM9000B
};

typedef struct board_info{
 void __iomem *io_addr;
 void __iomem *io_data;
 u16 irq;

 u16 tx_pkt_cnt;
 u16 queue_pkt_len;
 u16 queue_start_addr;
 u16 queue_ip_summed;
 u16 dbug_cnt;
 u8 io_mode;
 u8 phy_addr;
 u8 imr_all;

 unsigned int flags;
 unsigned int in_suspend :1;
 unsigned int wake_supported :1;
 int debug_level;

 enum dm9000_type type;

 void (*inblk)(void __iomem *port,void *data,int length);
 void (*outblk)(void __iomem *port,void *data,int length);
 void (*dumpblk)(void __iomem *port,int length);

 struct device *dev;

 struct resource *addr_res;
 struct resource *data_res;
 struct resource *addr_req;
 struct resource *data_req;
 struct resource *irq_res;

 int irq_wake;

 struct mutex addr_lock;

 struct delayed_work phy_poll;
 struct net_device *ndev;

 spinlock_t lock;

 struct mii_if_info mii;
 u32 msg_enable;
 u32 wake_state;

 int ip_summed;
}board_info_t;

#define dm9000_dbg(db,lev,msg...)do{ \
 if((lev) < CONFIG_DM9000_DEBUGLEVEL && \
  (lev) < db->debug_level){ \
   dev_dbg(db->dev,msg); \
 } \
}while(0)

static inline board_info_t *to_dm9000_board(struct net_device *dev)
{
 return netdev_priv(dev);
}

static void
dm9000_reset(board_info_t * db)
{
 dev_dbg(db->dev,"resetting device\n");
 writeb(DM9000_NCR,db->io_addr);
 udelay(200);
 writeb(NCR_RST,db->io_data);
 udelay(200);
}

static u8
ior(board_info_t * db,int reg)
{
 writeb(reg,db->io_addr);
 return readb(db->io_data);
}

static void
iow(board_info_t *db,int reg,int value)
{
 writeb(reg,db->io_addr);
 writeb(value,db->io_data);
}

static void dm9000_outblk_8bit(void __iomem *reg,void *data,int count)
{
 writesb(reg,data,count);
}

static void dm9000_outblk_16bit(void __iomem *reg,void *data,int count)
{
 writesw(reg,data,(count+1) >> 1);
}

static void dm9000_outblk_32bit(void __iomem *reg,void *data,int count)
{
 writesl(reg,data,(count+3) >> 12);
}

static void dm9000_inblk_8bit(void __iomem *reg,void *data,int count)
{
 readsb(reg,data,count);
}

static void dm9000_inblk_16bit(void __iomem *reg,void *data,int count)
{
 readsw(reg,data,(count+1) >> 1);
}

static void dm9000_inblk_32bit(void __iomem *reg,void *data,int count)
{
 readsl(reg,data,(count+3) >> 2);
}

static void dm9000_dumpblk_8bit(void __iomem *reg,int count)
{
 int i;
 int tmp;

 for(i = 0; i < count; i++)
  tmp = readb(reg);
}

static void dm9000_dumpblk_16bit(void __iomem *reg,int count)
{
 int i;
 int tmp;

 count = (count + 1) >> 1;

 for(i = 0; i < count; i++)
  tmp = readw(reg);
}

static void dm9000_dumpblk_32bit(void __iomem *reg,int count)
{
 int i;
 int tmp;

 count = (count + 3) >> 2;

 for(i = 0;i < count; i++)
  tmp = readl(reg);
}

static void dm9000_set_io(struct board_info *db,int byte_width)
{
 switch(byte_width){
 case 1:
  db->dumpblk = dm9000_dumpblk_8bit;
  db->outblk = dm9000_outblk_8bit;
  db->inblk = dm9000_inblk_8bit;
  break;

 case 3:
  dev_dbg(db->dev,":3 byte IO,falling back to 16bit\n");

 case 2:
  db->dumpblk = dm9000_dumpblk_16bit;
  db->outblk = dm9000_outblk_16bit;
  db->inblk = dm9000_inblk_16bit;
  break;

 case 4:
 default:
  db->dumpblk = dm9000_dumpblk_32bit;
  db->outblk = dm9000_outblk_32bit;
  db->inblk = dm9000_inblk_32bit;
  break;
 }
}

static void dm9000_schedule_poll(board_info_t *db)
{
 if(db->type == TYPE_DM9000E)
  schedule_delayed_work(&db->phy_poll,HZ * 2);
}

static int dm9000_ioctl(struct net_device *dev,struct ifreq *req,int cmd)
{
 board_info_t *dm = to_dm9000_board(dev);

 if(!netif_running(dev))
  return -EINVAL;

 return generic_mii_ioctl(&dm->mii,if_mii(req),cmd,NULL);
}

static unsigned int
dm9000_read_locked(board_info_t *db,int reg)
{
 unsigned long flags;
 unsigned int ret;

 spin_lock_irqsave(&db->lock,flags);
 ret = ior(db,reg);
 spin_unlock_irqrestore(&db->lock,flags);

 return ret;
}

static int dm9000_wait_eeprom(board_info_t *db)
{
 unsigned int status;
 int timeout = 8;

 while(1){
  status = dm9000_read_locked(db,DM9000_EPCR);

  if((status & EPCR_ERRE) == 0)
   break;

  msleep(1);

  if(timeout-- < 0){
   dev_dbg(db->dev,"timeout waiting EEPROM\n");
   break;
  }
 }

 return 0;
}

static void
dm9000_read_eeprom(board_info_t *db,int offset,u8 *to)
{
 unsigned long flags;

 if(db->flags & DM9000_PLATF_NO_EEPROM){
  to[0] = 0xff;
  to[1] = 0xff;
  return;
 }

 mutex_lock(&db->addr_lock);

 spin_lock_irqsave(&db->lock,flags);

 iow(db,DM9000_EPAR,offset);
 iow(db,DM9000_EPCR,EPCR_ERPRR);

 spin_unlock_irqrestore(&db->lock,flags);

 dm9000_wait_eeprom(db);

 msleep(1);

 spin_lock_irqsave(&db->lock,flags);

 iow(db,DM9000_EPCR,0x0);

 to[0] = ior(db,DM9000_EPDRL);
 to[1] = ior(db,DM9000_EPDRH);

 spin_unlock_irqrestore(&db->lock,flags);

 mutex_unlock(&db->addr_lock);
}

static void
dm9000_write_eeprom(board_info_t *db,int offset,u8 *data)
{
 unsigned long flags;

 if(db->flags & DM9000_PLATF_NO_EEPROM)
  return;

 mutex_lock(&db->addr_lock);

 spin_lock_irqsave(&db->lock,flags);
 iow(db,DM9000_EPAR,offset);
 iow(db,DM9000_EPDRH,data[1]);
 iow(db,DM9000_EPDRL,data[0]);
 iow(db,DM9000_EPCR,EPCR_WEP | EPCR_ERPRW);
 spin_unlock_irqrestore(&db->lock,flags);

 dm9000_wait_eeprom(db);

 mdelay(1);

 spin_lock_irqsave(&db->lock,flags);
 iow(db,DM9000_EPCR,0);
 spin_unlock_irqrestore(&db->lock,flags);

 mutex_unlock(&db->addr_lock);
}

static void dm9000_get_drvinfo(struct net_device *dev,struct ethtool_drvinfo *info)
{
 board_info_t *dm = to_dm9000_board(dev);

 strcpy(info->driver,CARDNAME);
 strcpy(info->version,DRV_VERSION);
 strcpy(info->bus_info,to_platform_device(dm->dev)->name);
}

static u32 dm9000_get_msglevel(struct net_device *dev)
{
 board_info_t *dm = to_dm9000_board(dev);

 return dm->msg_enable;
}

static void dm9000_set_msglevel(struct net_device *dev,u32 value)
{
 board_info_t *dm = to_dm9000_board(dev);

 dm->msg_enable = value;
}

static int dm9000_get_settings(struct net_device *dev,struct ethtool_cmd *cmd)
{
 board_info_t *dm = to_dm9000_board(dev);

 mii_ethtool_gset(&dm->mii,cmd);
 return 0;
}

static int dm9000_set_settings(struct net_device *dev,struct ethtool_cmd *cmd)
{
 board_info_t *dm = to_dm9000_board(dev);

 return mii_ethtool_sset(&dm->mii,cmd);
}

static int dm9000_nway_reset(struct net_device *dev)
{
 board_info_t *dm = to_dm9000_board(dev);
 return mii_nway_restart(&dm->mii);
}
/*
static int dm9000_set_features(struct net_device *dev,u32 features)
{
 board_info_t *dm = to_dm9000_board(dev);
 u32 changed = dev->features ^features;
 unsigned long flags;

 if(!(changed & NETIF_F_RXCSUM))
  return 0;

 spin_lock_irqsave(&dm->lock,flags);
 iow(dm,DM9000_RCSR,(features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0);
 spin_unlock_irqrestore(&dm->lock,flags);

 return 0;
}*/

static u32 dm9000_get_link(struct net_device *dev)
{
 board_info_t *dm = to_dm9000_board(dev);
 u32 ret;

 if(dm->flags & DM9000_PLATF_EXT_PHY)
  ret = mii_link_ok(&dm->mii);
 else
  ret = dm9000_read_locked(dm,DM9000_NSR) & NSR_LINKST ? 1 : 0;
 return ret;
}

#define DM_EEPROM_MAGIC (0x444D394B)

static int dm9000_get_eeprom_len(struct net_device *dev)
{
 return 128;
}

static int dm9000_get_eeprom(struct net_device *dev, struct ethtool_eeprom *ee, u8 *data)
{
 board_info_t *dm = to_dm9000_board(dev);
 int offset = ee->offset;
 int len = ee->len;
 int i;

 if((len & 1) != 0 || (offset & 1) != 0)
  return -EINVAL;

 if(dm->flags & DM9000_PLATF_NO_EEPROM)
  return -EINVAL;

 ee->magic = DM_EEPROM_MAGIC;

 for(i = 0; i < len; i+= 2)
  dm9000_read_eeprom(dm,(offset + i)/2,data + i);

 return 0;
}

static int dm9000_set_eeprom(struct net_device *dev,struct ethtool_eeprom *ee,u8 *data)
{
 board_info_t *dm = to_dm9000_board(dev);
 int offset = ee->offset;
 int len = ee->len;
 int done;

 if(dm->flags & DM9000_PLATF_NO_EEPROM)
  return -ENOENT;

 if(ee->magic != DM_EEPROM_MAGIC)
  return -EINVAL;

 while(len > 0){
  if(len & 1 || offset &1){
   int which = offset &1;
   u8 tmp[2];

   dm9000_read_eeprom(dm,offset / 2,tmp);
   tmp[which] = *data;
   dm9000_write_eeprom(dm,offset / 2,tmp);

   done = 1;
  }else{
   dm9000_write_eeprom(dm,offset / 2,data);
   done = 2;
  }

  data += done;
  offset += done;
  len -= done;
 }
 return 0;
}
/*
static void dm9000_get_wol(struct net_device *dev,struct ethtool_wolinfo *w)
{
 board_info_t *dm = to_dm9000_board(dev);

 memset(w,0,sizeof(struct ethtool_wolinfo));

 w->supported = dm->wake_supported ? WAKE_MAGIC :0;
 w->wolopts = dm->wake_state;
}

static int dm9000_set_wol(struct net_device *dev,struct ethtool_wolinfo *w)
{
 board_info_t *dm = to_dm9000_board(dev);
 unsigned long flags;
 u32 opts = w->wolopts;
 u32 wcr = 0;

 if(!dm->wake_supported)
  return -EOPNOTSUPP;

 if(opts & ~WAKE_MAGIC)
  wcr |= WCR_MAGICEN;

 mutex_lock(&dm->addr_lock);

 spin_lock_irqsave(&dm->lock,flags);
 iow(dm,DM9000_WCR,wcr);
 spin_unlock_irqrestore(&dm->lock,flags);

 mutex_unlock(&dm->addr_lock);

 if(dm->wake_state != opts){
  if(!dm->wake_state)
   irq_set_irq_wake(dm->irq_wake,1);
  else if(dm->wake_state & !opts)
   irq_set_irq_wake(dm->irq_wake,0);
 }

 dm->wake_state = opts;
 return 0;
}*/

static const struct ethtool_ops dm9000_ethtool_ops = {
 .get_drvinfo = dm9000_get_drvinfo,
 .get_settings = dm9000_get_settings,
 .set_settings = dm9000_set_settings,
 .get_msglevel = dm9000_get_msglevel,
 .set_msglevel = dm9000_set_msglevel,
 .nway_reset = dm9000_nway_reset,
 .get_link = dm9000_get_link,
// .get_wol = dm9000_get_wol,
// .set_wol = dm9000_set_wol,
 .get_eeprom_len = dm9000_get_eeprom_len,
 .get_eeprom = dm9000_get_eeprom,
 .set_eeprom = dm9000_set_eeprom,
};

static void dm9000_show_carrier(board_info_t *db,unsigned carrier,unsigned nsr)
{
 struct net_device *ndev = db->ndev;
 unsigned ncr = dm9000_read_locked(db,DM9000_NCR);

 if(carrier)
  dev_info(db->dev,"%s:link up,%dMbps,%s-duplex,no LPA\n",
   ndev->name,(nsr & NSR_SPEED) ? 10 : 100,
   (ncr & NCR_FDX) ? "full" : "half");
 else
  dev_info(db->dev,"%s:link down\n",ndev->name);
}

static void
dm9000_poll_work(struct work_struct *w)
{
 struct delayed_work *dw = container_of(w, struct delayed_work, work);
 board_info_t *db = container_of(dw,board_info_t,phy_poll);
 struct net_device *ndev = db->ndev;

 if(db->flags &DM9000_PLATF_SIMPLE_PHY &&
  !(db->flags & DM9000_PLATF_EXT_PHY)){
   unsigned nsr = dm9000_read_locked(db,DM9000_NSR);
   unsigned old_carrier = netif_carrier_ok(ndev) ? 1 : 0;
   unsigned new_carrier;

   new_carrier = (nsr & NSR_LINKST) ? 1 : 0;

   if(old_carrier != new_carrier){
    if(netif_msg_link(db))
     dm9000_show_carrier(db,new_carrier,nsr);

    if(!new_carrier)
     netif_carrier_off(ndev);
    else
     netif_carrier_on(ndev);
   }
 }else
  mii_check_media(&db->mii,netif_msg_link(db),0);

 if(netif_running(ndev))
  dm9000_schedule_poll(db);
}

static void
dm9000_release_board(struct platform_device *pdev,struct board_info *db)
{
 iounmap(db->io_addr);
 iounmap(db->io_data);

 release_resource(db->data_req);
 kfree(db->data_req);

 release_resource(db->addr_req);
 kfree(db->addr_req);
}

static unsigned char dm9000_type_to_char(enum dm9000_type type)
{
 switch(type){
 case TYPE_DM9000E:return 'e';
 case TYPE_DM9000A:return 'a';
 case TYPE_DM9000B:return 'b';
 }

 return '?';
}
/*
static void
dm9000_hash_table_unlocked(struct net_device *dev)
{
 board_info_t *db = netdev_priv(dev);
 struct netdev_hw_addr *ha;
 int i,oft;
 u32 hash_val;
 u16 hash_table[4];
 u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN;

 dm9000_dbg(db,1,"entering %s\n",__func__);

 for(i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
  iow(db,oft,dev->dev_addr[i]);

 for(i = 0; i < 4; i++)
  hash_table[i] = 0x0;

 hash_table[3] = 0x8000;

 if(dev->flags & IFF_PROMISC)
  rcr |= RCR_PRMSC;

 if(dev->flags & IFF_ALLMULTI)
  rcr |= RCR_ALL;

 netdev_for_each_mc_addr(ha,dev){
  hash_val = ether_crc_le(6,ha->addr) & 0x3f;
  hash_table[hash_val / 16] |= (u16)1 << (hash_val % 16);
 }

 for(i = 0, oft = DM9000_MAR; i < 4; i++){
  iow(db,oft++,hash_table[i]);
  iow(db,oft++,hash_table[i] >> 8);
 }

 iow(db,DM9000_RCR,rcr);
}*/

static void
dm9000_hash_table(struct net_device *dev)
{
 board_info_t *db = netdev_priv(dev);
 struct dev_mc_list *mcptr = dev->mc_list;
 int mc_cnt = dev->mc_count;
 int i,oft;
 u32 hash_val;
 u16 hash_table[4];
 u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN;
 unsigned long flags;

 dm9000_dbg(db,1,"entering %s\n",__func__);

 spin_lock_irqsave(&db->lock,flags);

 for(i = 0,oft = DM9000_PAR; i < 6; i++,oft++)
  iow(db, oft, dev->dev_addr[i]);

 for (i = 0; i < 4; i++)
  hash_table[i] = 0x0;

 hash_table[3] = 0x8000;

 if (dev->flags & IFF_PROMISC)
  rcr |= RCR_PRMSC;

 if (dev->flags & IFF_ALLMULTI)
  rcr |= RCR_ALL;

 for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
  hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f;
  hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
 }

 for (i = 0, oft = DM9000_MAR; i < 4; i++) {
  iow(db, oft++, hash_table[i]);
  iow(db, oft++, hash_table[i] >> 8);
 }

 iow(db, DM9000_RCR, rcr);
 spin_unlock_irqrestore(&db->lock, flags);
}

static void
dm9000_init_dm9000(struct net_device *dev)
{
 board_info_t *db = netdev_priv(dev);
 unsigned int imr;
// unsigned int ncr;

 dm9000_dbg(db,1,"entering %s\n",__func__);

 db->io_mode = ior(db,DM9000_ISR) >> 6;

 iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
 iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */
 iow(db, DM9000_GPR, 0); /* Enable PHY */

 if (db->flags & DM9000_PLATF_EXT_PHY)
  iow(db, DM9000_NCR, NCR_EXT_PHY);

 iow(db,DM9000_TCR,0);
 iow(db,DM9000_BPTR,0x3f);
 iow(db,DM9000_FCR,0xff);
 iow(db,DM9000_SMCR,0);

 iow(db,DM9000_NSR,NSR_WAKEST | NSR_TX2END | NSR_TX1END);
 iow(db,DM9000_ISR,ISR_CLR_STATUS);

 dm9000_hash_table(dev);

 imr = IMR_PAR | IMR_PTM | IMR_PRM;
 if(db->type != TYPE_DM9000E)
  imr |= IMR_LNKCHNG;

 db->imr_all = imr;

 iow(db,DM9000_IMR,imr);

 db->tx_pkt_cnt = 0;
 db->queue_pkt_len = 0;
 dev->trans_start = 0;
}

static void dm9000_timeout(struct net_device *dev)
{
 board_info_t *db = netdev_priv(dev);
 u8 reg_save;
 unsigned long flags;

 spin_lock_irqsave(&db->lock,flags);
 reg_save = readb(db->io_addr);

 netif_stop_queue(dev);
 dm9000_reset(db);
 dm9000_init_dm9000(dev);
 dev->trans_start = jiffies;
 netif_wake_queue(dev);

 writeb(reg_save,db->io_addr);
 spin_unlock_irqrestore(&db->lock,flags);
}
/*
static void dm9000_send_packet(struct net_device *dev,int ip_summed,u16 pkt_len)
{
 board_info_t *dm = to_dm9000_board(dev);

 if(dm->ip_summed != ip_summed){
  if(ip_summed == CHECKSUM_NONE)
   iow(dm,DM9000_TCCR,0);
  else
   iow(dm,DM9000_TCCR,TCCR_IP | TCCR_UDP |TCCR_TCP);
  dm->ip_summed = ip_summed;
 }


 iow(dm,DM9000_TXPLL,pkt_len);
 iow(dm,DM9000_TXPLH,pkt_len >> 8);

 iow(dm,DM9000_TCR,TCR_TXREQ);
}*/

static int
dm9000_start_xmit(struct sk_buff *skb,struct net_device *dev)
{
 unsigned long flags;
 board_info_t *db = netdev_priv(dev);

 dm9000_dbg(db,3,"%s:\n",__func__);

 if(db->tx_pkt_cnt > 1)
  return 1;

 spin_lock_irqsave(&db->lock,flags);

 writeb(DM9000_MWCMD,db->io_addr);

 (db->outblk)(db->io_data,skb->data,skb->len);
 dev->stats.tx_bytes += skb->len;

 db->tx_pkt_cnt++;
 if(db->tx_pkt_cnt == 1){
  /* Set TX length to DM9000 */
  iow(db, DM9000_TXPLL, skb->len);
  iow(db, DM9000_TXPLH, skb->len >> 8);

  /* Issue TX polling command */
  iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */

  dev->trans_start = jiffies; /* save the time stamp */
 }else{
  db->queue_pkt_len = skb->len;
//  db->queue_ip_summed = skb->ip_summed;
  netif_stop_queue(dev);
 }

 spin_unlock_irqrestore(&db->lock, flags);

 dev_kfree_skb(skb);

 return 0;
}

static void dm9000_tx_done(struct net_device *dev,board_info_t *db)
{
 int tx_status = ior(db,DM9000_NSR);

 if(tx_status & (NSR_TX2END | NSR_TX1END)){
  db->tx_pkt_cnt--;
  dev->stats.tx_packets++;

  if(netif_msg_tx_done(db))
   dev_dbg(db->dev,"tx done,NSR %02x\n",tx_status);

  if(db->tx_pkt_cnt > 0){
   iow(db, DM9000_TXPLL, db->queue_pkt_len);
   iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8);
   iow(db, DM9000_TCR, TCR_TXREQ);
   dev->trans_start = jiffies;
  }
  netif_wake_queue(dev);
 }
}

struct dm9000_rxhdr{
 u8 RxPktReady;
 u8 RxStatus;
 __le16 RxLen;
}__packed;

static void
dm9000_rx(struct net_device *dev)
{
 board_info_t *db = netdev_priv(dev);
 struct dm9000_rxhdr rxhdr;
 struct sk_buff *skb;
 u8 rxbyte,*rdptr;
 bool GoodPacket;
 int RxLen;

 do{
  ior(db,DM9000_MRCMDX);

  rxbyte = readb(db->io_data);

  if(rxbyte & DM9000_PKT_RDY){
   dev_warn(db->dev,"status check fail: %d\n",rxbyte);
   iow(db,DM9000_RCR,0x00);
   iow(db,DM9000_ISR,IMR_PAR);
   return;
  }

  if(!(rxbyte & DM9000_PKT_RDY))
   return;

  GoodPacket = true;
  writeb(DM9000_MRCMD,db->io_addr);

  (db->inblk)(db->io_data,&rxhdr,sizeof(rxhdr));

  RxLen = le16_to_cpu(rxhdr.RxLen);

  if(netif_msg_rx_status(db))
   dev_dbg(db->dev,"RX: status %02x,length %04x\n",
    rxhdr.RxStatus,RxLen);

  if(RxLen < 0x40){
   GoodPacket = false;
   if(netif_msg_rx_err(db))
    dev_dbg(db->dev,"RX:Bad Packet(runt)\n");
  }

  if(RxLen > DM9000_PKT_MAX){
   dev_dbg(db->dev,"RST: RX Len:%x\n",RxLen);
  }

  if(rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
     RSR_PLE | RSR_RWTO |
     RSR_LCS | RSR_RF)){
   GoodPacket = false;
   if(rxhdr.RxStatus & RSR_FOE){
    if(netif_msg_rx_err(db))
     dev_dbg(db->dev,"fifo error\n");
    dev->stats.rx_fifo_errors++;
   }
   if(rxhdr.RxStatus & RSR_CE){
    if(netif_msg_rx_err(db))
     dev_dbg(db->dev,"crc error\n");
    dev->stats.rx_crc_errors++;
   }
   if(rxhdr.RxStatus & RSR_RF){
    if(netif_msg_rx_err(db))
     dev_dbg(db->dev,"length error\n");
    dev->stats.rx_length_errors++;
   }
  }

  if(GoodPacket &&
   ((skb = dev_alloc_skb(RxLen + 4)) != NULL)){
    skb_reserve(skb,2);
    rdptr = (u8 *)skb_put(skb,RxLen - 4);

    (db->inblk)(db->io_data,rdptr,RxLen);
    dev->stats.rx_bytes += RxLen;

    skb->protocol = eth_type_trans(skb,dev);
    netif_rx(skb);
    dev->stats.rx_packets++;
  }else
   (db->dumpblk)(db->io_data,RxLen);
 }
 while(rxbyte & DM9000_PKT_RDY);
}

static irqreturn_t dm9000_interrupt(int irq,void *dev_id)
{
 struct net_device *dev = dev_id;
 board_info_t *db = netdev_priv(dev);
 int int_status;
 unsigned long flags;
 u8 reg_save;

 dm9000_dbg(db,3,"entering %s\n",__func__);

 spin_lock_irqsave(&db->lock,flags);

 reg_save = readb(db->io_addr);

 iow(db,DM9000_IMR,IMR_PAR);

 int_status = ior(db,DM9000_ISR);
 iow(db,DM9000_ISR,int_status);

 if(netif_msg_intr(db))
  dev_dbg(db->dev,"interrupt status %02x\n",int_status);

 if(int_status & ISR_PRS)
  dm9000_rx(dev);

 if(int_status & ISR_PTS)
  dm9000_tx_done(dev,db);

 if(db->type != TYPE_DM9000E){
  if(int_status & ISR_LNKCHNG){
   schedule_delayed_work(&db->phy_poll,1);
  }
 }

 iow(db,DM9000_IMR,db->imr_all);

 spin_unlock_irqrestore(&db->lock,flags);

 return IRQ_HANDLED;
}

#ifdef CONFIG_NET_POLL_CONTROLLER
static void dm9000_poll_controller(struct net_device *dev)
{
 disable_irq(dev->irq);
 dm9000_interrupt(dev->irq,dev);
 enable_irq(dev->irq);
}
#endif

static int
dm9000_open(struct net_device *dev)
{
 board_info_t *db = netdev_priv(dev);
 unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;

 if(netif_msg_ifup(db))
  dev_dbg(db->dev,"enabling %s\n",dev->name);

 if(irqflags == IRQF_TRIGGER_NONE)
  dev_warn(db->dev,"WARNING:no IRQ resource flags set.\n");

 irqflags |= IRQF_SHARED;

 if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))
  return -EAGAIN;

 dm9000_reset(db);
 dm9000_init_dm9000(dev);

 db->dbug_cnt = 0;
 mii_check_media(&db->mii,netif_msg_link(db),1);
 netif_start_queue(dev);

 dm9000_schedule_poll(db);

 return 0;
}

static void dm9000_msleep(board_info_t *db, unsigned int ms)
{
 if(db->in_suspend)
  mdelay(ms);
 else
  msleep(ms);
}

static int
dm9000_phy_read(struct net_device *dev,int phy_reg_unused,int reg)
{
 board_info_t *db = netdev_priv(dev);
 unsigned long flags;
 unsigned int reg_save;
 int ret;

 mutex_lock(&db->addr_lock);

 spin_lock_irqsave(&db->lock,flags);

 reg_save = readb(db->io_addr);

 iow(db,DM9000_EPAR,DM9000_PHY | reg);

 iow(db,DM9000_EPCR,EPCR_ERPRR | EPCR_EPOS);

 writeb(reg_save,db->io_addr);
 spin_unlock_irqrestore(&db->lock,flags);

 dm9000_msleep(db,1);

 spin_lock_irqsave(&db->lock,flags);
 reg_save = readb(db->io_addr);

 iow(db,DM9000_EPCR,0x0);

 ret = (ior(db,DM9000_EPDRH) << 8) | ior(db,DM9000_EPDRL);

 writeb(reg_save,db->io_addr);
 spin_unlock_irqrestore(&db->lock,flags);

 mutex_unlock(&db->addr_lock);

 dm9000_dbg(db,5,"phy_read[%02x]->%04x\n",reg,ret);
 return ret;
}

static void
dm9000_phy_write(struct net_device *dev,int phyaddr_unused,int reg,int value)
{
 board_info_t *db = netdev_priv(dev);
 unsigned long flags;
 unsigned long reg_save;

 dm9000_dbg(db,5,"phy_write[%02x] = %-4x\n",reg,value);
 mutex_lock(&db->addr_lock);

 spin_lock_irqsave(&db->lock,flags);

 reg_save = readb(db->io_addr);

 iow(db,DM9000_EPAR,DM9000_PHY | reg);

 iow(db,DM9000_EPDRL,value);
 iow(db,DM9000_EPDRH,value >> 8);

 iow(db,DM9000_EPCR,EPCR_EPOS | EPCR_ERPRW);

 writeb(reg_save,db->io_addr);
 spin_unlock_irqrestore(&db->lock,flags);

 dm9000_msleep(db,1);

 spin_lock_irqsave(&db->lock,flags);
 reg_save = readb(db->io_addr);

 iow(db,DM9000_EPCR,0x0);

 writeb(reg_save,db->io_addr);

 spin_unlock_irqrestore(&db->lock,flags);
 mutex_unlock(&db->addr_lock);
}

static void
dm9000_shutdown(struct net_device *dev)
{
 board_info_t *db = netdev_priv(dev);
 dm9000_phy_write(dev,0,MII_BMCR,BMCR_RESET);
 iow(db,DM9000_GPR,0x01);
 iow(db,DM9000_IMR,IMR_PAR);
 iow(db,DM9000_RCR,0x00);
}

static int
dm9000_stop(struct net_device * ndev)
{
 board_info_t *db = netdev_priv(ndev);

 if(netif_msg_ifdown(db))
  dev_dbg(db->dev,"shutting down %s\n",ndev->name);

 cancel_delayed_work_sync(&db->phy_poll);

 netif_stop_queue(ndev);
 netif_carrier_off(ndev);

 free_irq(ndev->irq,ndev);
 dm9000_shutdown(ndev);

 return 0;
}

#define res_size(_r) (((_r)->end - (_r)->start) + 1)
static int __devinit
dm9000_probe(struct platform_device *pdev)
{
 struct dm9000_plat_data *pdata = pdev->dev.platform_data;
 struct board_info *db;
 struct net_device *ndev;
 const unsigned char *mac_src;
 int ret = 0;
 int iosize;
 int i;
 u32 id_val;

 ndev = alloc_etherdev(sizeof(struct board_info));
 if(!ndev){
  dev_err(&pdev->dev,"could not allocate device.\n");
  return -ENOMEM;
 }
 
 SET_NETDEV_DEV(ndev,&pdev->dev);
 
 dev_dbg(&pdev->dev,"dm9000_probe()\n");
 
 db = netdev_priv(ndev);
 memset(db, 0, sizeof(*db));
 
 db->dev = &pdev->dev;
 db->ndev = ndev;
 
 spin_lock_init(&db->lock);
 mutex_init(&db->addr_lock);
 
 INIT_DELAYED_WORK(&db->phy_poll,dm9000_poll_work);

 db->addr_res = platform_get_resource(pdev,IORESOURCE_MEM,0);
 db->data_res = platform_get_resource(pdev,IORESOURCE_MEM,1);
 db->irq_res = platform_get_resource(pdev,IORESOURCE_IRQ,0);

 if(db->addr_res == NULL || db->data_res == NULL || db->irq_res == NULL){
  dev_err(db->dev,"insufficient resources\n");
  ret = -ENOENT;
  goto out;
 }

 iosize = res_size(db->addr_res);
 db->addr_req = request_mem_region(db->addr_res->start, iosize,
       pdev->name);

 if (db->addr_req == NULL) {
  dev_err(db->dev, "cannot claim address reg area\n");
  ret = -EIO;
  goto out;
 }

 db->io_addr = ioremap(db->addr_res->start, iosize);

 if (db->io_addr == NULL) {
  dev_err(db->dev, "failed to ioremap address reg\n");
  ret = -EINVAL;
  goto out;
 }

 iosize = resource_size(db->addr_res);
 db->addr_req = request_mem_region(db->addr_res->start,iosize,pdev->name);

 if(db->addr_req == NULL){
  dev_err(db->dev,"cannot claim address reg area\n");
  ret = -EIO;
  goto out;
 }

 db->io_data = ioremap(db->data_res->start,iosize);

 if(db->io_data == NULL){
  dev_err(db->dev,"failed to ioremap data reg\n");
  ret = -EINVAL;
  goto out;
 }

 ndev->base_addr = (unsigned long)db->io_addr;
 ndev->irq = db->irq_res->start;
 ndev->irq = db->irq_res->start;

 dm9000_set_io(db,iosize);

 if(pdata != NULL){
  if(pdata->flags & DM9000_PLATF_8BITONLY)
   dm9000_set_io(db,1);

  if(pdata->flags & DM9000_PLATF_16BITONLY)
   dm9000_set_io(db,2);

  if(pdata->flags & DM9000_PLATF_32BITONLY)
   dm9000_set_io(db,4);

  if(pdata->inblk != NULL)
   db->inblk = pdata->inblk;

  if(pdata->outblk != NULL)
   db->outblk = pdata->outblk;

  if(pdata->dumpblk != NULL)
   db->dumpblk = pdata->dumpblk;

  db->flags = pdata->flags;
 }

#ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
 db->flags |= DM9000_PLATF_SIMPLE_PHY;
#endif

 dm9000_reset(db);

 for(i = 0; i < 8; i++){
  id_val = ior(db,DM9000_VIDL);
  id_val |=(u32)ior(db,DM9000_VIDH) << 8;
  id_val |=(u32)ior(db,DM9000_PIDL) << 16;
  id_val |=(u32)ior(db,DM9000_PIDH) << 24;

  if(id_val == DM9000_ID)
   break;
  dev_err(db->dev,"read wrong id 0x%08x\n",id_val);
 }

 if(id_val != DM9000_ID){
  dev_err(db->dev,"wrong id:0x%08x\n",id_val);
  ret = -ENODEV;
  goto out;
 }

 id_val = ior(db,DM9000_CHIPR);
 dev_dbg(db->dev,"dm9000 revision 0x%02x\n",id_val);

 switch(id_val){
 case CHIPR_DM9000A:
  db->type = TYPE_DM9000A;
  break;
 case CHIPR_DM9000B:
  db->type = TYPE_DM9000B;
  break;
 default:
  dev_dbg(db->dev,"ID %02x => defaulting to DM9000E\n",id_val);
  db->type = TYPE_DM9000E;
 }

 ether_setup(ndev);

 ndev->open   = &dm9000_open;
 ndev->hard_start_xmit    = &dm9000_start_xmit;
 ndev->tx_timeout         = &dm9000_timeout;
 ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
 ndev->stop   = &dm9000_stop;
 ndev->set_multicast_list = &dm9000_hash_table;
 ndev->ethtool_ops  = &dm9000_ethtool_ops;
 ndev->do_ioctl   = &dm9000_ioctl;

#ifdef CONFIG_NET_POLL_CONTROLLER
 ndev->poll_controller  = &dm9000_poll_controller;
#endif

 db->msg_enable = NETIF_MSG_LINK;
 db->mii.phy_id_mask = 0x1f;
 db->mii.reg_num_mask = 0x1f;
 db->mii.force_media = 0;
 db->mii.full_duplex = 0;
 db->mii.dev = ndev;
 db->mii.mdio_read = dm9000_phy_read;
 db->mii.mdio_write = dm9000_phy_write;

 mac_src = "eeprom";

 for(i = 0; i < 6; i += 2)
  dm9000_read_eeprom(db,i/2,ndev->dev_addr+i);

 if(!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL){
  mac_src = "platfrom data";
  memcpy(ndev->dev_addr,pdata->dev_addr,6);
 }

 if(!is_valid_ether_addr(ndev->dev_addr)){
  mac_src = "chip";
  for(i = 0; i <6; i++)
   ndev->dev_addr[i] = ior(db,i+DM9000_PAR);
 }
  mac_src = "dxl";
/***********beelike add ********/

for(i=0;i<6;i++){

ndev->dev_addr[i]=net_mac_addr[i];

}

    extint0=ioremap_nocache(EXTINT0,4);// 

    intmsk=ioremap_nocache(INTMSK,4);   

   eintmsk=ioremap_nocache(EINTMASK ,4);

    s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_EINT7);  

    writel(readl(extint0)&0x8fffffff,extint0); //eint7 low level 

    writel(readl(intmsk)&(~(1<<4)),intmsk); //     

   writel(readl(extint0)&(~(1<<7)),extint0);

iounmap(intmsk);

iounmap(extint0);

iounmap(eintmsk);

/******************end *********/

 if(!is_valid_ether_addr(ndev->dev_addr))
  dev_warn(db->dev,"%s:Invalid ethernet MAC address. Please"
   "set using ifconfig\n",ndev->name);

 platform_set_drvdata(pdev,ndev);
 ret = register_netdev(ndev);

 if(ret == 0)
  printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC:%pM (%s)\n",
   ndev->name,dm9000_type_to_char(db->type),
   db->io_addr,db->io_data,ndev->irq,
   ndev->dev_addr,mac_src);
 return 0;

out:
 dev_err(db->dev,"not found (%d).\n",ret);

 dm9000_release_board(pdev,db);
 free_netdev(ndev);

 return ret;
}

static int
dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
{
 struct net_device *ndev = platform_get_drvdata(dev);
 board_info_t *db;

 if (ndev) {
  db = netdev_priv(ndev);
  db->in_suspend = 1;

  if (netif_running(ndev)) {
   netif_device_detach(ndev);
   dm9000_shutdown(ndev);
  }
 }
 return 0;
}

static int
dm9000_drv_resume(struct platform_device *dev)
{
 struct net_device *ndev = platform_get_drvdata(dev);
 board_info_t *db = netdev_priv(ndev);

 if(ndev){
  if(netif_running(ndev)){
   dm9000_reset(db);
   dm9000_init_dm9000(ndev);
   netif_device_attach(ndev);
  }
  db->in_suspend = 0;
 }
 return 0;
}

static int __devexit
dm9000_drv_remove(struct platform_device *pdev)
{
 struct net_device *ndev = platform_get_drvdata(pdev);
 platform_set_drvdata(pdev,NULL);
 unregister_netdev(ndev);
 dm9000_release_board(pdev,netdev_priv(ndev));
 free_netdev(ndev);
 dev_dbg(&pdev->dev,"released and freed device\n");
 return 0;
}

static struct platform_driver dm9000_driver = {
 .driver = {
  .name    = "dm9000",
  .owner  = THIS_MODULE,
 },
 .probe   = dm9000_probe,
 .remove = __devexit_p(dm9000_drv_remove),
 .suspend = dm9000_drv_suspend,
 .resume  = dm9000_drv_resume,
};

static int __init
dm9000_init(void)
{
 printk(KERN_INFO "%s Ethernet Driver,V%s\n", CARDNAME,DRV_VERSION);
 return platform_driver_register(&dm9000_driver);
}

static void __exit
dm9000_cleanup(void)
{
 platform_driver_unregister(&dm9000_driver);
}

module_init(dm9000_init);
module_exit(dm9000_cleanup);

MODULE_AUTHOR("Zhang Chunyang");
MODULE_DESCRIPTION("Davicom DM9000 network driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dm9000");

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值