www.pudn.com > DM9000.rar > dm9000.c


/****************************************Copyright (c)************************************************** 
**                               Guangzou ZLG-MCU Development Co.,LTD. 
**                                     graduate school 
**                                 http://www.zlgmcu.com 
** 
**--------------File Info------------------------------------------------------------------------------- 
** File name:           rtl8019.c 
** Last modified Date:  2005-05-12 
** Last Version:        1.0 
** Descriptions:        This is a Kernel module for uClinux 2.4.x .
**                      This module let uClinux 2.4.x can use rtl8019.  
**------------------------------------------------------------------------------------------------------ 
** Created by:          Chenmingji 
** Created date:        2005-05-12 
** Version:             1.0 
** Descriptions:        The original version 
** 
**------------------------------------------------------------------------------------------------------ 
** Modified by: 
** Modified date: 
** Version: 
** Descriptions: 
** 
 
********************************************************************************************************/ 

#define IN_DM9000
#include "config.h"
#include "dm9000.h"

/******************************************************************************************************** 
              function announce
********************************************************************************************************/ 

static int net_init(struct net_device *dev);
static int net_open(struct net_device *dev);
static int net_release(struct net_device *dev); 
static int net_config(struct net_device *dev, struct ifmap *map);
static int net_tx(struct sk_buff *skb, struct net_device *dev);
static void net_irq_handle(int irq, void *dev_id, struct pt_regs *regs); 
static int net_set_mac_address(struct net_device *dev, void *addr);
int  net_init_module(void);
void net_cleanup(void);
static void net_tasklet(unsigned long);

/******************************************************************************************************** 
              define announce
********************************************************************************************************/ 
static struct net_device *DM9000Dev; 

module_init(net_init_module);
module_exit(net_cleanup);
DECLARE_TASKLET(ZLG_net_tasklet, net_tasklet, (unsigned long)(&DM9000Dev));
 
MODULE_LICENSE("Proprietary");
MODULE_DESCRIPTION("Guangzou ZLG-MCU Development Co.,LTD.\ngraduate school\nhttp://www.zlgmcu.com");
MODULE_SUPPORTED_DEVICE("uClinux2.4.x LPC2200 DM9000");
MODULE_AUTHOR("chenmingji");

/********************************************************************************************************* 
**                  "全局和静态变量在这里定义"          
**        global variables and static variables define here 
********************************************************************************************************/ 
static unsigned int usage;
static u32 PinSel0Save; 
static board_info_t NetDriverInfo[1]; 

/********************************************************************************************************/ 

static struct net_device net_net =
{
    name:           "eth0",
    init:           net_init,
    base_addr:      IOaddress0,
    irq:            NET_IRQ,
    watchdog_timeo: NET_TIMEOUT,
};

 
/********************************************************************************************************* 
** Function name:           ior 
** 
** Descriptions:            read a reg form dm9000  
** 
** input parameters:        board_info_t *db    ;dm9000 status struct 
**                          reg                 ;reg address of dm9000 
** Returned value:          uint8               ;reg value  
**          
** Used global variables:   None 
** Calling modules:         None 
** 
** Created by:              Yehaoben 
** Created Date:            2004/02/02 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified date: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
static uint8 ior(board_info_t *db, uint8 reg) 
{    
    unsigned int i; 
    unsigned int rt; 
 
    outb(reg, db->ioaddr); 
    for (i = 0; i < BUS_DELAY; i++) 
    { 
    } 
 
    rt = inb(db->io_data); 
    for (i = 0; i < BUS_DELAY; i++) 
    { 
    } 
     
    return rt; 
} 
/********************************************************************************************************* 
** Function name:           iow 
** 
** Descriptions:            write a value to a dm9000 reg   
** 
** input parameters:        board_info_t *db    ;dm9000 status struct 
**                          reg                 ;reg address of dm9000 
**                          value               ;reg value  
** Returned value:          None  
**          
** Used global variables:   None 
** Calling modules:         None 
** 
** Created by:              Yehaoben 
** Created Date:            2004/02/02 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified date: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static void iow(board_info_t *db, uint8 reg, uint8 value) 
{ 
    unsigned int i; 
     
    outb(reg, db->ioaddr); 
    for(i = 0; iio_data); 
    for(i = 0; i> 8) & 0xff)); 
 
    iow(db, 0xb, 0xa);      /* Issue phyxcer write command */ 
    udelay(500);            /* Wait write complete */ 
    iow(db, 0xb, 0x0);      /* Clear phyxcer write command */ 
} 

/********************************************************************************************************* 
** Function name:           set_PHY_mode 
** 
** Descriptions:            set the PHY device working    
** 
** input parameters:        board_info_t *db    ;dm9000 status struct 
**                             
** Returned value:          None  
**          
** Used global variables:   None 
** Calling modules:         None 
** 
** Created by:              Yehaoben 
** Created Date:            2004/02/02 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified date: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static void set_PHY_mode(board_info_t *db) 
{ 
    unsigned int phy_reg4 = 0x01e1, phy_reg0=0x1000; 
 
    if ( !(db->op_mode & DM9000_AUTO)) 
    { 
        switch(db->op_mode) 
        { 
            case DM9000_10MHD: 
                phy_reg4 = 0x21; /* 10M HALF DUPLEX*/ 
                phy_reg0 = 0x0000;  
                break; 
            case DM9000_10MFD: 
                phy_reg4 = 0x41; /* 10M FULL DUPLEX*/ 
                phy_reg0 = 0x1100;  
                break; 
            case DM9000_100MHD: 
                phy_reg4 = 0x81; /* 100M HALF DUPLEX*/ 
                phy_reg0 = 0x2000;  
                break; 
            case DM9000_100MFD: 
                phy_reg4 = 0x101;/* 100M HALF DUPLEX */  
                phy_reg0 =0x3100;  
                break; 
            default: 
                break; 
        } 
        phy_write(db, 4, phy_reg4); /* Set PHY media mode */ 
        phy_write(db, 0, phy_reg0); /*  Tmp */ 
    } 
 
    iow(db, 0x1e, 0x01);            /* Let GPIO0 output */ 
    iow(db, 0x1f, 0x00);            /* Enable PHY */ 
} 
/********************************************************************************************************* 
** Function name: device_init 
** Descriptions:  device init 
** Input: dev:    information of device 
**         
** Output: 0:     OK 
**         other: errno 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static int device_init(struct net_device *dev)
{
    unsigned long flag;
    uint8   i; 
    board_info_t *db = dev->priv; 
 
    local_irq_save(flag); 
    /* 硬件复位复位 */ 
 
    Hardware_Initial0(); 
    db->ioaddr = IOaddress0; 
    db->io_data = IOaddress0 + 4; 
    /* RESET device */ 
    /*Hardware Reset*/ 
    Hardware_Reset_Clr0(); 
    udelay(500); 
    Hardware_Reset_Set0(); 
    udelay(500); 
    Hardware_Reset_Clr0(); 
    udelay(500);     
 
    /*software reset*/ 
    iow(db, 0, 1);          
    udelay(500);              /* delay 100us */ 
    /* I/O mode */ 
    db->io_mode = ior(db, 0xfe) >> 6; /* ISR bit7:6 keeps I/O mode *///read the io mode (8/16/32bits) 
 
    /* NIC Type: FASTETHER, HOMERUN, LONGRUN */ 
    db->nic_type = FASTETHER_NIC; //identify_nic(db);   //just check for dm9801 or dm9802 
 
    /* GPIO0 on pre-activate PHY */ 
    iow(db, 0x1f, 0x00);       /*REG_1F bit0 activate internal phyxcer*/ 
 
    /* Set PHY */ 
    db->op_mode = DM9000_AUTO;//may set it to be each one of DM9000_PHY_mode type. 
    set_PHY_mode(db); 
 
    /* Init needed register value */ 
    db->reg0 = DM9000_REG00; 
    if ((db->nic_type != FASTETHER_NIC) && (db->op_mode & DM9000_1M_HPNA) )//for dm9801 or dm9802 
    { 
        db->reg0 |= DM9000_EXT_MII; 
    } 
     
    /* User passed argument */ 
    db->reg5 = DM9000_REG05; 
    db->reg8 = DM9000_REG08; 
    db->reg9 = DM9000_REG09; 
    db->rega = DM9000_REG0A; 
 
    /* Program operating register */ 
    iow(db, 0x00, db->reg0);/* DISCARD LONG\CRC_ERR\mutilcast\Promiscuous\WatchDog,Pass Runt,RX not enable */ 
    iow(db, 0x02, 0X14);     /* TX Polling clear *///??????????????enable the PAD //OLD VALUE IS 0X00 
    iow(db, 0x08, 0x3f);     /* Less 3Kb, 600us */ 
    iow(db, 0x09, db->reg9); /* Flow Control : High/Low Water */ 
    iow(db, 0x0a, db->rega); /* Flow Control */ 
    iow(db, 0x2f, 0);        /* Special Mode */ 
    iow(db, 0x01, 0x2c);     /* clear TX status *///clear wakeup status; clear TX2END and TX1END 
    iow(db, 0xfe, 0x0f);         /* Clear interrupt status */ 
 
 
    /* Set address filter table */ 
    for(i = 0; i < 6; i++) 
    { 
        db->nic_mac[i] = MyMacID[i]; 
    } 
 
    for(i = 0; i < 6; i++) 
    { 
        iow(db, 0x10 + i, db->nic_mac[i]);  //将芯片物理地址写入到MAC寄存器 
    } 
 
    /* Activate DM9000 */ 
    iow(db, 0x05, db->reg5 | 1); /* RX enable */ 
    iow(db, 0xff, DM9000_REGFF);     /* Enable TX/RX interrupt mask */ 
    //udelay(5000);  
 
    local_irq_restore(flag); 
 
    return 0;
}
 
/********************************************************************************************************* 
** Function name: net_init 
** Descriptions:  net device init 
** Input: dev:    information of device 
**         
** Output: 0:     OK 
**         other: errno 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 

        static int net_init(struct net_device *dev)
{
    ether_setup(dev); /* assign some of the fields */

    dev->open            = net_open;
    dev->stop            = net_release;
    dev->set_config      = net_config;
    dev->hard_start_xmit = net_tx; 
    dev->set_mac_address = net_set_mac_address;
    dev->flags           &= ~(IFF_LOOPBACK | IFF_MULTICAST); 
    dev->priv            = NetDriverInfo;

    memcpy(dev->dev_addr, MyMacID, dev->addr_len);
    SET_MODULE_OWNER(dev);

    return 0;
}

/********************************************************************************************************* 
** Function name: net_config 
** Descriptions:  config device 
** Input: dev:    information of device 
**        map:    config data 
** Output: 0:     OK 
**         other: errno 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static int net_config(struct net_device *dev, struct ifmap *map)
{
    return -EBUSY;
}
 
/********************************************************************************************************* 
** Function name: net_set_mac_address 
** Descriptions:  set mac address 
** Input: dev:    information of device 
**        addr:   config data 
** Output: 0:     OK 
**         other: errno 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static int net_set_mac_address(struct net_device *dev, void *addr) 
{ 
    struct sockaddr *mac_addr;
    int i; 
 
    mac_addr = addr;
    if (netif_running(dev)) 
    {
        return -EBUSY; 
    }
    /* Set the device copy of the Ethernet address */ 
 
    memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len); 
    
    for(i = 0; i < 6; i++) 
    { 
        MyMacID[i] = mac_addr->sa_data[i]; 
    } 
    device_init(dev); 
 
    return 0;     
} 
 
                           
/********************************************************************************************************* 
** Function name: net_tx 
** Descriptions:  send data to other machine 
** Input: skb:    save data for send 
**        dev:    information of device 
** Output: 0:     OK 
**         other: not OK 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static int net_tx(struct sk_buff *skb, struct net_device *dev)
{
    unsigned long flag;
    int len; 
    u16 *data; 
    board_info_t *db = dev->priv; 
 
    netif_stop_queue(dev); 
 
    len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; 
    data = (u16 *)skb->data;

    len = (len + 1) & (~1); 
    local_irq_save(flag); 

    iow(db, 0xff, 0x80); 
 
    outb(0xf8, db->ioaddr); 
 
    outsw(db->io_data, data, len >> 1); 
 
    iow(db, 0xfc, len & 0xff); 
    iow(db, 0xfd, (len >> 8) & 0xff); 
  
    iow(db, 0x2, 0x1);      /* Cleared after TX complete */ 
         
    /* Re-enable interrupt*/  
    iow(db, 0xff, 0x83); 
            
    dev->trans_start = jiffies; 
    local_irq_restore(flag);
 
    dev_kfree_skb(skb); 
 
    return 0; /* Our simple device can not fail */
}

/********************************************************************************************************* 
** Function name: net_open 
** Descriptions:  open device 
** Input: dev:    information of device 
**        
** Output: 0:     OK 
**         other: not OK 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static int  net_open(struct net_device *dev)
{
    unsigned long flag;
    u32 temp;
 
    if (usage == 0) 
    { 
        local_irq_save(flag);
        temp = inl(PINSEL0);
        PinSel0Save = temp & (0x0f << (8 * 2));
        temp |= (3 << (9 * 2));
        temp &= ~(3 << (8 * 2));
        outl(temp, PINSEL0);
 
        temp = inl(IO0DIR);
        temp |= 1 << 8;
        outl(temp, IO0DIR);

        outl(1 << 8, IOCLR);

        device_init(dev);

        temp = inl(VPBDIV);
        temp = inl(VPBDIV);
        outl(0, VPBDIV);
        outl(inl(EXTMODE) & (~(1 << 3)), EXTMODE);
        outl(inl(EXTPOLAR) | (1 << 3), EXTPOLAR);
        outl(temp, VPBDIV);
        local_irq_restore(flag);
 
        request_irq(dev->irq, net_irq_handle, SA_INTERRUPT | SA_SAMPLE_RANDOM, "eth0", dev); 
    }
    usage++;
    MOD_INC_USE_COUNT;

    netif_start_queue(dev);
 
    return 0;          /* success */
} 

/********************************************************************************************************* 
** Function name: net_release 
** Descriptions:  release device 
** Input: dev:    information of device 
**        
** Output: 0:     OK 
**         other: not OK 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static int  net_release(struct net_device *dev) 
{
    unsigned long flag;
    u32 temp;

    netif_stop_queue(dev);
    MOD_DEC_USE_COUNT;
 
    MOD_DEC_USE_COUNT;
    usage--; 
    if (usage == 0) 
    { 
        local_irq_save(flag);
        temp = inl(PINSEL0);
        temp &= ~(3 << (9 * 2));
        temp |= PinSel0Save; 
        outl(temp, PINSEL0);
        local_irq_restore(flag); 
        free_irq(dev->irq, dev); 
    }
    return(0); 
} 

/********************************************************************************************************* 
** Function name: net_rx 
** Descriptions:  transact receving data 
** Input: dev:    information of device 
**        
** Output: 0:     OK 
**         other: not OK 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static void net_rx(struct net_device *dev, unsigned int length)
{
    struct sk_buff *skb;
    u8 *dec; 
    board_info_t *db = dev->priv; 

    /*
     * The packet has been retrieved from the transmission
     * medium. Build an skb around it, so upper layers can handle it
     */
    skb = dev_alloc_skb(length + 2);
    if (!skb)
    {
        return;
    }
    skb_reserve(skb, 2);                        /* align IP on 16B boundary */  

 
    skb_put(skb, length);
    dec = skb->data; 
 
    insw(db->io_data, dec, length >> 1); 
    if ((length & 0x01) != 0) 
    { 
        dec[length - 1] = inb(db->io_data); 
    }
 
    /* Write metadata, and then pass to the receive level */
    skb->dev = dev;
    skb->protocol = eth_type_trans(skb, dev);
    skb->ip_summed = CHECKSUM_UNNECESSARY; 
 
    netif_rx(skb);
    dev->last_rx = jiffies;
    return;
}

/********************************************************************************************************* 
** Function name: device_rx 
** Descriptions:  device receving data 
** Input: dev:    information of device 
**        
** Output: 0:     OK 
**         other: not OK 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static int device_rx(struct net_device *dev)
{
    unsigned int i, RxStatus, RxLen, GoodPacket, tmplen; 
    unsigned int rxbyte; 
    board_info_t *db = dev->priv; 


    while (1)
    {
        ior(db, 0xf0);          /* Dummy read *///set the address to 0xf0 
        rxbyte = inb(db->io_data);  /* Got most updated data */ 
 
        /* Status check: this byte must be 0 or 1 */ 
        if (rxbyte > DM9000_PKT_RDY) 
        { 
            return -1; 
        } 
 
 
        if (rxbyte != DM9000_PKT_RDY) 
        { 
            break; 
        } 
 
        /* A packet ready now  & Get status/length */ 
        GoodPacket = TRUE; 
        outb(0xf2, db->ioaddr);//set the address to 0xf2 
             
        RxStatus = inw(db->io_data); 
        RxLen    = inw(db->io_data); 
 
        /* Packet Status check */ 
        if (RxLen < 60) 
        { //Runt Packet 
             GoodPacket = FALSE;  
        } 
             
        if (RxLen > DM9000_PKT_MAX) 
        {  //long packet 
           return -1; 
        } 
             
        if (RxStatus & 0xbf00) 
        {//status err 
            GoodPacket = FALSE; 
        } 
 
        /* Move data from DM9000 */ 
             
        if ( GoodPacket  ) 
        { 
            net_rx(dev, RxLen); 
        } 
        else 
        { 
            /* Without buffer or error packet */ 
            tmplen = (RxLen + 1) / 2; 
            for (i = 0; i < tmplen; i++) 
            { 
                inw(db->io_data); 
            } 
        } 
    }

    return 0;
} 

/********************************************************************************************************* 
** Function name: net_tasklet 
** Descriptions:  The tasklet for interrupt handler 
** Input: 
** Output none 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static void net_tasklet(unsigned long data) 
{ 
    struct net_device *dev; 
 
    dev = (struct net_device *)data; 
 
    device_init(dev); 
} 

/********************************************************************************************************* 
** Function name: net_irq_handle 
** Descriptions:  The top-half interrupt handler 
** Input: 
** Output none 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static void net_irq_handle(int irq, void *dev_id, struct pt_regs *regs)
{
    unsigned int int_status; 
    struct net_device *dev;
    board_info_t *db; 
    
    dev = (struct net_device *)dev_id; 
    db = dev->priv;
 
    int_status = ior(db, 0xfe);         /* Got ISR */ 
    iow(db, 0xfe, int_status);          /* Clear ISR status */  
    outl(1 << (dev->irq - 14), EXTINT); 
 
    if (int_status & DM9000_TX_INTR)     //表示发送成功,判断发送状态寄存器TSR,决定是否出错 
    { 
        netif_start_queue(dev); 
    } 
 
    if (int_status & DM9000_RX_INTR)     /* 接收成功       */ 
    { 
        if (device_rx(dev) == -1) 
        { 
            DM9000Dev = dev; 
            tasklet_schedule (&ZLG_net_tasklet); 
        } 
    } 
} 

/********************************************************************************************************* 
** Function name: net_init_module 
** Descriptions:  init driver 
** Input: none 
**        
** Output: 0:     OK 
**         other: not OK 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        int  net_init_module(void)
{
    int  result;

    result = register_netdev(&net_net); 
    if (result < 0)
    {
        printk(KERN_ERR "eth0: error %i registering device \"%s\"\n",
               result, net_net.name);
        return(result); 
    } 

    printk(KERN_ERR "eth0: init OK\n");
    return(0); 
}

/********************************************************************************************************* 
** Function name: net_cleanup 
** Descriptions:  exit driver 
** Input: none 
**        
** Output: 0:     OK 
**         other: not OK 
** Created by:    Chenmingji 
** Created Date:  2005-05-12 
**------------------------------------------------------------------------------------------------------- 
** Modified by: 
** Modified Date:  
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        void net_cleanup(void)
{
    unregister_netdev(&net_net);
}

/*********************************************************************************************************
**                            End Of File
********************************************************************************************************/