/* 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");
|