Davicom公司DM9000A和DM9010 ISA NIC 以太網(wǎng)驅(qū)動(dòng)分析
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 */
#if defined(CHECKSUM)
iow(db, DM9KS_TCCR, 0x07); /* TX UDP/TCP/IP checksum enable */
iow(db, DM9KS_RCSR, 0x02); /*Receive checksum enable */
#endif
#if defined(ETRANS)
iow(db, DM9KS_ETXCSR, 0x83);
#endif
/* Set address filter table */
dm9000_hash_table(dev);
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;
outb(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++)
outb((data_ptr[i] 0xff), db->io_data);
break;
case DM9KS_WORD_MODE:
tmplen = (skb->len + 1) / 2;
for (i = 0; i tmplen; i++)
outw(((u16 *)data_ptr)[i], db->io_data);
break;
case DM9KS_DWORD_MODE:
tmplen = (skb->len + 3) / 4;
for (i = 0; i tmplen; i++)
outl(((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;
DMFE_DBUG(0, dmfe_stop, 0);
/* 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 */
#if FALSE
printk(nRX FIFO OVERFLOW %lxn, db->stats.rx_fifo_errors);
printk(RX CRC %lxn, db->stats.rx_crc_errors);
printk(RX LEN Err %lxn, db->stats.rx_length_errors);
printk(RESET %xn, db->reset_counter);
printk(RESET: TX Timeout %xn, db->reset_tx_timeout);
printk(g_TX_nsr %xn, g_TX_nsr);
#endif
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;
DMFE_DBUG(0, dmfe_tx_done(), 0);
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
pid控制相關(guān)文章:pid控制原理
評(píng)論