📄 dm9000x.c
字号:
/* Set TX length to DM9000 */
iow(db, 0xfc, skb->len & 0xff);
iow(db, 0xfd, (skb->len >> 8) & 0xff);
/* Issue TX polling command */
iow(db, 0x2, 0x1); /* Cleared after TX complete */
dev->trans_start = jiffies; /* saved the time stamp */
} else {
/* Second packet */
db->tx_pkt_cnt++;
db->queue_pkt_len = skb->len;
}
/* free this SKB */
dev_kfree_skb(skb);
/* Re-enable resource check */
if (db->tx_pkt_cnt == 1)
netif_wake_queue(dev);
/* Re-enable interrupt*/
iow(db,0xff,0x83);
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, 0x1f, 0x01); /* Power-Down PHY */
iow(db, 0xff, 0x80); /* Disable all interrupt */
iow(db, 0x05, 0x00); /* Disable RX */
MOD_DEC_USE_COUNT;
/* Dump Statistic counter */
#if FALSE
printk("\nRX FIFO OVERFLOW %lx\n", db->stats.rx_fifo_errors);
printk("RX CRC %lx\n", db->stats.rx_crc_errors);
printk("RX LEN Err %lx\n", db->stats.rx_length_errors);
printk("RX LEN < 64byte %x\n", db->runt_length_counter);
printk("RX LEN > 1514byte %x\n", db->long_length_counter);
printk("RESET %x\n", db->reset_counter);
printk("RESET: TX Timeout %x\n", db->reset_tx_timeout);
printk("RESET: RX Status Wrong %x\n", db->reset_rx_status);
#endif
return 0;
}
/*
DM9102 insterrupt handler
receive the packet to upper layer, free the transmitted packet
*/
void dmfe_tx_done(struct net_device *dev, board_info_t *db)
{
int tx_status = ior(db, 0x01); /* Got TX status */
if (tx_status & 0xc) {
/* One packet sent complete */
db->tx_pkt_cnt--;
dev->trans_start = 0;
db->stats.tx_packets++;
/* Queue packet check & send */
if (db->tx_pkt_cnt > 0) {
iow(db, 0xfc, db->queue_pkt_len & 0xff);
iow(db, 0xfd, (db->queue_pkt_len >> 8) & 0xff);
iow(db, 0x2, 0x1);
dev->trans_start = jiffies;
}
netif_wake_queue(dev);
}
}
static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
board_info_t *db;
int int_status;
u8 reg_save;
DMFE_DBUG(0, "dmfe_interrupt()", 0);
if (!dev) {
DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0);
return;
}
/* A real interrupt coming */
db = (board_info_t *)dev->priv;
spin_lock(&db->lock);
/* Save previous register address */
reg_save = inb(db->ioaddr);
/* Disable all interrupt */
iow(db, 0xff, 0x80);
/* Got DM9000 interrupt status */
int_status = ior(db, 0xfe); /* Got ISR */
iow(db, 0xfe, int_status); /* Clear ISR status */
/* Received the coming packet */
if (int_status & DM9000_RX_INTR)
tasklet_schedule(&dmfe_rx_tasklet);
/* Trnasmit Interrupt check */
if (int_status & DM9000_TX_INTR)
dmfe_tx_done(dev,db);
/* Re-enable interrupt mask */
iow(db, 0xff, 0x83);
/* Restore previous register address */
outb(reg_save, db->ioaddr);
spin_unlock(&db->lock);
}
/*
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;
DMFE_DBUG(0, "dmfe_get_stats", 0);
return &db->stats;
}
/*
Process the upper socket ioctl command
*/
static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
return 0;
}
/*
A periodic timer routine
Dynamic media sense, allocated Rx buffer...
*/
static void dmfe_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
board_info_t *db = (board_info_t *)dev->priv;
u8 reg_save, tmp_reg;
DMFE_DBUG(0, "dmfe_timer()", 0);
/* Save previous register address */
reg_save = inb(db->ioaddr);
/* TX timeout check */
if (dev->trans_start&&((jiffies-dev->trans_start)>DMFE_TX_TIMEOUT)) {
db->device_wait_reset = 1;
db->reset_tx_timeout++;
}
/* DM9000 dynamic RESET check and do */
if (db->device_wait_reset) {
netif_stop_queue(dev);
db->reset_counter++;
db->device_wait_reset = 0;
dev->trans_start = 0;
dmfe_init_dm9000(dev);
netif_wake_queue(dev);
}
/* Auto Sense Media mode policy:
FastEthernet NIC: don't need to do anything.
Media Force mode: don't need to do anything.
HomeRun/LongRun NIC and AUTO_Mode:
INT_MII not link, select EXT_MII
EXT_MII not link, select INT_MII
*/
if ( (db->nic_type != FASTETHER_NIC) && (db->op_mode & DM9000_AUTO) ) {
tmp_reg = ior(db, 0x01); /* Got link status */
if ( !(tmp_reg & 0x40) ) { /* not link */
db->reg0 ^= 0x80;
iow(db, 0x00, db->reg0);
}
}
/* Restore previous register address */
outb(reg_save, db->ioaddr);
/* Set timer again */
db->timer.expires = DMFE_TIMER_WUT;
add_timer(&db->timer);
}
/*
Received a packet and pass to upper layer
*/
static void dmfe_packet_receive(unsigned long unused)
{
struct net_device *dev = dmfe_dev;
board_info_t *db = (board_info_t *)dev->priv;
struct sk_buff *skb;
u8 rxbyte, *rdptr;
u16 i, RxStatus, RxLen, GoodPacket, tmplen;
u32 tmpdata;
/* Check packet ready or not */
do {
ior(db, 0xf0); /* Dummy read */
rxbyte = inb(db->io_data); /* Got most updated data */
/* Status check: this byte must be 0 or 1 */
if (rxbyte > DM9000_PKT_RDY) {
iow(db, 0x05, 0x00); /* Stop Device */
iow(db, 0xfe, 0x80); /* Stop INT request */
db->device_wait_reset = TRUE;
db->reset_rx_status++;
}
/* packet ready to receive check */
if (rxbyte == DM9000_PKT_RDY) {
/* A packet ready now & Get status/length */
GoodPacket = TRUE;
outb(0xf2, db->ioaddr);
if (db->io_mode == DM9000_BYTE_MODE) {
/* Byte mode */
RxStatus = inb(db->io_data)+(inb(db->io_data) << 8);
RxLen = inb(db->io_data)+(inb(db->io_data) << 8);
} else if (db->io_mode == DM9000_WORD_MODE) {
/* Word mode */
RxStatus = inw(db->io_data);
RxLen = inw(db->io_data);
} else {
/* DWord mode */
tmpdata = inl(db->io_data);
RxStatus = tmpdata;
RxLen = tmpdata >> 16;
}
/* Packet Status check */
if (RxLen < 0x40) {
GoodPacket = FALSE;
db->runt_length_counter++;
}
if (RxLen > DM9000_PKT_MAX) {
printk("<DM9000> RST: RX Len:%x\n", RxLen);
db->device_wait_reset = TRUE;
db->long_length_counter++;
}
if (RxStatus & 0xbf00) {
GoodPacket = FALSE;
if (RxStatus & 0x100)
db->stats.rx_fifo_errors++;
if (RxStatus & 0x200)
db->stats.rx_crc_errors++;
if (RxStatus & 0x8000)
db->stats.rx_length_errors++;
}
/* Move data from DM9000 */
if (!db->device_wait_reset) {
if ( GoodPacket && ((skb = dev_alloc_skb(RxLen + 4)) != NULL ) ) {
skb->dev = dev;
skb_reserve(skb, 2);
rdptr = (u8 *) skb_put(skb, RxLen-4);
/* Read received packet from RX SARM */
if (db->io_mode == DM9000_BYTE_MODE) {
/* Byte mode */
for (i=0; i<RxLen; i++)
rdptr[i]=inb(db->io_data);
} else if (db->io_mode == DM9000_WORD_MODE) {
/* Word mode */
tmplen = (RxLen + 1) / 2;
for (i = 0; i < tmplen; i++)
((u16 *)rdptr)[i] = inw(db->io_data);
} else {
/* DWord mode */
tmplen = (RxLen + 3) / 4;
for (i = 0; i < tmplen; i++)
((u32 *)rdptr)[i] = inl(db->io_data);
}
/* Pass to upper layer */
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
db->stats.rx_packets++;
} else {
/* Without buffer or error packet */
if (db->io_mode == DM9000_BYTE_MODE) {
/* Byte mode */
for (i = 0; i < RxLen; i++)
inb(db->io_data);
} else if (db->io_mode == DM9000_WORD_MODE) {
/* Word mode */
printk("0");
tmplen = (RxLen + 1) / 2;
for (i = 0; i < tmplen; i++)
inw(db->io_data);
} else {
/* DWord mode */
tmplen = (RxLen + 3) / 4;
for (i = 0; i < tmplen; i++)
inl(db->io_data);
}
}
}
}
}while(rxbyte == DM9000_PKT_RDY && !db->device_wait_reset);
}
/*
Read a word data from SROM
*/
static u16 read_srom_word(board_info_t *db, int offset)
{
iow(db, 0xc, offset);
iow(db, 0xb, 0x4);
udelay(200);
iow(db, 0xb, 0x0);
return (ior(db, 0xd) + (ior(db, 0xe) << 8) );
}
/*
Set DM9000 multicast address
*/
static void dm9000_hash_table(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
struct dev_mc_list *mcptr = dev->mc_list;
int mc_cnt = dev->mc_count;
u32 hash_val;
u16 i, oft, hash_table[4];
DMFE_DBUG(0, "dm9000_hash_table()", 0);
/* Set Node address */
for (i = 0, oft = 0x10; i < 6; i++, oft++)
iow(db, oft, dev->dev_addr[i]);
/* Clear Hash Table */
for (i = 0; i < 4; i++)
hash_table[i] = 0x0;
/* broadcast address */
hash_table[3] = 0x8000;
/* the multicast address in Hash Table : 64 bits */
for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
hash_val = cal_CRC((char *)mcptr->dmi_addr, 6, 0) & 0x3f;
hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
}
/* Write the hash table to MAC MD table */
for (i = 0, oft = 0x16; i < 4; i++) {
iow(db, oft++, hash_table[i] & 0xff);
iow(db, oft++, (hash_table[i] >> 8) & 0xff);
}
}
/*
Calculate the CRC valude of the Rx packet
flag = 1 : return the reverse CRC (for the received packet CRC)
0 : return the normal CRC (for Hash Table index)
*/
static unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
{
u32 crc = ether_crc_le(Len, Data);
if (flag)
return ~crc;
return crc;
}
/*
Read a byte from I/O port
*/
static u8 ior(board_info_t *db, int reg)
{
outb(reg, db->ioaddr);
return inb(db->io_data);
}
/*
Write a byte to I/O port
*/
static void iow(board_info_t *db, int reg, u8 value)
{
outb(reg, db->ioaddr);
outb(value, db->io_data);
}
/*
Read a word from phyxcer
*/
static u16 phy_read(board_info_t *db, int reg)
{
/* Fill the phyxcer register into REG_0C */
iow(db, 0xc, DM9000_PHY | reg);
iow(db, 0xb, 0xc); /* Issue phyxcer read command */
udelay(100); /* Wait read complete */
iow(db, 0xb, 0x0); /* Clear phyxcer read command */
/* The read data keeps on REG_0D & REG_0E */
return ( ior(db, 0xe) << 8 ) | ior(db, 0xd);
}
/*
Write a word to phyxcer
*/
static void phy_write(board_info_t *db, int reg, u16 value)
{
/* Fill the phyxcer register into REG_0C */
iow(db, 0xc, DM9000_PHY | reg);
/* Fill the written data into REG_0D & REG_0E */
iow(db, 0xd, (value & 0xff));
iow(db, 0xe, ( (value >> 8) & 0xff));
iow(db, 0xb, 0xa); /* Issue phyxcer write command */
udelay(500); /* Wait write complete */
iow(db, 0xb, 0x0); /* Clear phyxcer write command */
}
#ifdef MODULE
MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
MODULE_DESCRIPTION("Davicom DM9000 ISA/uP Fast Ethernet Driver");
MODULE_PARM(debug, "i");
MODULE_PARM(mode, "i");
MODULE_PARM(reg5, "i");
MODULE_PARM(reg9, "i");
MODULE_PARM(rega, "i");
MODULE_PARM(nfloor, "i");
/* Description:
when user used insmod to add module, system invoked init_module()
to initilize and register.
*/
int init_module(void)
{
DMFE_DBUG(0, "init_module() ", debug);
if (debug)
dmfe_debug = debug; /* set debug flag */
switch(mode) {
case DM9000_10MHD:
case DM9000_100MHD:
case DM9000_10MFD:
case DM9000_100MFD:
case DM9000_1M_HPNA:
media_mode = mode;
break;
default:
media_mode = DM9000_AUTO;
}
nfloor = (nfloor > 15) ? 0:nfloor;
return dmfe_probe(0); /* search board and register */
}
/* Description:
when user used rmmod to delete module, system invoked clean_module()
to un-register DEVICE.
*/
void cleanup_module(void)
{
board_info_t * db;
DMFE_DBUG(0, "clean_module()", 0);
unregister_netdev(dmfe_dev);
db = (board_info_t *)dmfe_dev->priv;
release_region(dmfe_dev->base_addr, 2);
kfree(db); /* free board information */
kfree(dmfe_dev); /* free device structure */
DMFE_DBUG(0, "clean_module() exit", 0);
}
#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -