#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>
#include <linux/interrupt.h>
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <linux/crc32.h>
static volatile unsigned long *bwscon;
static volatile unsigned long *bankcon4;
#defineBWSCON (0x48000000)
#define BANKCON4 (0x48000014)
#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_NCR 0x00
#defineDM9000_PKT_MAX 1536 //Received packet max size
#defineDM9000_PKT_RDY 0x01 //Packet ready to receive
#define DMFE_TIMER_WUT jiffies+(HZ*2) //timer wakeup time : 2 second
#define DMFE_TX_TIMEOUT(HZ*2) //tx packet time-out time 1.5 s"
#define DBG(msg...) do{ \
if(debug)\
printk(KERN_INFO msg);\
}while(0)
struct dm9000x{
u32ioaddr; // Register I/O base address
u32iodata; // Data I/O address
u16irq; // IRQ
u8iomode; // 0:16bits 1:word 2:byte
u8opmode;
u16 Preg0,Preg4;
u16tx_pkt_cnt;
u16sent_pkt_len, queue_pkt_len;
u8device_wait_reset; //device state
u8nic_type; // NIC type
spinlock_tlock;
};
static int debug=0;
static struct net_device *xnet_dev = NULL;
static void dm9000_hash_table(struct net_device *dev);
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 do_xnet_reset(struct dm9000x *dm9x);
static void iowt(struct dm9000x *dm9x, int reg, u8 value);
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);
static void xnet_timeout(struct net_device *dev);
static void xnet_timeout(struct net_device *dev)
{
struct dm9000x *dm9x=netdev_priv(dev);
u8 reg_save;
reg_save=readb(dm9x->ioaddr);
netif_stop_queue(dev);
do_xnet_reset(dm9x);
dev->trans_start=jiffies;
netif_wake_queue(dev);
writeb(reg_save,dm9x->ioaddr);
}
int xnet_probe(struct net_device *dev)
{
int i =0;
u32id_val;
unsignedlong iobase;
structdm9000x *dm9x=netdev_priv(dev);
unsignedchar mac_add[6] = {0x00, 0x13, 0xf6, 0x6c, 0x87, 0x89};
memset(dm9x,0,sizeof(struct dm9000x));
bwscon =ioremap_nocache(BWSCON,0x0000004); //总线位宽和等待状态控制器
bankcon4=ioremap_nocache(BANKCON4,0x0000004);
iobase=(unsigned long)ioremap(DM9000_MIN_IO,0x400); //进行地址隐射
writel((readl(bwscon)&(~(0xf<<16)))|(0xD<<16),bwscon); //enable UB/LB enable WAIT 16-bit
writel(0x1f7c,bankcon4);
s3c2410_gpio_cfgpin(S3C2410_GPF7,S3C2410_GPF7_EINT7);
spin_lock_init(&dm9x->lock);
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) {
DBG("id_val: %x, iobase: %p \n", id_val, (void *)iobase);
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;
dev->tx_timeout=&xnet_timeout;
dev->set_multicast_list=&dm9000_hash_table;
for (i = 0; i < 6; i++)
dev->dev_addr[i] = mac_add[i];
request_region(iobase, 2,dev->name);
}
return0;
}
static void do_xnet_reset(struct dm9000x *dm9x)
{
iowt(dm9x,DM9000_NCR, 1<<0);
}
static void dm9000_hash_table(struct net_device *dev)
{
struct dm9000x *dm9x = 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 = (1<<5) |(1<<4)| 1;
unsigned long flags;
spin_lock_irqsave(&dm9x->lock,flags);
for (i = 0, oft = 0x10; i < 6;i++, oft++)
iowt(dm9x, oft,dev->dev_addr[i]);
for (i = 0; i < 4; i++)
hash_table[i] = 0x0;
hash_table[3] = 0x8000;
if (dev->flags &0x100)
rcr |= 2;
if (dev->flags&0x200)
rcr |=(1<<3);
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 = 0x16; i < 4;i++) {
iowt(dm9x,oft++,hash_table[i]);
iowt(dm9x,oft++,hash_table[i]>>8);
}
iowt(dm9x, 0x05,rcr);
spin_unlock_irqrestore(&dm9x->lock,flags);
}
static void do_init_dm9000x(struct net_device *dev)
{
//inti,oft;
structdm9000x *dm9x = netdev_priv(dev);
//set theinternal PHY power-on, GPIOs normal, and wait 2ms
iowt(dm9x,0x1F,0); //GPR (reg_1Fh)bit GPIO0=0 pre-activatePHY
iowt(dm9x,0x1e, 1);
iowt(dm9x,0x1F, 0);
dm9x->iomode = iord(dm9x, 0xFE)>> 6; //ISR bit[7:6] I/O mode
//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, 0x3F);
iowt(dm9x,0x0a, 0xff);
// ActivateDM9000
iowt(dm9x,0x05, 0x31); //RX enable
iowt(dm9x,0xff, 0x83); //Enable TX/RX interrupt mask
dm9000_hash_table(dev);
dm9x->tx_pkt_cnt = 0;
dm9x->queue_pkt_len = 0;
dev->trans_start = 0;
spin_lock_init(&dm9x->lock);
DBG("do initdm9000x xnte dev! \n");
}
static void do_xnet_tx(void)
{
structnet_device *dev = xnet_dev;
structdm9000x *dm9x = netdev_priv(dev);
inttx_status = iord(dm9x,0x01); //Got TX status
if(tx_status & 0xc){ //One packet sent complete
dm9x->tx_pkt_cnt--;
dev->stats.tx_packets++;
if (dm9x->tx_pkt_cnt > 0){ //Queue packet check & send
//Set TX length to DM9000
iowt(dm9x, 0xfc, dm9x->queue_pkt_len );
iowt(dm9x, 0xfd, (dm9x->queue_pkt_len>> 8) );
//Issue TX polling command
iowt(dm9x, 0x2,0x1); //Cleared after TX complete
dev->trans_start =jiffies; //saved the timestamp
}
netif_wake_queue(dev);
}
DBG("xnet_tx_done the xnet dev! \n");
}
struct dm9000_rxhdr {
u8 RxPktReady;
u8 RxStatus;
__le16 RxLen;
} __attribute__((__packed__));
static void dm9000_inblk_16bit(void __iomem *reg, void *data, intcount)
{
readsw(reg, data, (count+1)>> 1);
}
static void do_xnet_rx(void)
{
structnet_device *dev = xnet_dev;
structdm9000x *dm9x = netdev_priv(dev);
structsk_buff *skb;
struct dm9000_rxhdrrxhdr;
u8 rxbyte,*rdptr;
u16 i,RxLen, GoodPacket, tmplen;
do {
iord(dm9x,0xf0); //Dummy read
rxbyte =inb(dm9x->iodata); //Got most updated data
if (rxbyte == DM9000_PKT_RDY) { // packet ready to receivecheck
GoodPacket = 1;
outb(0xf2, dm9x->ioaddr);
dm9000_inblk_16bit((void*)dm9x->iodata,&rxhdr,(int)sizeof(rxhdr));
RxLen=le16_to_cpu(rxhdr.RxLen);
if (RxLen < 0x40) {
GoodPacket = 0;
} else if (RxLen > DM9000_PKT_MAX) {
DBG("<DM9000> RST: RX Len:%x(%x)\n",RxLen, rxhdr.RxStatus);
dm9x->device_wait_reset = 1;
}