/* enc28j60.c: EDTP FrameThrower style enc28j60 driver for Linux 2.4 * * (c) Copyright 2006 American Microsystems Limited * Written by David Anders. * * Based on the Procyon AVRlib enc28j60.c written by Pascal Stang * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */
//#define MODULE
//#ifndef __KERNEL__
// #define __KERNEL__
//#endif #include <linux/module.h> #include <linux/config.h> #include <linux/netdevice.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/in.h> #include <linux/etherdevice.h> /* eth_type_trans */ #include <linux/ip.h> /* struct iphdr */ #include <linux/tcp.h> /* struct tcphdr */ #include <linux/skbuff.h> #include <linux/types.h> /* size_t */ #include <asm/io.h> #include <asm/hardware.h> #include <asm/irq.h> #include <asm/byteorder.h> #include "enc28j60.h" #include <asm/arch-s3c2410/S3C2410.h>
#define DEBUG #ifdef DEBUG #define PRINTK printk #else #define PRINTK(fmt, arg...) #endif
void enc_device_init(void); static void enc_timer(unsigned long);
static void enc28j60_Interrupt(int irq, void *dev_id, struct pt_regs * regs); static void net_timeout(struct net_device *dev); //static void enc_packet_receive(unsigned long unused);
//DECLARE_TASKLET(enc_rx_tasklet,enc_packet_receive,0);
static struct net_device * enc_dev = NULL; u8 Enc28j60Bank=-1; u16 NextPacketPtr; spinlock_t lplock;
typedef struct board_info{ struct timer_list timer; struct net_device_stats stats; u8 device_wait_reset; u16 tx_pkt_cnt; u16 queue_pkt_len; u16 queue_start_addr; unsigned int reset_tx_timeout; }board_info_t; //void enc_tx_done(struct net_device *dev, board_info_t *db);
#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" */
//----------------spi section begin-------------------------------------------------------------------//
unsigned char ReadSIOData(void); void SendSIOData(unsigned char data); #define BIT_RDY 0x01 typedef enum{ //这里设置波特率 BandRate_10kbps, BandRate_20kbps, BandRate_40kbps, BandRate_80kbps, BandRate_125kbps, BandRate_250kbps, BandRate_500kbps, BandRate_1Mbps, BandRate_10Mbps, BandRate_25Mbps }CanBandRate; void init_SPI(CanBandRate bandratee); void init_SPI(CanBandRate bandrate) //SPI 初始化
{ //GPGCON&=~(0x3f<<10);
//GPGCON|=(0x3f<<10);
GPECON&=~(0x3f<<22); //GPE11 12 13 配置gpe11 12 13分别为spi的miso0/mosi0/clk0
GPECON|=(0x2a<<22); SPPRE0&=0; switch(bandrate) // spi时钟频率设置baudrate = PCLK / 2 / (prescaler value + 1) 此处PCLK为50m
{ case BandRate_10kbps: case BandRate_20kbps: case BandRate_40kbps: case BandRate_80kbps: case BandRate_125kbps: SPPRE0|=0xc7; break; case BandRate_250kbps: SPPRE0|=0x63; break; case BandRate_500kbps: SPPRE0|=0x31; break; case BandRate_1Mbps: SPPRE0|=0x18; case BandRate_10Mbps: SPPRE0|=0x01; case BandRate_25Mbps: SPPRE0|=0x00; break; } SPCON0&=0; SPCON0|=0x18;// polling mode/enable clk/master/active high/format A/normal mode
}
unsigned char ReadSIOData(void) //SPI 数据接收
{ while(!(SPSTA0&BIT_RDY)); return SPRDAT0; }
void SendSIOData(unsigned char data) //SPI 数据发送
{ SPTDAT0=data; while(!(SPSTA0&BIT_RDY)); //等待发送
}
/***************************************************spi end****************************************/
void enc28j60ChipSelect(int cs_stat) //使能enc28j60的SPI总线
{ unsigned long tmpval; if ( cs_stat == 1 ) { tmpval=GPGDAT; tmpval &= ~(1<<2); //GPG2 cs0=0
GPGDAT=tmpval; } else { tmpval=GPGDAT; tmpval |= (1<<2); //GPG2 cs0=1
GPGDAT=tmpval; } }
void enc28j60ReadBuffer(u16 len, u8* data) { u8 tmpval; //int counter=1;
// assert CS
enc28j60ChipSelect(1); // issue read command
tmpval=ENC28J60_READ_BUF_MEM; // __raw_writeb(tmpval,S3C2410_SPI1DTX);
// SPI1DTX=tmpval;
SendSIOData(tmpval); //udelay(4);
while(len--) { // read data
tmpval=0x00; // send 0x00 to make the clk output 这里是spi要求的。
SendSIOData(tmpval); // udelay(4);
*data++ =ReadSIOData(); // udelay(4);
} // release CS
// udelay(50);
enc28j60ChipSelect(0); }
void enc28j60WriteBuffer(u16 len, u8* data) { u8 tmpval; // assert CS
enc28j60ChipSelect(1); // issue write command
tmpval = ENC28J60_WRITE_BUF_MEM; //参考28页
SendSIOData(tmpval); // udelay(1);
while(len--) { // write data
tmpval = *data++; SendSIOData(tmpval); //udelay(1);
} // release CS
// udelay(100);
enc28j60ChipSelect(0); }
u8 enc28j60ReadOp(u8 op, u8 address) //读控制寄存器
{ u8 data; u8 tmpval; // assert CS
enc28j60ChipSelect(1); // issue read command
tmpval = op | (address & ADDR_MASK); SendSIOData(tmpval); data=ReadSIOData(); // udelay(1);
tmpval = 0x00; SendSIOData(tmpval); data=ReadSIOData();//这里是为了维护spi总线的时序
// udelay(1);
if(address & 0x80)//这里是为了兼容MAC和MII命令,因为这种命令返回的数据的前一个字节是没有意义的。
{ tmpval = 0x00; SendSIOData(tmpval); data=ReadSIOData(); // udelay(1);
} data=ReadSIOData(); // release CS
enc28j60ChipSelect(0); return data; }
void enc28j60WriteOp(u8 op, u8 address, u8 data)//写控制寄存器
{ u8 tmpval; // assert CS
// while(1)
// {
enc28j60ChipSelect(1); // issue write command
tmpval = op | (address & ADDR_MASK); // printk("GPGDAT\n=%x\n",GPGDAT);
//}
SendSIOData(tmpval); // udelay(1);
tmpval = data; SendSIOData(tmpval); // udelay(100);
// release CS
enc28j60ChipSelect(0); }
void enc28j60SetBank(u8 address) { // set the bank (if needed)
if((address & BANK_MASK) != Enc28j60Bank) { // set the bank
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0)); enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5); Enc28j60Bank = (address & BANK_MASK); } }
u8 enc28j60Read(u8 address) { // set the bank
enc28j60SetBank(address); // do the read
return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address); }
void enc28j60Write(u8 address, u8 data) { // set the bank
enc28j60SetBank(address); // do the write
enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data); }
u16 enc28j60PhyRead(u8 address) { u16 data; // Set the right address and start the register read operation
enc28j60Write(MIREGADR, address); enc28j60Write(MICMD, MICMD_MIIRD); // wait until the PHY read completes
while(enc28j60Read(MISTAT) & MISTAT_BUSY); // quit reading
enc28j60Write(MICMD, 0x00); // get data value
data = enc28j60Read(MIRDL); data |= enc28j60Read(MIRDH); // return the data
return data; }
void enc28j60PhyWrite(u8 address, u16 data) { // set the PHY register address
enc28j60Write(MIREGADR, address); // write the PHY data
enc28j60Write(MIWRL, data); enc28j60Write(MIWRH, data>>8); // wait until the PHY write completes
// while(enc28j60Read(MISTAT) & MISTAT_BUSY){
// printk("MISTAT:0x%02x\n",enc28j60Read(MISTAT));
// udelay(1000);
// }
}
void nicGetMacAddress(u8* macaddr) { //unsigned char mc;
// mc=enc28j60Read(MAADR5);
//printk("mac5=%x\n",mc);
// read MAC address registers
// NOTE: MAC address in ENC28J60 is byte-backward
*macaddr++ = enc28j60Read(MAADR5); *macaddr++ = enc28j60Read(MAADR4); *macaddr++ = enc28j60Read(MAADR3); *macaddr++ = enc28j60Read(MAADR2); *macaddr++ = enc28j60Read(MAADR1); *macaddr++ = enc28j60Read(MAADR0); }
void nicSetMacAddress(u8* macaddr) { // write MAC address
// NOTE: MAC address in ENC28J60 is byte-backward
enc28j60Write(MAADR5, *macaddr++); enc28j60Write(MAADR4, *macaddr++); enc28j60Write(MAADR3, *macaddr++); enc28j60Write(MAADR2, *macaddr++); enc28j60Write(MAADR1, *macaddr++); enc28j60Write(MAADR0, *macaddr++); }
void enc28j60_RegDump(void) { PRINTK("RevID: 0x%02x\r\n", enc28j60Read(EREVID)); PRINTK("Cntrl: ECON1 ECON2 ESTAT EIR EIE\r\n"); PRINTK(" 0x%02x ",enc28j60Read(ECON1)); PRINTK("0x%02x ",enc28j60Read(ECON2)); PRINTK("0x%02x ",enc28j60Read(ESTAT)); PRINTK("0x%02x ",enc28j60Read(EIR)); PRINTK("0x%02x\n\n",enc28j60Read(EIE)); PRINTK("MAC : MACON1 MACON2 MACON3 MACON4 MAC-Address\r\n"); PRINTK(" 0x%02x ",enc28j60Read(MACON1)); PRINTK("0x%02x ",enc28j60Read(MACON2)); PRINTK("0x%02x ",enc28j60Read(MACON3)); PRINTK("0x%02x ",enc28j60Read(MACON4)); PRINTK("%02x:",enc28j60Read(MAADR5)); PRINTK("%02x:",enc28j60Read(MAADR4)); PRINTK("%02x:",enc28j60Read(MAADR3)); PRINTK("%02x:",enc28j60Read(MAADR2)); PRINTK("%02x:",enc28j60Read(MAADR1)); PRINTK("%02x\n\n",enc28j60Read(MAADR0)); PRINTK("Rx : ERXST ERXND ERXWRPT ERXRDPT ERXFCON EPKTCNT MAMXFL\r\n"); PRINTK(" 0x%02x:",enc28j60Read(ERXSTH)); PRINTK("0x%02x ",enc28j60Read(ERXSTL)); PRINTK("0x%02x:",enc28j60Read(ERXNDH)); PRINTK("0x%02x ",enc28j60Read(ERXNDL)); PRINTK("0x%02x:",enc28j60Read(ERXWRPTH)); PRINTK("0x%02x ",enc28j60Read(ERXWRPTL)); PRINTK("0x%02x:",enc28j60Read(ERXRDPTH)); PRINTK("0x%02x ",enc28j60Read(ERXRDPTL)); PRINTK("0x%02x ",enc28j60Read(ERXFCON)); PRINTK("0x%02x ",enc28j60Read(EPKTCNT)); PRINTK("0x%02x:",enc28j60Read(MAMXFLH)); PRINTK("0x%02x\n",enc28j60Read(MAMXFLL)); PRINTK("Tx : ETXST ETXND MACLCON1 MACLCON2 MAPHSUP\r\n"); PRINTK("0x%02x:",enc28j60Read(ETXSTH)); PRINTK("0x%02x ",enc28j60Read(ETXSTL)); PRINTK("0x%02x:",enc28j60Read(ETXNDH)); PRINTK("0x%02x ",enc28j60Read(ETXNDL)); PRINTK("0x%02x ",enc28j60Read(MACLCON1)); PRINTK("0x%02x ",enc28j60Read(MACLCON2)); PRINTK("0x%02x\n",enc28j60Read(MAPHSUP)); udelay(1000); }
static struct net_device_stats * get_stats(struct net_device *dev) { board_info_t *db=(board_info_t *)dev->priv; return &db->stats; }
int enc28j60_open (struct net_device *dev) { int result; board_info_t * db = (board_info_t *)dev->priv; PRINTK("enc28j60_open called\n"); // set_external_irq(IRQ_EINT1,EXT_FALLING_EDGE,GPIO_PULLUP_DIS);
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIE, EIE_INTIE|EIE_PKTIE|EIE_TXIE|EIE_RXERIE|EIE_TXERIE); set_external_irq(dev->irq,EXT_FALLING_EDGE,GPIO_PULLUP_DIS); result = request_irq(dev->irq,enc28j60_Interrupt , 0, "enc28j60" , dev); //注册中断
//printk("request_irq returned: %d\n",result);
// printk("INTMASK==%x\n",INTMSK);
//printk("EXINT0=%x\n",EXTINT0);
//printk("EXINTMASK=%x\n",EINTMASK);
//printk("GPFCON=%x\n",GPFCON);
enable_irq(dev->irq); //使能 IRQ_EINT7
// printk("INTMASK===%x\n",INTMSK);
//printk("EXINT0=%x\n",EXTINT0);
//printk("EXINTMASK=%x\n",EINTMASK);
//printk("GPFCON=%x\n",GPFCON);
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE|EIE_TXIE|EIE_RXERIE|EIE_TXERIE); //打开EIE中断
/* set and active a timer process */ init_timer(&db->timer); db->timer.expires = DMFE_TIMER_WUT * 2; db->timer.data = (unsigned long)dev; db->timer.function = &enc_timer; //add_timer(&db->timer)//打开定时中断
db->tx_pkt_cnt = 0; db->queue_pkt_len = 0; dev->trans_start = 0; netif_start_queue (dev); return 0; }
int enc28j60_release (struct net_device *dev) { board_info_t *db = (board_info_t *)dev->priv; PRINTK ("enc28j60_release called\n"); enc28j60_RegDump(); del_timer(&db->timer); netif_stop_queue(dev); INTMSK|=5; disable_irq(dev->irq); free_irq(dev->irq,dev); return 0; } static void enc_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; board_info_t *db = (board_info_t *)dev->priv; /* TX timeout check */ PRINTK("in timer\n"); if (dev->trans_start&&((jiffies-dev->trans_start)>DMFE_TX_TIMEOUT)) { PRINTK("time outttt\n"); db->device_wait_reset = 1; db->reset_tx_timeout++; } if (db->device_wait_reset) { netif_stop_queue(dev); // db->reset_counter++;
db->device_wait_reset = 0; dev->trans_start = 0; // dm9000_init(dev);
PRINTK("in reset\n"); netif_wake_queue(dev); } /* Set timer again */ db->timer.expires = DMFE_TIMER_WUT; add_timer(&db->timer); };
static int enc28j60_xmit (struct sk_buff *skb, struct net_device *dev) { //board_info_t *db = (board_info_t *)dev->priv;
//char * data_ptr;
//int i;, tmplen;
//unsigned char mc,stat;
unsigned char stat; //struct net_local *lp=(struct net_local *)dev->priv;
spin_lock_irq(&lplock);//互斥锁
/* if (db->tx_pkt_cnt >= 1) { spin_unlock_irq(&lplock); return 1; }*/ netif_stop_queue(dev); //停止网络发送
/* Disable all interrupt */ enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIE, EIE_INTIE);
// mc=enc28j60Read(MAADR5);
//printk("mac5=%x\n",mc);
// Set the write pointer to start of transmit buffer area
enc28j60Write(EWRPTL, TXSTART_INIT); // 28j60缓冲区写入的位置
enc28j60Write(EWRPTH, TXSTART_INIT>>8);
enc28j60Write(ETXSTL, TXSTART_INIT); //28j60缓冲区开始位置
enc28j60Write(ETXSTH, TXSTART_INIT>>8); // Set the TXND pointer to correspond to the packet size given
enc28j60Write(ETXNDL, (TXSTART_INIT+skb->len)); //skb->len发送数据的长度
enc28j60Write(ETXNDH, (TXSTART_INIT+skb->len)>>8);
stat=enc28j60Read(ESTAT); // printk("ESTAT=%x\n",stat);
if(stat&2)//检查是否有发送错误
{ PRINTK("send erro!\n"); spin_unlock_irq(&lplock); return 1; } // write per-packet control byte lht
enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00); //use MCON3 参考42页
// copy the packet into the transmit buffer
enc28j60WriteBuffer(skb->len, skb->data); //udelay(100);
// send the contents of the transmit buffer onto the network
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); udelay(400);//可以调试,有可能影响稳定性 可以更改
spin_unlock_irq(&lplock); dev->trans_start=jiffies;//加入时间戳
dev_kfree_skb(skb);//释放空间
// netif_wake_queue(dev);
udelay(200);//可以调试,有可能影响稳定性 可以更改
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE|EIE_TXIE|EIE_RXERIE|EIE_TXERIE); return 0; }
static void enc28j60_Interrupt(int irq, void *dev_id, struct pt_regs * regs) { //struct net_device *dev = dev_id;
// board_info_t *db;
struct sk_buff *skb; struct net_device *dev = dev_id; u16 rxstat; u16 len=0; u16 status,PKCNT; // int counter;
// int loop=1;
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIE, EIE_INTIE); //disable irq
status=enc28j60Read(EIR); // printk("status e=%x\n",status);
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, status); // printk("EIRff=%x\n",enc28j60Read(EIR));
if(status & EIR_TXIF) //发送中断
{ enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXIF); //enc_tx_done(dev,db);
netif_wake_queue(dev); } if(status & EIR_PKTIF) //接收中断
{ do{ NextPacketPtr = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0); //下个数据包起始地址 参考45页
NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8; //printk("NextPacketPtr=%x\n",NextPacketPtr);
// re ad the packet length
len = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0); //数据包长度
len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8; // printk("len=%x\n",len);
rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0); rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
skb = dev_alloc_skb(len+2); skb->dev = dev; skb_reserve(skb,2); skb_put(skb,len); // copy the packet from the receive buffer
enc28j60ReadBuffer(len, skb->data); // Move the RX read pointer to the start of the next received packet
// This frees the memory we just read out
enc28j60Write(ERXRDPTL, (NextPacketPtr)); enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8); //printk();
//printk("ERXWR=0x%x:",(enc28j60Read(ERXWRPTH)<<8)+enc28j60Read(ERXWRPTL));
//printk("0x%02x ",enc28j60Read(ERXWRPTL));
//printk("ERXRD=0x%x:\n",(enc28j60Read(ERXRDPTH)<<8)+enc28j60Read(ERXRDPTL));
// printk("0x%02x ",enc28j60Read(ERXRDPTL));
enc28j60Write(ERDPTL, (NextPacketPtr)); enc28j60Write(ERDPTH, (NextPacketPtr)>>8); //不用.可以自动变化 ECON2.AUTOINC置位
// decrement the packet counter indicate we are done with this packet
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); skb->protocol= eth_type_trans(skb,dev); skb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx(skb); //数据交给上层网络
//udelay(100);
dev->last_rx=jiffies; PKCNT=enc28j60Read(EPKTCNT); //缓冲区还有多少包?
//printk("PKCNT=%x\n",PKCNT);
//udelay(1200);
}while(PKCNT!=0); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//enc28j60Write(ERXSTL,0x00);
//enc28j60Write(ERXSTH,0x08);
/* enc28j60Write(ECON1, 0x00); //close receive enc28j60Write(ERXSTL, RXSTART_INIT&0xFF); enc28j60Write(ERXSTH, RXSTART_INIT>>8); // set receive pointer address enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF); enc28j60Write(ERXRDPTH, RXSTART_INIT>>8); enc28j60Write(ERDPTL, RXSTART_INIT&0xFF); enc28j60Write(ERDPTH, RXSTART_INIT>>8); enc28j60Write(ECON1, 0x04); //enable receive */ } if(status& EIE_TXERIE) { PRINTK("TX erro\n"); enc_device_init(); netif_wake_queue(dev); } if(status& EIE_RXERIE) { //enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, EIE_RXERIE);
PRINTK("RX erro\n");; enc_device_init(); netif_wake_queue(dev); } enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE|EIE_TXIE|EIE_RXERIE|EIE_TXERIE); return; } #if 0 void enc_tx_done(struct net_device *dev, board_info_t *db) { netif_wake_queue(dev); } #endif int __init enc28j60_init (struct net_device *dev) { board_info_t *db; // u8 id;
// int result;
// static struct net_device_stats enc28j60_netstats;
// id = enc28j60Read(EREVID);
// PRINTK("enc28j60 id(%d)\n", id);
// if((id == 0) || (id == 0xff))
// return -ENODEV;
db=(void *)(kmalloc(sizeof(*db),GFP_KERNEL)); memset(db,0,sizeof(*db)); dev->priv = db ; memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = get_stats; enc_dev = dev; dev->open = enc28j60_open; dev->stop = enc28j60_release; dev->hard_start_xmit = enc28j60_xmit; dev->tx_timeout =net_timeout; dev->watchdog_timeo=5*HZ; dev->irq=IRQ_EINT7; spin_lock_init(&lplock); dev->dev_addr[0] = 0x80;// 0x11;i
dev->dev_addr[1] = 0xe2; dev->dev_addr[2] = 0x66; dev->dev_addr[3] = 0x60; dev->dev_addr[4] = 0x00; dev->dev_addr[5] = 0x01; nicSetMacAddress(dev->dev_addr); #if 1 { u8 checkaddr[6]; nicGetMacAddress(checkaddr); if(memcmp(checkaddr, dev->dev_addr, 6) != 0) { kfree(dev->priv); dev->priv = NULL; PRINTK("enc28j60 error! may be no ic(%2X:%2X:%2X:%2X:%2X:%2X)!\n", checkaddr[0], checkaddr[0], checkaddr[1], checkaddr[2], checkaddr[3], checkaddr[4], checkaddr[5]); return -ENODEV; } } #endif PRINTK("set macaddr\n"); ether_setup(dev); PRINTK("dev->hard_header_len: 0x%02x\n",dev->hard_header_len); // do bank 0 stuff
// initialize receive buffer
// 16-bit transfers, must write low byte first
// set receive buffer start address
PRINTK("starting enc28j60 init process!\n"); return 0; } static void net_timeout(struct net_device *dev) { PRINTK("transmit timed out...\n"); enc_device_init(); netif_wake_queue(dev); }
void enc_device_init(void) { enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); udelay(1000); //复位后的延时
enc28j60PhyWrite(PHLCON, 0x3412); enc28j60SetBank(ECON1); NextPacketPtr = RXSTART_INIT; enc28j60Write(ERXSTL, RXSTART_INIT&0xFF); enc28j60Write(ERXSTH, RXSTART_INIT>>8); // set receive pointer address
enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF); enc28j60Write(ERXRDPTH, RXSTART_INIT>>8); enc28j60Write(ERDPTL, RXSTART_INIT&0xFF); enc28j60Write(ERDPTH, RXSTART_INIT>>8); // enc28j60Write(ERXWRPTL,RXSTART_INIT&0xFF); //set the wr pointer or receive area
// enc28j60Write(ERXWRPTH,RXSTART_INIT>>8);
// enc28j60Write(ERXRDPTL,RXSTART_INIT&0xFF);
// enc28j60Write(ERXRDPTH,RXSTART_INIT);
// set receive buffer end:
// ERXND defaults to 0x1FFF (end of ram)
enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF); enc28j60Write(ERXNDH, RXSTOP_INIT>>8); // set transmit buffer start
// ETXST defaults to 0x0000 (beginnging of ram)
enc28j60Write(ETXSTL, TXSTART_INIT&0xFF); enc28j60Write(ETXSTH, TXSTART_INIT>>8); PRINTK("bank2 enc28j60 init process!\n"); // do bank 2 stuff
enc28j60Write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); // bring MAC out of reset
enc28j60Write(MACON2, 0x00); // enable automatic padding and CRC operations
// enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); //b s g
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN|MACON3_FULDPX); //q s g
enc28j60Write(MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); // set inter-frame gap (non-back-to-back)
enc28j60Write(MAIPGL, 0x12); enc28j60Write(MAIPGH, 0x0C); // set inter-frame gap (back-to-back)
// enc28j60Write(MABBIPG, 0x12); // b s g 半双工
enc28j60Write(MABBIPG, 0x15); // q s g 全双工
enc28j60PhyWrite(PHCON1,0x0100); //q s g
// Set the maximum packet size which the controller will accept
enc28j60Write(MAMXFLL, MAX_FRAMELEN&0xFF); enc28j60Write(MAMXFLH, MAX_FRAMELEN>>8); PRINTK("bank3 enc28j60 init process!\n"); // do bank 3 stuff
// write MAC address
// NOTE: MAC address in ENC28J60 is byte-backward
enc28j60Write(MAADR5, ENC28J60_MAC0); enc28j60Write(MAADR4, ENC28J60_MAC1); enc28j60Write(MAADR3, ENC28J60_MAC2); enc28j60Write(MAADR2, ENC28J60_MAC3); enc28j60Write(MAADR1, ENC28J60_MAC4); enc28j60Write(MAADR0, ENC28J60_MAC5); // no loopback of transmitted frames
PRINTK("phy enc28j60 init process!\n"); enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS); // enable interrutps
// enable packet reception
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); // enc28j60Write(ERXFCON, 0x00);
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_PKTIF|EIR_TXIF|EIR_RXERIF|EIR_TXERIF); PRINTK("enabling interupts!\n"); enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE|EIE_TXIE|EIE_RXERIE|EIE_TXERIE); // Reenable receive logic
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); PRINTK("enc28j60 device initialized\n"); }
//#ifdef MODULE
struct net_device enc28j60 = {init: enc28j60_init};
int __init enc28j60_init_module (void) { int result; unsigned long tmpval; init_SPI(BandRate_25Mbps); //25M
//init_SPI(BandRate_10Mbps);
strcpy (enc28j60.name, "eth%d"); GPGCON &=~(3<<4); //GPG2 输出属性
GPGCON |=(1<<4); //disable the pullup resistors for GPG0,GPG5,GPG6,GPG7
tmpval=0; tmpval |= (1<<4) | (1<<5) | (1<<6) | (1<<7); GPGUP=tmpval; GPFCON &=~(3<<14); GPFCON |=2<<14; //disable pullup resistors for GPF1 and GPF4
tmpval=GPFUP; tmpval |=(1<<7) ; GPFUP=tmpval; enc_device_init(); //enc28j60初始化
if ((result = register_netdev (&enc28j60))) { PRINTK ("enc28j60: Error %d initializing enc28j60 based device",result); return result; } return 0; }
void __exit enc28j60_cleanup (void) { PRINTK ("Cleaning Up the Module\n"); enc28j60PhyWrite(PHLCON, 0x3492); if(enc28j60.priv) kfree(enc28j60.priv); unregister_netdev (&enc28j60); return; }
module_init (enc28j60_init_module); module_exit (enc28j60_cleanup); //#endif /* MODULE */
MODULE_LICENSE("GPL");
|