ENC28J60网络设备驱动分析

文件:enc28j60.rar
大小:9KB
下载:下载

 enc28j60是一款比较常用的网络芯片,主要特点是接口简单,通过spi接口与cpu通信,所以它的管脚数要少很多,这个优点同时也带来很大的问题,spi传输的效率肯定没有总线结构快,如果大量数据传输的时候会出现问题。下边是整个驱动的代码:

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

通过上边这个驱动来分析下,网络设备驱动的运行流程:

  网卡数据的接受是通过中断来完成,通过上边的代码,具体的感悟就是,整个linux系统驱动代码其实和mcu下子函数的编写是没有什么区别的,只是由于在linux下,需要kernel去统一管理设备和资源,需要统一的接口,所以在实现具体的子函数后,需要按照kernel的规范去填充它规定的结构体,同时按照kernel要求的模板和框架去搭建这个驱动,如果我们对这个驱动进行剥离,剥离的规则就是mcu和kernel,那么一下的函数就是属于mcu队伍:
void init_SPI(CanBandRate bandratee);
unsigned char ReadSIOData(void)         //SPI 数据接收
void SendSIOData(unsigned char data)  //SPI 数据发送
void enc28j60ChipSelect(int cs_stat)   //使能enc28j60的SPI总线
void enc28j60ReadBuffer(u16 len, u8* data)
void enc28j60WriteBuffer(u16 len, u8* data)
u8 enc28j60ReadOp(u8 op, u8 address)  //读控制寄存器
void enc28j60WriteOp(u8 op, u8 address, u8 data)//写控制寄存器
void enc28j60SetBank(u8 address)
u8 enc28j60Read(u8 address)
void enc28j60Write(u8 address, u8 data)
u16 enc28j60PhyRead(u8 address)
void enc28j60PhyWrite(u8 address, u16 data)
void nicGetMacAddress(u8* macaddr)
void nicSetMacAddress(u8* macaddr)
以下的函数就属于kernel队伍:
int enc28j60_open (struct net_device *dev)
int enc28j60_release (struct net_device *dev)
static void enc_timer(unsigned long data)
enc28j60_Interrupt(int irq, void *dev_id, struct pt_regs * regs)
int __init enc28j60_init (struct net_device *dev)
int __init enc28j60_init_module (void)
void __exit  enc28j60_cleanup (void)
module_init (enc28j60_init_module);
module_exit (enc28j60_cleanup);

这里我们会发现,属于mcu队伍的函数往往需要去实际的编写代码,需要去查看数据手册,就是需要通过思考编写的代码,而属于kernel队伍的函数就不是这样,它有自己规定的框架,只要在固定的地方填充固定的东西就可以了,一个框架而以,不管是open()、release()都是这样,这样看来驱动编写和mcu开发是没有本质的区别的,只需要了解kernel中一些其它的知识就可以编写完美的代码了,而这些知识就包括kernel化的中断、定时,以及资源的控制等。
<script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/buttonLite.js#style=-1&uuid=&pophcol=3&lang=zh"></script> <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/bshareC0.js"></script>
阅读(3096) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

yfj3002012-06-20 08:52:21

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值