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

📄 dm9000.txt

📁 DM9000的网卡驱动模块。开发环境是LINUX+ARM9。
💻 TXT
📖 第 1 页 / 共 2 页
字号:
		}
		printk("%02x\n", ndev->dev_addr[5]);
	}
	return 0;

 release:
	printk("%s: not found (%d).\n", CARDNAME, ret);

	dm9000_release_board(pdev, db);
	kfree(ndev);

	return ret;
}

/**
 *  Open the interface.
 *  The interface is opened whenever "ifconfig" actives it.
 **/
static int
dm9000_open(struct net_device *dev)
{
	board_info_t *db = (board_info_t *) dev->priv;

	PRINTK2("entering dm9000_open\n");

	/* Using the RISING EDGE for this interrupt */
	if (request_irq(dev->irq, dm9000_interrupt, IRQF_SHARED | IRQF_TRIGGER_RISING, dev->name, dev))
		return -EAGAIN;

	/* Initialize DM9000 board */
	dm9000_reset(db);
	dm9000_init_dm9000(dev);

	/* Init driver variable */
        db->runt_length_counter = 0;
	db->long_length_counter = 0;
	db->reset_counter       = 0;

	/* set and active a timer process */
	init_timer(&db->timer);
	db->timer.expires  = DM9000_TIMER_WUT;
	db->timer.data     = (unsigned long)dev;
	db->timer.function = &dm9000_timer;
	add_timer(&db->timer);

	netif_start_queue(dev);

	return 0;
}

/*
 *  Hardware start transmission.
 *  Send a packet to media from the upper layer.
 */
static int
dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	board_info_t *db = (board_info_t *) dev->priv;

	PRINTK3("dm9000_start_xmit\n");

	if (db->tx_pkt_cnt > 1) return 1; 
	
	netif_stop_queue(dev); 

	/* Disable all interrupt */
	iow(db, DM9000_IMR, 0x80);
	
	/* Move data to DM9000 TX RAM */
	writeb(0xf8, db->io_addr);
	
	if (db->io_mode == DM9000_BYTE_MODE) {
		/* Byte mode */
		writesb(db->io_data,skb->data,skb->len);
	} else if (db->io_mode == DM9000_WORD_MODE) {
		/* Word mode */
		writesw(db->io_data, skb->data, (skb->len+1) >> 1);
	} else {
		/* DWord mode */
		writesl(db->io_data,skb->data, (skb->len+3) >> 2);
	} 

	/* TX control: First packet immediately send, second packet queue */
	if (db->tx_pkt_cnt == 0) {
		/* First Packet */
		db->tx_pkt_cnt++;

		/* Set TX length to DM9000 */
		iow(db, DM9000_TXPLL, skb->len & 0xff);
		iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff);

		/* Issue TX polling command */
		iow(db, DM9000_TCR, 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,DM9000_IMR,0x83);
	polling_times=0;
	return 0;
}

/*
 * Stop the interface.
 * The interface is stopped when it is brought.
 */
static int
dm9000_stop(struct net_device *ndev)
{
	board_info_t *db = (board_info_t *) ndev->priv;

	PRINTK1("entering %s\n",__FUNCTION__);

	/* deleted timer */
	del_timer(&db->timer);

	netif_stop_queue(ndev); 

	/* free interrupt */
	free_irq(ndev->irq, ndev);

	/* RESET devie */
	dm9000_shutdown(ndev);
	
	//MOD_DEC_USE_COUNT;

	return 0;
}

/**
 *Process the upper socket ioctl command
 **/
static int dm9000_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
	return 0;
}

/**
 *  Get statistics from driver.
 **/
static struct net_device_stats *
dm9000_get_stats(struct net_device *dev)
{
	board_info_t *db = (board_info_t *) dev->priv;
	return &db->stats;
}

/*
  DM9102 insterrupt handler
  receive the packet to upper layer, free the transmitted packet
*/

static void dm9000_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 irqreturn_t dm9000_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;

	//printk("SBZ: entering %s\n",__FUNCTION__);

	if (!dev) {
		PRINTK1("dm9000_interrupt() without DEVICE arg\n");
		return IRQ_HANDLED;
	}

	/* A real interrupt coming */
	db = (board_info_t *)dev->priv;
	spin_lock(&db->lock);

	reg_save = readb(db->io_addr);

	/* Disable all interrupt */
	iow(db, DM9000_IMR, 0x80); 

	/* Got DM9000 interrupt status */
	int_status = ior(db, 0xfe);		/* Got ISR */
	iow(db, DM9000_ISR, int_status);		/* Clear ISR status */ 

	/* Received the coming packet */
	if (int_status & DM9000_RX_INTR)  {
#if 0
		tasklet_schedule(&dmfe_rx_tasklet);
#else 
		   dm9000_rx(dev);
#endif
	}

	/* Trnasmit Interrupt check */
	if (int_status & DM9000_TX_INTR)
		dm9000_tx_done(dev,db);
		
	/* Re-enable interrupt mask */ 
	iow(db, DM9000_IMR, 0x83);

	/* Restore previous register address */
	writeb(reg_save, db->io_addr); 

	spin_unlock(&db->lock); 

	return IRQ_HANDLED;
}


/*
 *  A periodic timer routine
 *  Dynamic media sense, allocated Rx buffer...
 */
static void
dm9000_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;

	PRINTK3("dm9000_timer()\n");

	/* Save previous register address */
	reg_save = readb(db->io_addr);

	/* 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;
		dm9000_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 */
	writeb(reg_save, db->io_addr);

	/* Set timer again */
	db->timer.expires = DM9000_TIMER_WUT;
	add_timer(&db->timer);
}


/*
  Received a packet and pass to upper layer
*/
static void
dm9000_rx(struct net_device *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;
 	polling_times++;
	/* Check packet ready or not */
	do {
		ior(db,0xf4);
		ior(db,0xf5);
		ior(db, 0xf0);			/* Dummy read */
		rxbyte = readb(db->io_data);
		rxbyte = readb(db->io_data);
		rxbyte = readb(db->io_data);
		rxbyte = readb(db->io_data);
		rxbyte = readb(db->io_data);
		rxbyte = readb(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;
			writeb(0xf2, db->io_addr);
			
			if (db->io_mode == DM9000_BYTE_MODE) {
				/* Byte mode */
				RxStatus = readb(db->io_data)+(readb(db->io_data) << 8);
				RxLen    = readb(db->io_data)+(readb(db->io_data) << 8);
			} else if (db->io_mode == DM9000_WORD_MODE) {
				/* Word mode */
				RxStatus = readw(db->io_data);
				RxLen    = readw(db->io_data);
			} else {
				/* DWord mode */
				tmpdata  = readl(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]=readb(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] = readw(db->io_data);
					} else {
						/* DWord mode */
						tmplen = (RxLen + 3) / 4;
						for (i = 0; i < tmplen; i++)
							((u32 *)rdptr)[i] = readl(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++)
							readb(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++)
							readw(db->io_data);
					} else {
						/* DWord mode */
						tmplen = (RxLen + 3) / 4;
						for (i = 0; i < tmplen; i++)
							readl(db->io_data);
					} 
				}
			}
		}
	}while(rxbyte == DM9000_PKT_RDY && !db->device_wait_reset);
}

/*
 *  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];

	PRINTK1("dm9000_hash_table()");

	/* 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 = crc32(0, (char *)mcptr->dmi_addr, 6) & 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);
	}
}


static int
dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
{
	struct net_device *ndev = platform_get_drvdata(dev);

	if (ndev) {
		if (netif_running(ndev)) {
			netif_device_detach(ndev);
			dm9000_shutdown(ndev);
		}
	}
	return 0;
}

static int
dm9000_drv_resume(struct platform_device *dev)
{
	struct net_device *ndev = platform_get_drvdata(dev);
	board_info_t *db = (board_info_t *) ndev->priv;

	if (ndev) {

		if (netif_running(ndev)) {
			dm9000_reset(db);
			dm9000_init_dm9000(ndev);

			netif_device_attach(ndev);
		}
	}
	return 0;
}

static int
dm9000_drv_remove(struct platform_device *pdev)
{
	struct net_device *ndev = platform_get_drvdata(pdev);

	platform_set_drvdata(pdev, NULL);

	unregister_netdev(ndev);
	dm9000_release_board(pdev, (board_info_t *) ndev->priv);
	kfree(ndev);		/* free device structure */

	PRINTK1("clean_module() exit\n");

	return 0;
}

static struct platform_driver dm9000_driver = {
	.driver	= {
		.name    = "dm9000",
		.owner	 = THIS_MODULE,
	},
	.probe   = dm9000_probe,
	.remove  = dm9000_drv_remove,
	.suspend = dm9000_drv_suspend,
	.resume  = dm9000_drv_resume,
};

static int __init
dm9000_init(void)
{
	printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME);

	return platform_driver_register(&dm9000_driver);	/* search board and register */
}

static void __exit
dm9000_cleanup(void)
{
	platform_driver_unregister(&dm9000_driver);
}

module_init(dm9000_init);
module_exit(dm9000_cleanup);

MODULE_AUTHOR("Sascha Hauer, Ben Dooks");
MODULE_DESCRIPTION("Davicom DM9000 network driver");
MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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