⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dm9000.c

📁 开发板用的事博创的arm2410-s
💻 C
📖 第 1 页 / 共 3 页
字号:
        db->op_mode = media_mode;
        set_PHY_mode(db);
        /* Program operating register */
        iow(db, DM9KS_NCR, 0);
        iow(db, DM9KS_TCR, 0);  /* TX Polling clear */
        iow(db, DM9KS_BPTR, 0x3f); /* Less 3kb, 600us */
        iow(db, DM9KS_SMCR, 0);  /* Special Mode */
        iow(db, DM9KS_NSR, 0x2c); /* clear TX status */
        iow(db, DM9KS_ISR, 0x0f);  /* Clear interrupt status */
        /* Added by jackal at 03/29/2004 */
 
        /* Set address filter table */
        dm9000_hash_table(dev);
        /* Activate DM9000A/DM9010 */
        iow(db, DM9KS_RXCR, DM9KS_REG05 | 1); /* RX enable */
        iow(db, DM9KS_IMR, DM9KS_REGFF);  // Enable TX/RX interrupt mask
 
        /* Init Driver variable */
        db->tx_pkt_cnt   = 0;
                
        netif_carrier_on(dev);
        spin_lock_init(&db->lock);
}
/*
  Hardware start transmission.
  Send a packet to media from the upper layer.
*/
static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
        board_info_t *db = (board_info_t *)dev->priv;
        char * data_ptr;
        int i, tmplen;
        if(db->Speed == 10)
                {if (db->tx_pkt_cnt >= 1) return 1;}
        else
                {if (db->tx_pkt_cnt >= 2) return 1;}
        
        /* packet counting */
        db->tx_pkt_cnt++;
        db->stats.tx_packets++;
        db->stats.tx_bytes+=skb->len;
        if (db->Speed == 10)
                {if (db->tx_pkt_cnt >= 1) netif_stop_queue(dev);}
        else
                {if (db->tx_pkt_cnt >= 2) netif_stop_queue(dev);}
        /* Disable all interrupt */
        iow(db, DM9KS_IMR, DM9KS_DISINTR);
        /* Set TX length to reg. 0xfc & 0xfd */
        iow(db, DM9KS_TXPLL, (skb->len & 0xff));
        iow(db, DM9KS_TXPLH, (skb->len >> 8) & 0xff);
        /* Move data to TX SRAM */
        data_ptr = (char *)skb->data;
        
        PUTB(DM9KS_MWCMD, db->io_addr); // Write data into SRAM trigger
        switch(db->io_mode)
        {
                case DM9KS_BYTE_MODE:
                        for (i = 0; i < skb->len; i++)
                                PUTB((data_ptr[i] & 0xff), db->io_data);
                        break;
                case DM9KS_WORD_MODE:
                        tmplen = (skb->len + 1) / 2;
                        for (i = 0; i < tmplen; i++)
                                 PUTW(((u16 *)data_ptr)[i], db->io_data);
                         break;
                 case DM9KS_DWORD_MODE:
                         tmplen = (skb->len + 3) / 4;   
                        for (i = 0; i< tmplen; i++)
                                PUTL(((u32 *)data_ptr)[i], db->io_data);
                        break;
        }
        
#if !defined(ETRANS)
        /* Issue TX polling command */
        iow(db, DM9KS_TCR, 0x1); /* Cleared after TX complete*/
#endif
        /* Saved the time stamp */
        dev->trans_start = jiffies;
        db->cont_rx_pkt_cnt =0;
        /* Free this SKB */
        dev_kfree_skb(skb);
        /* Re-enable interrupt */
        iow(db, DM9KS_IMR, DM9KS_REGFF);
        return 0;
}
/*
  Stop the interface.
  The interface is stopped when it is brought.
*/
static int dmfe_stop(struct net_device *dev)
{
        board_info_t *db = (board_info_t *)dev->priv;
        
        /* deleted timer */
        del_timer(&db->timer);
        netif_stop_queue(dev); 
        /* free interrupt */
        free_irq(dev->irq, dev);
        /* RESET devie */
        phy_write(db, 0x00, 0x8000); /* PHY RESET */
        iow(db, DM9KS_GPR, 0x01);  /* Power-Down PHY */
        iow(db, DM9KS_IMR, DM9KS_DISINTR); /* Disable all interrupt */
        iow(db, DM9KS_RXCR, 0x00); /* Disable RX */
        /* Dump Statistic counter */
        return 0;
}
static void dmfe_tx_done(unsigned long unused)
{
        struct net_device *dev = dmfe_dev;
        board_info_t *db = (board_info_t *)dev->priv;
        int  nsr;
               
        nsr = ior(db, DM9KS_NSR);
        if(nsr & 0x04) db->tx_pkt_cnt--;
        if(nsr & 0x08) db->tx_pkt_cnt--;
        if (db->tx_pkt_cnt < 0)
        {
                printk("[dmfe_tx_done] tx_pkt_cnt ERROR!!\n");
                db->tx_pkt_cnt =0;
        }
        if (db->Speed == 10)
                {if(db->tx_pkt_cnt < 1 ) netif_wake_queue(dev);}
        else  
                {if(db->tx_pkt_cnt < 2 ) netif_wake_queue(dev);}
        
        return;
}
/*
  DM9000 insterrupt handler
  receive the packet to upper layer, free the transmitted packet
*/
static irqreturn_t dmfe_interrupt(int irq, void *dev_id)
{
        struct net_device *dev = dev_id;
        board_info_t *db;
        int int_status,i;
        u8 reg_save;
        /* A real interrupt coming */
        db = (board_info_t *)dev->priv;
        spin_lock(&db->lock);
        /* Save previous register address */
        reg_save = GETB(db->io_addr);
        /* Disable all interrupt */
        iow(db, DM9KS_IMR, DM9KS_DISINTR); 
        /* Got DM9000A/DM9010 interrupt status */
        int_status = ior(db, DM9KS_ISR);  /* Got ISR */
        iow(db, DM9KS_ISR, int_status);  /* Clear ISR status */ 
        /* Link status change */
        if (int_status & DM9KS_LINK_INTR) 
        {
                netif_stop_queue(dev);
                for(i=0; i<500; i++) /*wait link OK, waiting time =0.5s */
                {
                        phy_read(db,0x1);
                        if(phy_read(db,0x1) & 0x4) /*Link OK*/
                        {
                                /* wait for detected Speed */
                                for(i=0; i<200;i++)
                                        udelay(1000);
                                /* set media speed */
                                if(phy_read(db,0)&0x2000) db->Speed =100;
                                else db->Speed =10;
                                break;
                        }
                        udelay(1000);
                }
                netif_wake_queue(dev);
                //printk("[INTR]i=%d speed=%d\n",i, (int)(db->Speed)); 
        }
        /* Received the coming packet */
        if (int_status & DM9KS_RX_INTR) 
                dmfe_packet_receive(dev);
        /* Trnasmit Interrupt check */
        if (int_status & DM9KS_TX_INTR)
                dmfe_tx_done(0);
        
        if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT)
        {
                iow(db, DM9KS_IMR, 0xa2);
        }
        else
        {
                /* Re-enable interrupt mask */ 
                iow(db, DM9KS_IMR, DM9KS_REGFF);
        }
        
        /* Restore previous register address */
        PUTB(reg_save, db->io_addr); 
        spin_unlock(&db->lock); 
        return IRQ_HANDLED;
}
/*
  Get statistics from driver.
*/
static struct net_device_stats * dmfe_get_stats(struct net_device *dev)
{
        board_info_t *db = (board_info_t *)dev->priv;
        return &db->stats;
}
/*
  Process the upper socket ioctl command
*/
static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
        return 0;
}
/* Our watchdog timed out. Called by the networking layer */
static void
dmfe_timeout(struct net_device *dev)
{
        board_info_t *db = (board_info_t *)dev->priv;
        printk("TX time-out -- dmfe_timeout().\n");
        db->reset_tx_timeout++;
        db->stats.tx_errors++;
        dmfe_reset(dev);
        
}
static void dmfe_reset(struct net_device * dev)
{
        board_info_t *db = (board_info_t *)dev->priv;
        u8 reg_save;
        int i;
        /* Save previous register address */
        reg_save = GETB(db->io_addr);
        netif_stop_queue(dev); 
        db->reset_counter++;
        dmfe_init_dm9000(dev);
        
        db->Speed =10;
        for(i=0; i<1000; i++) /*wait link OK, waiting time=1 second */
        {
                if(phy_read(db,0x1) & 0x4) /*Link OK*/
                {
                        if(phy_read(db,0)&0x2000) db->Speed =100;
                        else db->Speed =10;
                        break;
                }
                udelay(1000);
        }
        
        netif_wake_queue(dev);
        
        /* Restore previous register address */
        PUTB(reg_save, db->io_addr);
}
/*
  A periodic timer routine
*/
static void dmfe_timer(unsigned long data)
{
        struct net_device * dev = (struct net_device *)data;
        board_info_t *db = (board_info_t *)dev->priv;
             
        if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT)
        {
                db->cont_rx_pkt_cnt=0;
                iow(db, DM9KS_IMR, DM9KS_REGFF);
        }
        /* Set timer again */
        db->timer.expires = DMFE_TIMER_WUT;
        add_timer(&db->timer);
        
        return;
}
#if !defined(CHECKSUM)
#define check_rx_ready(a) ((a) == 0x01)
#else
inline u8 check_rx_ready(u8 rxbyte)
{
        if (!(rxbyte & 0x01))
                return 0;
        return ((rxbyte >> 4) | 0x01);
}
#endif
/*
  Received a packet and pass to upper layer
*/
static void dmfe_packet_receive(struct net_device *dev)
{
        board_info_t *db = (board_info_t *)dev->priv;
        struct sk_buff *skb;
        u8 rxbyte, val;
        u16 i, GoodPacket, tmplen = 0, MDRAH, MDRAL;
        u32 tmpdata;
        rx_t rx;
        u16 * ptr = (u16*)&rx;
        u8* rdptr;
        do {
                /*store the value of Memory Data Read address register*/
                MDRAH=ior(db, DM9KS_MDRAH);
                MDRAL=ior(db, DM9KS_MDRAL);
                
                ior(db, DM9KS_MRCMDX);  /* Dummy read */
                rxbyte = GETB(db->io_data); /* Got most updated data */
                /* packet ready to receive check */
                if(!(val = check_rx_ready(rxbyte))) break;
                /* A packet ready now  & Get status/length */
                GoodPacket = TRUE;
                PUTB(DM9KS_MRCMD, db->io_addr);
                /* Read packet status & length */
                switch (db->io_mode) 
                        {
                          case DM9KS_BYTE_MODE: 
                                     *ptr = GETB(db->io_data) + 
                                               (GETB(db->io_data) << 8);
                                    *(ptr+1) = GETB(db->io_data) + 
                                            (GETB(db->io_data) << 8);
                                    break;
                          case DM9KS_WORD_MODE:
                                    *ptr = GETW(db->io_data);
                                    *(ptr+1)    = GETW(db->io_data);
                                    break;
                          case DM9KS_DWORD_MODE:
                                    tmpdata  = GETL(db->io_data);
                                    *ptr = tmpdata;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -