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

📄 dm9000x.c

📁 davicom公司的10/100M以太网接口芯片dm9000在Linux下的驱动源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	//iow(db, 0x09, 0x38);		/* Less 3Kb, 200us */
	//iow(db, 0x0a, 0x21);		/* Less 3Kb, 200us */
//Marked by Spenser 10/02/2003
//	iow(db, 0x1e, 0x03);			/* Let GPIO0/GPIO1 output */
//	iow(db, 0x1f, 0x01);			/* Enable PHY */
	
}

/*
	Init HomeRun DM9801
*/
static void program_dm9801(board_info_t *db, u16 HPNA_rev)
{
	__u16 reg16, reg17, reg24, reg25;

	if ( !nfloor ) 
		nfloor = DM9801_NOISE_FLOOR;

	reg16 = phy_read(db, 16);
	reg17 = phy_read(db, 17);
	reg24 = phy_read(db, 24);
	reg25 = phy_read(db, 25);

	switch(HPNA_rev) {
		case 0xb900: /* DM9801 E3 */
			reg16 |= 0x1000;
			reg25 = ( (reg24 + nfloor) & 0x00ff) | 0xf000;
			break;
		case 0xb901: /* DM9801 E4 */
			reg25 = ( (reg24 + nfloor) & 0x00ff) | 0xc200;
			reg17 = (reg17 & 0xfff0) + nfloor + 3;
			break;
		case 0xb902: /* DM9801 E5 */
		case 0xb903: /* DM9801 E6 */
		default:
			reg16 |= 0x1000;
			reg25 = ( (reg24 + nfloor - 3) & 0x00ff) | 0xc200;
			reg17 = (reg17 & 0xfff0) + nfloor;
	}

	phy_write(db, 16, reg16);
	phy_write(db, 17, reg17);
	phy_write(db, 25, reg25);
}

/*
	Init LongRun DM9802
*/
static void program_dm9802(board_info_t *db)
{
	__u16 reg25;

	if ( !nfloor )
		nfloor = DM9802_NOISE_FLOOR;

	reg25 = phy_read(db, 25);
	reg25 = (reg25 & 0xff00) + nfloor;
	phy_write(db, 25, reg25);
}

/* 
	Identify NIC type
*/
static void identify_nic(board_info_t *db)
{
	u16 phy_reg3;
	iow(db, 0, DM9000_EXT_MII);
	phy_reg3 = phy_read(db, 3);

	switch(phy_reg3 & 0xfff0) {
		
		case 0xb900:
			
			if (phy_read(db, 31) == 0x4404) {
				db->nic_type =  HOMERUN_NIC;
				program_dm9801(db, phy_reg3);
			} else {
				db->nic_type = LONGRUN_NIC;
				program_dm9802(db);
			}
			break;

		default: db->nic_type = FASTETHER_NIC; 
			 break;

	}
	
	iow(db, 0, DM9000_INT_MII);	
}

/* 
	Initilize dm9000 board
*/
static void dmfe_init_dm9000(struct net_device *dev)
{
	board_info_t *db = (board_info_t *)dev->priv;
	DMFE_DBUG(0, "dmfe_init_dm9000()", 0);

	/* set the internal PHY power-on, GPIOs normal, and wait 2ms */
	iow(db, 0x1F, 0);	/* GPR (reg_1Fh)bit GPIO0=0 pre-activate PHY */
	udelay(20);		/* wait 2ms for PHY power-on ready */

	/* do a software reset and wait 20us */
//	iow(db, 0, 1);		/* NCR (reg_00h) bit[0] RST=1, reset on */
//	iow(db, 0, 3);		/* NCR (reg_00h) bit[0] RST=1 & Loopback=1, reset on. Added by SPenser */
	iow(db, DM9000_NCR, 3);
	udelay(20);		/* wait 20us at least for software reset ok */
	iow(db, 0, 3);		/* NCR (reg_00h) bit[0] RST=1 & Loopback=1, reset on. Added by SPenser */
	udelay(20);		/* wait 20us at least for software reset ok */

// Marked by Spenser
	/* set GPIO0=1 then GPIO0=0 to turn off and on the internal PHY */
	iow(db, 0x1F, 1);	/* GPR (reg_1Fh) bit[0] GPIO0=1 turn-off PHY */
	iow(db, 0x1F, 0);	/* GPR (reg_1Fh) bit[0] GPIO0=0 activate PHY */
	udelay(4000);		/* wait 4ms linking PHY (AUTO sense) if RX/TX */

	/* I/O mode */
	db->io_mode = ior(db, 0xfe) >> 6; /* ISR bit7:6 keeps I/O mode */

	/* NIC Type: FASTETHER, HOMERUN, LONGRUN */
	identify_nic(db);	

	/* Set PHY */
	db->op_mode = media_mode;
	set_PHY_mode(db);

	/* Init needed register value */
	db->reg0 = DM9000_NCR;
	if ( (db->nic_type != FASTETHER_NIC) && (db->op_mode & DM9000_1M_HPNA) )
		db->reg0 |= DM9000_EXT_MII;
	
	/* User passed argument */
	db->reg5 = reg5;
	db->reg8 = reg8;
	db->reg9 = reg9;
	db->rega = rega;

	/* Program operating register */
	//iow(db, 0x00, db->reg0);
	iow(db, 0x00, 0x08);
	iow(db, 0x02, 0);		/* TX Polling clear */
	iow(db, 0x2f, 0);		/* Special Mode */
	iow(db, 0x01, 0x2c);	/* clear TX status */
	iow(db, 0xfe, 0x0f); 	/* Clear interrupt status */
	iow(db, 0x08, 0x37);
	iow(db, 0x09, 0x38);	/* Flow control: High/Low water */
	iow(db, 0x0a, 0x29);	/* flow control */

	/* Set address filter table */
	dm9000_hash_table(dev);

	/* Activate DM9000 */
	iow(db, 0x05, db->reg5 | 1);	/* RX enable */
	iow(db, 0xff, DM9000_REGFF); 	/* Enable TX/RX interrupt mask */
 
	/* Init Driver variable */
	db->link_failed 	= 1;
	db->tx_pkt_cnt 		= 0;
	db->queue_pkt_len 	= 0;
	dev->trans_start 	= 0;
	
	netif_carrier_on(dev);
	spin_lock_init(&db->lock);

}

/* 
	Reset dm9000 board due to 32bits mode while excess collision or late collision.
*/

static void dmfe_reset_dm9000(struct net_device *dev)
{
	board_info_t *db = (board_info_t *)dev->priv;
	DMFE_DBUG(0, "dmfe_reset_dm9000()", 0);

	iow(db, 0, 1);		/* NCR (reg_00h) bit[0] RST=1, reset on. Added by SPenser */
	udelay(1);		/* wait 20us at least for software reset ok */
	iow(db, 0, 0);
	
	/* software reset 2 times */
	iow(db, DM9000_NCR, 3);
	udelay(20);
	iow(db, DM9000_NCR, 3);
	udelay(20);

	/* Program operating register */
	iow(db, 0x00, db->reg0);
	iow(db, 0x02, 0);		/* TX Polling clear */
	iow(db, 0x08, 0x3f);	/* Less 3Kb, 200us */
	iow(db, 0x09, 0x38);	/* Flow Control : High/Low Water */
	iow(db, 0x0a, 0x29);	/* TX Pause packet */
	iow(db, 0x2f, 0);		/* Special Mode */
	iow(db, 0x01, 0x2c);		/* clear TX status */
	iow(db, 0xfe, 0x0f); 		/* Clear interrupt status */

	/* Activate DM9000 */
	iow(db, 0x05, db->reg5 | 1);	/* RX enable */
	iow(db, 0xff, DM9000_REGFF); 	/* Enable TX/RX interrupt mask */
 
	/* Init Driver variable */
	db->link_failed 	= 1;
	db->tx_pkt_cnt 		= 0;
	db->queue_pkt_len 	= 0;
	dev->trans_start 	= 0;

	netif_carrier_on(dev);

} 

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

	DMFE_DBUG(0, "dmfe_start_xmit", 0);

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

	/* Disable all interrupt */
	iow(db, 0xff, 0x80);
	
	/* Move data to DM9000 TX RAM */
	data_ptr = (char *)skb->data;
	outb(0xf8, db->ioaddr);
	
	db->sent_pkt_len = skb->len;
		
	if (db->io_mode == DM9000_BYTE_MODE) {
		/* Byte mode */
		for (i = 0; i < skb->len; i++)
			outb((data_ptr[i] & 0xff), db->io_data);
	} else if (db->io_mode == DM9000_WORD_MODE) {
		/* Word mode */
		tmplen = (skb->len + 1) / 2;
		for (i = 0; i < tmplen; i++)
         		outw(((u16 *)data_ptr)[i], db->io_data);
	} else {
		/* DWord mode */
		tmplen = (skb->len + 3) / 4;			
		for (i = 0; i< tmplen; i++)
			outl(((u32 *)data_ptr)[i], db->io_data);
	} 

	/* 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, 0xfc, skb->len & 0xff);
		iow(db, 0xfd, (skb->len >> 8) & 0xff);

//		/* First Packet */
//		db->tx_pkt_cnt++;

		/* Issue TX polling command */
		iow(db, 0x2, 0x1);		/* Cleared after TX complete */

		/* saved the time stamp */
		dev->trans_start = jiffies;
	} 
	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);
	del_timer(&db->mdix_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;
}

static void dmfe_tx_done(unsigned long unused)
{
	struct net_device *dev = dmfe_dev;
	board_info_t *db = (board_info_t *)dev->priv;
	//int TxStatus;	//For Collision detect
	int tx_status = ior(db, 0x01);	/* Got TX status */
	DMFE_DBUG(0, "dmfe_tx_done()", 0);
	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) 
		{
			/* Set TX length to DM9000 */
			iow(db, 0xfc, db->queue_pkt_len & 0xff);
			iow(db, 0xfd, (db->queue_pkt_len >> 8) & 0xff);
		
			/* Issue TX polling command */
			iow(db, 0x2, 0x1);    /* Cleared after TX complete */
			dev->trans_start = jiffies; /* saved the time stamp */
			//netif_wake_queue(dev);
		}
		netif_wake_queue(dev);
	}

}

/*
  DM9102 insterrupt handler
  receive the packet to upper layer, free the transmitted packet
*/
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); 
	//iow(db, 0xff, 0x81);

	/* 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)
		tasklet_schedule(&dmfe_tx_tasklet);

	/* 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;
	//u8 tmpreg;
	
	DMFE_DBUG(0, "dmfe_timer()", 0);

⌨️ 快捷键说明

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