[uClinux-dev] [PATCH 01/15] dm9ks: merge Davicom v2.09

Thomas Chou thomas at wytron.com.tw
Mon Dec 3 02:32:20 EST 2007


Vendor driver udpates,

10/3/2006	-Add DM8606 read/write function by MDC and MDIO
V2.06	01/03/2007	-CONT_RX_PKT_CNT=0xFFFF
			-modify dmfe_tx_done function
			-check RX FIFO pointer
			-if using physical address, re-define I/O 
function
			-add db->cont_rx_pkt_cnt=0 at the front of 
dmfe_packet_receive()
V2.08	02/12/2007	-module parameter macro
			2.4  MODULE_PARM
			2.6  module_param
			-remove #include <linux/config>
  			-fix dmfe_interrupt for kernel 2.6.20                  
05/24/2007	-support ethtool and mii-tool
05/30/2007	-fix the driver bug when ifconfig eth0 (-)promisc and 
(-)allmulti.
06/05/2007	-fix dm9000b issue(ex. 10M TX idle=65mA, 10M harmonic)
			-add flow control function (option)

Signed-off-by: Thomas Chou <thomas at wytron.com.tw>

diff --git a/linux-2.6.x/drivers/net/Space.c b/linux-2.6.x/drivers/net/Space.c
index ac9b789..e0a921b 100644
--- a/linux-2.6.x/drivers/net/Space.c
+++ b/linux-2.6.x/drivers/net/Space.c
@@ -71,7 +71,7 @@ extern struct net_device *sonic_probe(int unit);
 extern struct net_device *SK_init(int unit);
 extern struct net_device *seeq8005_probe(int unit);
 extern struct net_device *smc_init(int unit);
-extern struct net_device *dm9ks_probe(int unit);
+extern struct net_device *dmfe_probe(int unit);
 extern struct net_device *atarilance_probe(int unit);
 extern struct net_device *sun3lance_probe(int unit);
 extern struct net_device *sun3_82586_probe(int unit);
@@ -199,7 +199,7 @@ static struct devprobe2 isa_probes[] __initdata = {
 	{mtip1000_init, 0},
 #endif
 #if defined(CONFIG_DM9KS)
-	{dm9ks_probe, 0},
+	{dmfe_probe, 0},
 #endif
 #ifdef CONFIG_SEEQ8005
 	{seeq8005_probe, 0},
diff --git a/linux-2.6.x/drivers/net/dm8606.h b/linux-2.6.x/drivers/net/dm8606.h
new file mode 100644
index 0000000..c4c81e1
--- /dev/null
+++ b/linux-2.6.x/drivers/net/dm8606.h
@@ -0,0 +1,48 @@
+u16 dm8606_read(board_info_t *, int);
+void dm8606_write(board_info_t *, int, u16);
+
+u16 dm8606_read(board_info_t *db, int offset)
+{
+	int bval, i=0;
+	bval = ( offset >> 5 ) | 0x80;
+	iow(db, 0x33, bval);
+	bval = offset;
+	iow(db, 0x0c, bval);
+	
+	iow(db, 0xb, 0x8); 	/* Clear phyxcer read command */
+	iow(db, 0xb, 0xc); 	/* Issue phyxcer read command */
+	iow(db, 0xb, 0x8); 	/* Clear phyxcer read command */
+	
+	do {
+		if ((!(ior(db,0xb) & 0x1)) || i>1000)
+			break;
+		i++;
+	}while(1);
+	iow(db, 0x33, 0);
+	/* The read data keeps on REG_0D & REG_0E */
+	return ( ior(db, DM9KS_EPDRH) << 8 ) | ior(db, DM9KS_EPDRL);
+	
+}
+
+void dm8606_write(board_info_t *db, int offset, u16 value)
+{
+	int bval,i=0;
+	bval = ( offset >> 5 ) | 0x80;
+	iow(db, 0x33, bval);
+	bval = offset;
+	iow(db, 0x0c, bval);
+	
+	/* Fill the written data into REG_0D & REG_0E */
+	iow(db, 0xd, (value & 0xff));
+	iow(db, 0xe, ( (value >> 8) & 0xff));
+
+	iow(db, 0xb, 0x8);	/* Clear phyxcer write command */
+	iow(db, 0xb, 0xa);	/* Issue phyxcer write command */
+	iow(db, 0xb, 0x8);	/* Clear phyxcer write command */
+	do {
+		if ((!(ior(db,0xb) & 0x1)) || i >1000)
+			break;
+		i++;
+	}while(1);
+	iow(db, 0x33, 0);
+}
diff --git a/linux-2.6.x/drivers/net/dm9ks.c b/linux-2.6.x/drivers/net/dm9ks.c
index e3b99f0..2f43384 100644
--- a/linux-2.6.x/drivers/net/dm9ks.c
+++ b/linux-2.6.x/drivers/net/dm9ks.c
@@ -1,6 +1,6 @@
 /*
 
-  dm9ks.c: Version 2.03 2005/10/17 
+  dm9ks.c: Version 2.08 2007/02/12 
   
         A Davicom DM9000A/DM9010 ISA NIC fast Ethernet driver for Linux.
 
@@ -15,33 +15,49 @@
 	GNU General Public License for more details.
 
 
-  (C)Copyright 1997-2005 DAVICOM Semiconductor,Inc. All Rights Reserved.
+  (C)Copyright 1997-2007 DAVICOM Semiconductor,Inc. All Rights Reserved.
 
-	
-V1.00	10/13/2004	Add new function Early transmit & IP/TCP/UDP Checksum
-			offload enable & flow control is default
-V1.1	12/29/2004	Add Two packet mode & modify RX function
-V1.2	01/14/2005	Add Early transmit mode 
-V1.3	03/02/2005	Support kernel 2.6
-v1.33   06/08/2005	#define DM9KS_MDRAL		0xf4
-			#define DM9KS_MDRAH		0xf5
-			
 V2.00 Spenser - 01/10/2005
 			- Modification for PXA270 MAINSTONE.
 			- Modified dmfe_tx_done().
 			- Add dmfe_timeout().
-V2.01	10/07/2005	Modified dmfe_timer()
-			Dected network speed 10/100M
-V2.02	10/12/2005	Use link change to chage db->Speed
-			dmfe_open() wait for Link OK  
-V2.03	11/22/2005	Power-off and Power-on PHY in dmfe_init()
-			support IOL
+V2.01	10/07/2005	-Modified dmfe_timer()
+			-Dected network speed 10/100M
+V2.02	10/12/2005	-Use link change to chage db->Speed
+			-dmfe_open() wait for Link OK  
+V2.03	11/22/2005	-Power-off and Power-on PHY in dmfe_init_dm9000()
+			-support IOL
+V2.04	12/13/2005	-delay 1.6s between power-on and power-off in 
+			 dmfe_init_dm9000()
+			-set LED mode 1 in dmfe_init_dm9000()
+			-add data bus driving capability in dmfe_init_dm9000()
+			 (optional)
+10/3/2006	-Add DM8606 read/write function by MDC and MDIO
+V2.06	01/03/2007	-CONT_RX_PKT_CNT=0xFFFF
+			-modify dmfe_tx_done function
+			-check RX FIFO pointer
+			-if using physical address, re-define I/O function
+			-add db->cont_rx_pkt_cnt=0 at the front of dmfe_packet_receive()
+V2.08	02/12/2007	-module parameter macro
+			2.4  MODULE_PARM
+			2.6  module_param
+			-remove #include <linux/config>
+  			-fix dmfe_interrupt for kernel 2.6.20                  
+05/24/2007	-support ethtool and mii-tool
+05/30/2007	-fix the driver bug when ifconfig eth0 (-)promisc and (-)allmulti.
+06/05/2007	-fix dm9000b issue(ex. 10M TX idle=65mA, 10M harmonic)
+			-add flow control function (option)
 */
 
+#define DRV_NAME	"dm9KS"
+#define DRV_VERSION	"2.08"
+#define DRV_RELDATE	"2007-06-05"
+
 #if defined(MODVERSIONS)
 #include <linux/modversions.h>
 #endif
 
+//#include <linux/config.h>
 #include <linux/init.h>				
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -53,6 +69,8 @@ V2.03	11/22/2005	Power-off and Power-on PHY in dmfe_init()
 #include <asm/dma.h>
 #include <linux/spinlock.h>
 #include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
 
 #ifdef CONFIG_ARCH_MAINSTONE
 #include <asm/io.h>
@@ -60,6 +78,8 @@ V2.03	11/22/2005	Power-off and Power-on PHY in dmfe_init()
 #include <asm/irq.h>
 #endif
 
+//#define DM8606
+
 #ifdef CONFIG_EXCALIBUR
 #include <asm/nios.h>
 #include <asm/io.h>
@@ -83,16 +103,20 @@ V2.03	11/22/2005	Power-off and Power-on PHY in dmfe_init()
 #define DM9KS_TCR		0x02	/* TX control Reg.*/
 #define DM9KS_RXCR		0x05	/* RX control Reg.*/
 #define DM9KS_BPTR		0x08
+#define DM9KS_FCTR		0x09
+#define DM9KS_FCR		0x0a
 #define DM9KS_EPCR		0x0b
 #define DM9KS_EPAR		0x0c
 #define DM9KS_EPDRL		0x0d
 #define DM9KS_EPDRH		0x0e
 #define DM9KS_GPR		0x1f	/* General purpose register */
+#define DM9KS_CHIPR		0x2c
 #define DM9KS_TCR2		0x2d
 #define DM9KS_SMCR		0x2f 	/* Special Mode Control Reg.*/
 #define DM9KS_ETXCSR		0x30	/* Early Transmit control/status Reg.*/
 #define	DM9KS_TCCR		0x31	/* Checksum cntrol Reg. */
 #define DM9KS_RCSR		0x32	/* Receive Checksum status Reg.*/
+#define DM9KS_BUSCR		0x38
 #define DM9KS_MRCMDX		0xf0
 #define DM9KS_MRCMD		0xf2
 #define DM9KS_MDRAL		0xf4
@@ -115,15 +139,15 @@ V2.03	11/22/2005	Power-off and Power-on PHY in dmfe_init()
 #include <asm/arch/mainstone.h>
 #define DM9KS_MIN_IO		(MST_ETH_PHYS + 0x300)
 #define DM9KS_MAX_IO            (MST_ETH_PHYS + 0x370)
-#define DM9K_IRQ		MAINSTONE_IRQ(3)
+#define DM9KS_IRQ		MAINSTONE_IRQ(3)
 #elif defined(CONFIG_EXCALIBUR)
 #define DM9KS_MIN_IO            (na_dm9000)
 #define DM9KS_MAX_IO            (DM9KS_MIN_IO + 7)
-#define DM9K_IRQ	        (na_dm9000_irq)
+#define DM9KS_IRQ	        (na_dm9000_irq)
 #else
 #define DM9KS_MIN_IO		0x300
 #define DM9KS_MAX_IO		0x370
-#define DM9K_IRQ		3
+#define DM9KS_IRQ		3
 #endif
 
 #define DM9KS_VID_L		0x28
@@ -142,7 +166,7 @@ V2.03	11/22/2005	Power-off and Power-on PHY in dmfe_init()
 #define TRUE			1
 #define FALSE			0
 /* Number of continuous Rx packets */
-#define CONT_RX_PKT_CNT	10 
+#define CONT_RX_PKT_CNT		0xFFFF
 
 #define DMFE_TIMER_WUT  jiffies+(HZ*5)	/* timer wakeup time : 5 second */
 
@@ -154,17 +178,24 @@ if (dmfe_debug||dbug_now) printk(KERN_ERR "dmfe: %s %x\n", msg, vaule)
 if (dbug_now) printk(KERN_ERR "dmfe: %s %x\n", msg, vaule)
 #endif
 
+#ifndef CONFIG_ARCH_MAINSTONE
+#pragma pack(push, 1)
+#endif
+
 typedef struct _RX_DESC
 {
 	u8 rxbyte;
 	u8 status;
 	u16 length;
-} __attribute__((__packed__)) RX_DESC;
+}RX_DESC;
 
 typedef union{
 	u8 buf[4];
 	RX_DESC desc;
-} __attribute__((__packed__)) rx_t;
+} rx_t;
+#ifndef CONFIG_ARCH_MAINSTONE
+#pragma pack(pop)
+#endif
 
 enum DM9KS_PHY_mode {
 	DM9KS_10MHD   = 0, 
@@ -175,39 +206,83 @@ enum DM9KS_PHY_mode {
 };
 
 /* Structure/enum declaration ------------------------------- */
-typedef struct board_info {
- 
-	u32 reset_counter;		/* counter: RESET */ 
-	u32 reset_tx_timeout;		/* RESET caused by TX Timeout */ 
-
-	u32 io_addr;			/* Register I/O base address */
-	u32 io_data;			/* Data I/O address */
+typedef struct board_info { 
+	u32 io_addr;/* Register I/O base address */
+	u32 io_data;/* Data I/O address */
+	u8 op_mode;/* PHY operation mode */
+	u8 io_mode;/* 0:word, 2:byte */
+	u8 Speed;	/* current speed */
+	u8 chip_revision;
+	int rx_csum;/* 0:disable, 1:enable */
+	
+	u32 reset_counter;/* counter: RESET */ 
+	u32 reset_tx_timeout;/* RESET caused by TX Timeout */
 	int tx_pkt_cnt;
-
-	u8 op_mode;			/* PHY operation mode */
-	u8 io_mode;			/* 0:word, 2:byte */
-	u8 device_wait_reset;		/* device state */
-	u8 Speed;			/* current speed */
-
 	int cont_rx_pkt_cnt;/* current number of continuos rx packets  */
-	struct timer_list timer;
 	struct net_device_stats stats;
+	
+	struct timer_list timer;
 	unsigned char srom[128];
 	spinlock_t lock;
-
+	struct mii_if_info mii;
 } board_info_t;
 /* Global variable declaration ----------------------------- */
-/* static int dmfe_debug = 1; */
+/*static int dmfe_debug = 0;*/
 static struct net_device * dmfe_dev = NULL;
-
+static struct ethtool_ops dmfe_ethtool_ops;
 /* For module input parameter */
-static int mode       = DM9KS_AUTO;
+static int mode       = DM9KS_AUTO;  
 static int media_mode = DM9KS_AUTO;
-static u8  irq        = DM9K_IRQ;
-static u32 iobase     = DM9KS_MIN_IO;
+static int  irq        = DM9KS_IRQ;
+static int iobase     = DM9KS_MIN_IO;
+
+#if 0  // use physical address; Not virtual address
+#ifdef outb
+	#undef outb
+#endif
+#ifdef outw
+	#undef outw
+#endif
+#ifdef outl
+	#undef outl
+#endif
+#ifdef inb
+	#undef inb
+#endif
+#ifdef inw
+	#undef inw
+#endif
+#ifdef inl
+	#undef inl
+#endif
+void outb(u8 reg, u32 ioaddr)
+{
+	(*(volatile u8 *)(ioaddr)) = reg;
+}
+void outw(u16 reg, u32 ioaddr)
+{
+	(*(volatile u16 *)(ioaddr)) = reg;
+}
+void outl(u32 reg, u32 ioaddr)
+{
+	(*(volatile u32 *)(ioaddr)) = reg;
+}
+u8 inb(u32 ioaddr)
+{
+	return (*(volatile u8 *)(ioaddr));
+}
+u16 inw(u32 ioaddr)
+{
+	return (*(volatile u16 *)(ioaddr));
+}
+u32 inl(u32 ioaddr)
+{
+	return (*(volatile u32 *)(ioaddr));
+}
+#endif
 
 /* function declaration ------------------------------------- */
-int dmfe_probe(struct net_device *);
+int dmfe_probe1(struct net_device *);
 static int dmfe_open(struct net_device *);
 static int dmfe_start_xmit(struct sk_buff *, struct net_device *);
 static void dmfe_tx_done(unsigned long);
@@ -215,23 +290,46 @@ static void dmfe_packet_receive(struct net_device *);
 static int dmfe_stop(struct net_device *);
 static struct net_device_stats * dmfe_get_stats(struct net_device *); 
 static int dmfe_do_ioctl(struct net_device *, struct ifreq *, int);
-static irqreturn_t dmfe_interrupt(int , void *);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static void dmfe_interrupt(int , void *, struct pt_regs *); 
+#else
+	#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+	static irqreturn_t dmfe_interrupt(int , void *, struct pt_regs *);
+	#else
+	static irqreturn_t dmfe_interrupt(int , void *);/* for kernel 2.6.20 */
+	#endif
+#endif
 static void dmfe_timer(unsigned long);
 static void dmfe_init_dm9000(struct net_device *);
 static unsigned long cal_CRC(unsigned char *, unsigned int, u8);
-static u8 ior(board_info_t *, int);
-static void iow(board_info_t *, int, u8);
+u8 ior(board_info_t *, int);
+void iow(board_info_t *, int, u8);
 static u16 phy_read(board_info_t *, int);
 static void phy_write(board_info_t *, int, u16);
 static u16 read_srom_word(board_info_t *, int);
 static void dm9000_hash_table(struct net_device *);
 static void dmfe_timeout(struct net_device *);
 static void dmfe_reset(struct net_device *);
+static int mdio_read(struct net_device *, int, int);
+static void mdio_write(struct net_device *, int, int, int);
+static void dmfe_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
+static int dmfe_get_settings(struct net_device *, struct ethtool_cmd *);
+static int dmfe_set_settings(struct net_device *, struct ethtool_cmd *);
+static u32 dmfe_get_link(struct net_device *);
+static int dmfe_nway_reset(struct net_device *);
+static uint32_t dmfe_get_rx_csum(struct net_device *);
+static uint32_t dmfe_get_tx_csum(struct net_device *);
+static int dmfe_set_rx_csum(struct net_device *, uint32_t );
+static int dmfe_set_tx_csum(struct net_device *, uint32_t );
 
 #if defined(CHECKSUM)
 static u8 check_rx_ready(u8);
 #endif
 
+#ifdef DM8606
+#include "dm8606.h"
+#endif
+
 //DECLARE_TASKLET(dmfe_tx_tasklet,dmfe_tx_done,0);
 
 /* DM9000 network baord routine ---------------------------- */
@@ -240,14 +338,16 @@ static u8 check_rx_ready(u8);
   Search DM9000 board, allocate space and register it
 */
 
-struct net_device * __init dm9ks_probe(void)
+struct net_device * __init dmfe_probe(void)
 {
 	struct net_device *dev;
 	int err;
+	
+	DMFE_DBUG(0, "dmfe_probe()",0);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	dev = init_etherdev(NULL, sizeof(struct board_info));
-	ether_setup(dev);		
+	//ether_setup(dev);		
 #else
 	dev= alloc_etherdev(sizeof(struct board_info));
 #endif
@@ -256,7 +356,7 @@ struct net_device * __init dm9ks_probe(void)
 		return ERR_PTR(-ENOMEM);
 
      	SET_MODULE_OWNER(dev);
-	err = dmfe_probe(dev);
+	err = dmfe_probe1(dev);
 	if (err)
 		goto out;
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
@@ -276,13 +376,14 @@ out:
 	return ERR_PTR(err);
 }
 
-int __init dmfe_probe(struct net_device *dev)
+int __init dmfe_probe1(struct net_device *dev)
 {
 	struct board_info *db;    /* Point a board information structure */
 	u32 id_val;
 	u16 i, dm9000_found = FALSE;
-
-	DMFE_DBUG(0, "dmfe_probe()",0);
+	u8 MAC_addr[6]={0x00,0x60,0x6E,0x33,0x44,0x55};
+	u8 HasEEPROM=0;
+	DMFE_DBUG(0, "dmfe_probe1()",0);
 
 	/* Search All DM9000 serial NIC */
 	do {
@@ -301,7 +402,7 @@ int __init dmfe_probe(struct net_device *dev)
 			if(!request_region(iobase, 2, dev->name))
 				return -ENODEV;
 
-			printk("<DM9KS> I/O: %x, VID: %x \n",iobase, id_val);
+			printk(KERN_ERR"<DM9KS> I/O: %x, VID: %x \n",iobase, id_val);
 			dm9000_found = TRUE;
 
 			/* Allocated board information structure */
@@ -309,22 +410,33 @@ int __init dmfe_probe(struct net_device *dev)
 			db = (board_info_t *)dev->priv;
 			dmfe_dev    = dev;
 			db->io_addr  = iobase;
-			db->io_data = iobase + 4;
-			/* driver system function */
-				
+			db->io_data = iobase + 4;   
+			db->chip_revision = ior(db, DM9KS_CHIPR);
+			
+			/* driver system function */				
 			dev->base_addr 		= iobase;
 			dev->irq 		= irq;
 			dev->open 		= &dmfe_open;
 			dev->hard_start_xmit 	= &dmfe_start_xmit;
-			dev->watchdog_timeo	= HZ;	
+			dev->watchdog_timeo	= 5*HZ;	
 			dev->tx_timeout		= dmfe_timeout;
 			dev->stop 		= &dmfe_stop;
 			dev->get_stats 		= &dmfe_get_stats;
 			dev->set_multicast_list = &dm9000_hash_table;
 			dev->do_ioctl 		= &dmfe_do_ioctl;
-
-#if defined(CHECKSUM)
-			dev->features = dev->features | NETIF_F_NO_CSUM;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,28)
+			dev->ethtool_ops = &dmfe_ethtool_ops;
+#endif
+#ifdef CHECKSUM
+			dev->features |=  NETIF_F_IP_CSUM;
+#endif
+			db->mii.dev = dev;
+			db->mii.mdio_read = mdio_read;
+			db->mii.mdio_write = mdio_write;
+			db->mii.phy_id = 1;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)
+			db->mii.phy_id_mask = 0x1F; 
+			db->mii.reg_num_mask = 0x1F; 
 #endif
 #ifdef CONFIG_EXCALIBUR
 			{
@@ -333,13 +445,26 @@ int __init dmfe_probe(struct net_device *dev)
 			  memcpy(dev->dev_addr, excalibur_enet_hwaddr, 6);
 			}
 #else
+			//db->msg_enable =(debug == 0 ? DMFE_DEF_MSG_ENABLE : ((1 << debug) - 1));
+			
 			/* Read SROM content */
 			for (i=0; i<64; i++)
 				((u16 *)db->srom)[i] = read_srom_word(db, i);
 
+			/* Get the PID and VID from EEPROM to check */
+			id_val = (((u16 *)db->srom)[4])|(((u16 *)db->srom)[5]<<16); 
+			printk("id_val=%x\n", id_val);
+			if (id_val == DM9KS_ID || id_val == DM9010_ID) 
+				HasEEPROM =1;
+			
 			/* Set Node Address */
 			for (i=0; i<6; i++)
-				dev->dev_addr[i] = db->srom[i];
+			{
+				if (HasEEPROM) /* use EEPROM */
+					dev->dev_addr[i] = db->srom[i];
+				else	/* No EEPROM */
+					dev->dev_addr[i] = MAC_addr[i];
+			}
 #endif
 		}//end of if()
 		iobase += 0x10;
@@ -360,12 +485,16 @@ static int dmfe_open(struct net_device *dev)
 	int i;
 	DMFE_DBUG(0, "dmfe_open", 0);
 
-	if (request_irq(dev->irq,&dmfe_interrupt,SA_SHIRQ,dev->name,dev)) 
+	if (request_irq(dev->irq,&dmfe_interrupt,0,dev->name,dev)) 
 		return -EAGAIN;
 
 	/* Initilize DM910X board */
 	dmfe_init_dm9000(dev);
- 
+#ifdef DM8606
+	// control DM8606
+	printk("[8606]reg0=0x%04x\n",dm8606_read(db,0));
+	printk("[8606]reg1=0x%04x\n",dm8606_read(db,0x1));
+#endif 
 	/* Init driver variable */
 	db->reset_counter 	= 0;
 	db->reset_tx_timeout 	= 0;
@@ -375,12 +504,12 @@ static int dmfe_open(struct net_device *dev)
 	db->Speed =10;
 	i=0;
 	do {
-		reg_nsr = ior(db,0x1);
+		reg_nsr = ior(db,DM9KS_NSR);
 		if(reg_nsr & 0x40) /* link OK!! */
 		{
 			/* wait for detected Speed */
 			mdelay(200);
-			reg_nsr = ior(db,0x1);
+			reg_nsr = ior(db,DM9KS_NSR);
 			if(reg_nsr & 0x80)
 				db->Speed =10;
 			else
@@ -393,7 +522,7 @@ static int dmfe_open(struct net_device *dev)
 	//printk("i=%d  Speed=%d\n",i,db->Speed);	
 	/* set and active a timer process */
 	init_timer(&db->timer);
-	db->timer.expires 	= DMFE_TIMER_WUT * 2;
+	db->timer.expires 	= DMFE_TIMER_WUT;
 	db->timer.data 		= (unsigned long)dev;
 	db->timer.function 	= &dmfe_timer;
 	add_timer(&db->timer);	//Move to DM9000 initiallization was finished.
@@ -407,8 +536,9 @@ static int dmfe_open(struct net_device *dev)
 */
 static void set_PHY_mode(board_info_t *db)
 {
-	u16 phy_reg0 = 0x1200;		/* Auto-negotiation & Restart Auto-negotiation */
-	u16 phy_reg4 = 0x01e1;		/* Default flow control disable*/
+#ifndef DM8606
+	u16 phy_reg0 = 0x1000;/* Auto-negotiation*/
+	u16 phy_reg4 = 0x01e1;
 
 	if ( !(db->op_mode & DM9KS_AUTO) ) // op_mode didn't auto sense */
 	{ 
@@ -429,8 +559,103 @@ static void set_PHY_mode(board_info_t *db)
 					   break;
 		} // end of switch
 	} // end of if
-	phy_write(db, 0, phy_reg0);
+#ifdef FLOW_CONTROL
+	phy_write(db, 4, phy_reg4|(1<<10));
+#else
 	phy_write(db, 4, phy_reg4);
+#endif //end of FLOW_CONTROL
+	phy_write(db, 0, phy_reg0|0x200);
+#else
+	/* Fiber mode */
+	phy_write(db, 16, 0x4014);
+	phy_write(db, 0, 0x2100);
+#endif //end of DM8606
+
+	if (db->chip_revision == 0x1A) /* DM9000B */
+	{
+		//set 10M TX idle =65mA (TX 100% utility is 160mA)
+		phy_write(db,20, phy_read(db,20)|(1<<11)|(1<<10));
+		
+		//DM9000B:fix harmonic
+		//For short code:
+		//PHY_REG 27 (1Bh) <- 0000h
+		phy_write(db, 27, 0x0000);
+		//PHY_REG 27 (1Bh) <- AA00h
+		phy_write(db, 27, 0xaa00);
+
+		//PHY_REG 27 (1Bh) <- 0017h
+		phy_write(db, 27, 0x0017);
+		//PHY_REG 27 (1Bh) <- AA17h
+		phy_write(db, 27, 0xaa17);
+
+		//PHY_REG 27 (1Bh) <- 002Fh
+		phy_write(db, 27, 0x002f);
+		//PHY_REG 27 (1Bh) <- AA2Fh
+		phy_write(db, 27, 0xaa2f);
+		
+		//PHY_REG 27 (1Bh) <- 0037h
+		phy_write(db, 27, 0x0037);
+		//PHY_REG 27 (1Bh) <- AA37h
+		phy_write(db, 27, 0xaa37);
+		
+		//PHY_REG 27 (1Bh) <- 0040h
+		phy_write(db, 27, 0x0040);
+		//PHY_REG 27 (1Bh) <- AA40h
+		phy_write(db, 27, 0xaa40);
+		
+		//For long code:
+		//PHY_REG 27 (1Bh) <- 0050h
+		phy_write(db, 27, 0x0050);
+		//PHY_REG 27 (1Bh) <- AA50h
+		phy_write(db, 27, 0xaa50);
+		
+		//PHY_REG 27 (1Bh) <- 006Bh
+		phy_write(db, 27, 0x006b);
+		//PHY_REG 27 (1Bh) <- AA6Bh
+		phy_write(db, 27, 0xaa6b);
+		
+		//PHY_REG 27 (1Bh) <- 007Dh
+		phy_write(db, 27, 0x007d);
+		//PHY_REG 27 (1Bh) <- AA7Dh
+		phy_write(db, 27, 0xaa7d);
+		
+		//PHY_REG 27 (1Bh) <- 008Dh
+		phy_write(db, 27, 0x008d);
+		//PHY_REG 27 (1Bh) <- AA8Dh
+		phy_write(db, 27, 0xaa8d);
+		
+		//PHY_REG 27 (1Bh) <- 009Ch
+		phy_write(db, 27, 0x009c);
+		//PHY_REG 27 (1Bh) <- AA9Ch
+		phy_write(db, 27, 0xaa9c);
+		
+		//PHY_REG 27 (1Bh) <- 00A3h
+		phy_write(db, 27, 0x00a3);
+		//PHY_REG 27 (1Bh) <- AAA3h
+		phy_write(db, 27, 0xaaa3);
+		
+		//PHY_REG 27 (1Bh) <- 00B1h
+		phy_write(db, 27, 0x00b1);
+		//PHY_REG 27 (1Bh) <- AAB1h
+		phy_write(db, 27, 0xaab1);
+		
+		//PHY_REG 27 (1Bh) <- 00C0h
+		phy_write(db, 27, 0x00c0);
+		//PHY_REG 27 (1Bh) <- AAC0h
+		phy_write(db, 27, 0xaac0);
+		
+		//PHY_REG 27 (1Bh) <- 00D2h
+		phy_write(db, 27, 0x00d2);
+		//PHY_REG 27 (1Bh) <- AAD2h
+		phy_write(db, 27, 0xaad2);
+		
+		//PHY_REG 27 (1Bh) <- 00E0h
+		phy_write(db, 27, 0x00e0);
+		//PHY_REG 27 (1Bh) <- AAE0h
+		phy_write(db, 27, 0xaae0);
+		//PHY_REG 27 (1Bh) <- 0000h
+		phy_write(db, 27, 0x0000);
+	}
 }
 
 /* 
@@ -441,11 +666,18 @@ 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);
 
+	spin_lock_init(&db->lock);
+	
+#if 0
 	/* set the internal PHY power-on, GPIOs normal, and wait 2ms */
+	iow(db, DM9KS_GPR, 0);	/* GPR (reg_1Fh)bit GPIO0=0 pre-activate PHY */
+	mdelay(20);		/* wait for PHY power-on ready */
 	iow(db, DM9KS_GPR, 1); 	/* Power-Down PHY */
-	udelay(500);
+	mdelay(1000);		/* compatible with rtl8305s */
+	mdelay(600);		/* compatible with rtl8305s */
+#endif 
 	iow(db, DM9KS_GPR, 0);	/* GPR (reg_1Fh)bit GPIO0=0 pre-activate PHY */
-	udelay(20);		/* wait 2ms for PHY power-on ready */
+	mdelay(20);		/* wait for PHY power-on ready */
 
 	/* do a software reset and wait 20us */
 	iow(db, DM9KS_NCR, 3);
@@ -467,14 +699,38 @@ static void dmfe_init_dm9000(struct net_device *dev)
 	iow(db, DM9KS_SMCR, 0);		/* Special Mode */
 	iow(db, DM9KS_NSR, 0x2c);	/* clear TX status */
 	iow(db, DM9KS_ISR, 0x0f); 	/* Clear interrupt status */
+	iow(db, DM9KS_TCR2, 0x80);	/* Set LED mode 1 */
+	if (db->chip_revision == 0x1A){ /* DM9000B */
+		/* Data bus current driving/sinking capability  */
+		iow(db, DM9KS_BUSCR, 0x01);	/* default: 2mA */
+	}
+#ifdef FLOW_CONTROL
+	iow(db, DM9KS_BPTR, 0x37);
+	iow(db, DM9KS_FCTR, 0x38);
+	iow(db, DM9KS_FCR, 0x29);
+#endif
 
-	/* 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 */
+#ifdef DM8606
+	iow(db,0x34,1);
 #endif
 
-#if defined(ETRANS)
+	if (dev->features & NETIF_F_HW_CSUM){
+		printk(KERN_INFO "DM9KS:enable TX checksum\n");
+		iow(db, DM9KS_TCCR, 0x07);	/* TX UDP/TCP/IP checksum enable */
+	}
+	if (db->rx_csum){
+		printk(KERN_INFO "DM9KS:enable RX checksum\n");
+		iow(db, DM9KS_RCSR, 0x02);	/* RX checksum enable */
+	}
+
+#ifdef ETRANS
+	/*If TX loading is heavy, the driver can try to anbel "early transmit".
+	The programmer can tune the "Early Transmit Threshold" to get 
+	the optimization. (DM9KS_ETXCSR.[1-0])
+	
+	Side Effect: It will happen "Transmit under-run". When TX under-run
+	always happens, the programmer can increase the value of "Early 
+	Transmit Threshold". */
 	iow(db, DM9KS_ETXCSR, 0x83);
 #endif
  
@@ -482,14 +738,13 @@ static void dmfe_init_dm9000(struct net_device *dev)
 	dm9000_hash_table(dev);
 
 	/* Activate DM9000A/DM9010 */
+	iow(db, DM9KS_IMR, DM9KS_REGFF); /* Enable TX/RX interrupt mask */
 	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);
 
 }
 
@@ -502,20 +757,32 @@ 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;}
+	
+	DMFE_DBUG(0, "dmfe_start_xmit", 0);
+	if (db->chip_revision != 0x1A)
+	{	/* DM9000A */
+		if(db->Speed == 10)
+			{if (db->tx_pkt_cnt >= 1) return 1;}
+		else
+			{if (db->tx_pkt_cnt >= 2) return 1;}
+	}else
+		/* DM9000B */
+		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);}
+	if (db->chip_revision != 0x1A)
+	{	/* DM9000A */
+		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);}
+	}else
+		/* DM9000B */
+		if (db->tx_pkt_cnt >= 2) netif_stop_queue(dev);		
 
 	/* Disable all interrupt */
 	iow(db, DM9KS_IMR, DM9KS_DISINTR);
@@ -546,7 +813,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
 			break;
 	}
 	
-#if !defined(ETRANS)
+#ifndef ETRANS
 	/* Issue TX polling command */
 	iow(db, DM9KS_TCR, 0x1); /* Cleared after TX complete*/
 #endif
@@ -583,7 +850,7 @@ static int dmfe_stop(struct net_device *dev)
 
 	/* RESET devie */
 	phy_write(db, 0x00, 0x8000);	/* PHY RESET */
-	iow(db, DM9KS_GPR, 0x01); 	/* Power-Down PHY */
+	//iow(db, DM9KS_GPR, 0x01); 	/* Power-Down PHY */
 	iow(db, DM9KS_IMR, DM9KS_DISINTR);	/* Disable all interrupt */
 	iow(db, DM9KS_RXCR, 0x00);	/* Disable RX */
 
@@ -609,18 +876,23 @@ static void dmfe_tx_done(unsigned long unused)
 	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)
+	if (nsr & 0x0c)
 	{
-		printk("[dmfe_tx_done] tx_pkt_cnt ERROR!!\n");
-		db->tx_pkt_cnt =0;
+		if(nsr & 0x04) db->tx_pkt_cnt--;
+		if(nsr & 0x08) db->tx_pkt_cnt--;
+		if(db->tx_pkt_cnt < 0)
+		{
+			printk(KERN_DEBUG "DM9KS:tx_pkt_cnt ERROR!!\n");
+			while(ior(db,DM9KS_TCR) & 0x1){}
+			db->tx_pkt_cnt = 0;
+		}
+			
+	}else{
+		while(ior(db,DM9KS_TCR) & 0x1){}
+		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);}
+		
+	netif_wake_queue(dev);
 	
 	return;
 }
@@ -629,7 +901,15 @@ static void dmfe_tx_done(unsigned long unused)
   DM9000 insterrupt handler
   receive the packet to upper layer, free the transmitted packet
 */
-static irqreturn_t dmfe_interrupt(int irq, void *dev_id)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#else
+	#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+	static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+	#else
+	static irqreturn_t dmfe_interrupt(int irq, void *dev_id) /* for kernel 2.6.20*/
+	#endif
+#endif
 {
 	struct net_device *dev = dev_id;
 	board_info_t *db;
@@ -710,19 +990,58 @@ static struct net_device_stats * dmfe_get_stats(struct net_device *dev)
 	DMFE_DBUG(0, "dmfe_get_stats", 0);
 	return &db->stats;
 }
+/*
+ *	Process the ethtool ioctl command
+ */
+static int dmfe_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	//struct dmfe_board_info *db = dev->priv;
+	struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+	u32 ethcmd;
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) 
+	{
+		case ETHTOOL_GDRVINFO:
+			strcpy(info.driver, DRV_NAME);
+			strcpy(info.version, DRV_VERSION);
+
+			sprintf(info.bus_info, "ISA 0x%lx %d",dev->base_addr, dev->irq);
+			if (copy_to_user(useraddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+	}
 
+	return -EOPNOTSUPP;
+}
 /*
   Process the upper socket ioctl command
 */
 static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
+	board_info_t *db = (board_info_t *)dev->priv;
+    	int rc=0;
+    	
 	DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
-	return 0;
+	
+    	if (!netif_running(dev))
+    		return -EINVAL;
+
+    	if (cmd == SIOCETHTOOL)
+        rc = dmfe_ethtool_ioctl(dev, (void *) ifr->ifr_data);
+	else {
+		spin_lock_irq(&db->lock);
+		rc = generic_mii_ioctl(&db->mii, if_mii(ifr), cmd, NULL);
+		spin_unlock_irq(&db->lock);
+	}
+
+	return rc;
 }
 
 /* Our watchdog timed out. Called by the networking layer */
-static void
-dmfe_timeout(struct net_device *dev)
+static void dmfe_timeout(struct net_device *dev)
 {
 	board_info_t *db = (board_info_t *)dev->priv;
 
@@ -737,7 +1056,6 @@ dmfe_timeout(struct net_device *dev)
 	printk("faH=0x%02x  fbH=0x%02x\n",ior(db,0xfa),ior(db,0xfb));
 #endif
 	dmfe_reset(dev);
-	
 }
 
 static void dmfe_reset(struct net_device * dev)
@@ -791,7 +1109,7 @@ static void dmfe_timer(unsigned long data)
 	return;
 }
 
-#if !defined(CHECKSUM)
+#ifndef CHECKSUM
 #define check_rx_ready(a)	((a) == 0x01)
 #else
 inline u8 check_rx_ready(u8 rxbyte)
@@ -820,6 +1138,8 @@ static void dmfe_packet_receive(struct net_device *dev)
 
 	DMFE_DBUG(0, "dmfe_packet_receive()", 0);
 
+	db->cont_rx_pkt_cnt=0;
+	
 	do {
 		/*store the value of Memory Data Read address register*/
 		MDRAH=ior(db, DM9KS_MDRAH);
@@ -940,7 +1260,7 @@ static void dmfe_packet_receive(struct net_device *dev)
 		
 			/* Pass to upper layer */
 			skb->protocol = eth_type_trans(skb,dev);
-#if defined(CHECKSUM)
+#ifdef CHECKSUM
 			if (val == 0x01)
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
 #endif
@@ -949,6 +1269,29 @@ static void dmfe_packet_receive(struct net_device *dev)
 			db->stats.rx_packets++;
 			db->stats.rx_bytes += rx.desc.length;
 			db->cont_rx_pkt_cnt++;
+#ifdef DBUG /* check RX FIFO pointer */
+			u16 MDRAH1, MDRAL1;
+			u16 tmp_ptr;
+			MDRAH1 = ior(db,DM9KS_MDRAH);
+			MDRAL1 = ior(db,DM9KS_MDRAL);
+			tmp_ptr = (MDRAH<<8)|MDRAL;
+			switch (db->io_mode)
+			{
+				case DM9KS_BYTE_MODE:
+					tmp_ptr += rx.desc.length+4;
+					break;
+				case DM9KS_WORD_MODE:
+					tmp_ptr += ((rx.desc.length+1)/2)*2+4;
+					break;
+				case DM9KS_DWORD_MODE:
+					tmp_ptr += ((rx.desc.length+3)/4)*4+4;
+					break;
+			}
+			if (tmp_ptr >=0x4000)
+				tmp_ptr = (tmp_ptr - 0x4000) + 0xc00;
+			if (tmp_ptr != ((MDRAH1<<8)|MDRAL1))
+				printk("[dm9ks:RX FIFO ERROR\n");
+#endif
 				
 			if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT)
 			{
@@ -969,7 +1312,7 @@ static u16 read_srom_word(board_info_t *db, int offset)
 {
 	iow(db, DM9KS_EPAR, offset);
 	iow(db, DM9KS_EPCR, 0x4);
-	udelay(200);
+	while(ior(db, DM9KS_EPCR)&0x1);	/* Wait read complete */
 	iow(db, DM9KS_EPCR, 0x0);
 	return (ior(db, DM9KS_EPDRL) + (ior(db, DM9KS_EPDRH) << 8) );
 }
@@ -987,6 +1330,25 @@ static void dm9000_hash_table(struct net_device *dev)
 
 	DMFE_DBUG(0, "dm9000_hash_table()", 0);
 
+	/* enable promiscuous mode */
+	if (dev->flags & IFF_PROMISC){
+		//printk(KERN_INFO "DM9KS:enable promiscuous mode\n");
+		iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)|(1<<1));
+		return;
+	}else{
+		//printk(KERN_INFO "DM9KS:disable promiscuous mode\n");
+		iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)&(~(1<<1)));
+	}
+		
+	/* Receive all multicast packets */
+	if (dev->flags & IFF_ALLMULTI){
+		//printk(KERN_INFO "DM9KS:Pass all multicast\n");
+		iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)|(1<<3));
+	}else{
+		//printk(KERN_INFO "DM9KS:Disable pass all multicast\n");
+		iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)&(~(1<<3)));
+	}
+	
 	/* Set Node address */
 	for (i = 0, oft = 0x10; i < 6; i++, oft++)
 		iow(db, oft, dev->dev_addr[i]);
@@ -1017,21 +1379,31 @@ static void dm9000_hash_table(struct net_device *dev)
          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;
-	 
+	return crc;	 
+}
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	board_info_t *db = (board_info_t *)dev->priv;
+	return phy_read(db, location);
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int val)
+{
+	board_info_t *db = (board_info_t *)dev->priv;
+	phy_write(db, location, val);
 }
 
 /*
    Read a byte from I/O port
 */
-static u8 ior(board_info_t *db, int reg)
+u8 ior(board_info_t *db, int reg)
 {
 	outb(reg, db->io_addr);
 	return inb(db->io_data);
@@ -1040,7 +1412,7 @@ static u8 ior(board_info_t *db, int reg)
 /*
    Write a byte to I/O port
 */
-static void iow(board_info_t *db, int reg, u8 value)
+void iow(board_info_t *db, int reg, u8 value)
 {
 	outb(reg, db->io_addr);
 	outb(value, db->io_data);
@@ -1055,7 +1427,7 @@ static u16 phy_read(board_info_t *db, int reg)
 	iow(db, DM9KS_EPAR, DM9KS_PHY | reg);
 
 	iow(db, DM9KS_EPCR, 0xc); 	/* Issue phyxcer read command */
-	udelay(100);			/* Wait read complete */
+	while(ior(db, DM9KS_EPCR)&0x1);	/* Wait read complete */
 	iow(db, DM9KS_EPCR, 0x0); 	/* Clear phyxcer read command */
 
 	/* The read data keeps on REG_0D & REG_0E */
@@ -1076,18 +1448,131 @@ static void phy_write(board_info_t *db, int reg, u16 value)
 	iow(db, DM9KS_EPDRH, ( (value >> 8) & 0xff));
 
 	iow(db, DM9KS_EPCR, 0xa);	/* Issue phyxcer write command */
-	udelay(500);			/* Wait write complete */
+	while(ior(db, DM9KS_EPCR)&0x1);	/* Wait read complete */
 	iow(db, DM9KS_EPCR, 0x0);	/* Clear phyxcer write command */
 }
+//====dmfe_ethtool_ops member functions====
+static void dmfe_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
+{
+	//board_info_t *db = (board_info_t *)dev->priv;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "ISA 0x%lx irq=%d",dev->base_addr, dev->irq);
+}
+static int dmfe_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	board_info_t *db = (board_info_t *)dev->priv;
+	spin_lock_irq(&db->lock);
+	mii_ethtool_gset(&db->mii, cmd);
+	spin_unlock_irq(&db->lock);
+	return 0;
+}
+static int dmfe_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	board_info_t *db = (board_info_t *)dev->priv;
+	int rc;
 
+	spin_lock_irq(&db->lock);
+	rc = mii_ethtool_sset(&db->mii, cmd);
+	spin_unlock_irq(&db->lock);
+	return rc;
+}
+/*
+* Check the link state
+*/
+static u32 dmfe_get_link(struct net_device *dev)
+{
+	board_info_t *db = (board_info_t *)dev->priv;
+	return mii_link_ok(&db->mii);
+}
+
+/*
+* Reset Auto-negitiation
+*/
+static int dmfe_nway_reset(struct net_device *dev)
+{
+	board_info_t *db = (board_info_t *)dev->priv;
+	return mii_nway_restart(&db->mii);
+}
+/*
+* Get RX checksum offload state
+*/
+static uint32_t dmfe_get_rx_csum(struct net_device *dev)
+{
+	board_info_t *db = (board_info_t *)dev->priv;
+	return db->rx_csum;
+}
+/*
+* Get TX checksum offload state
+*/
+static uint32_t dmfe_get_tx_csum(struct net_device *dev)
+{
+	return (dev->features & NETIF_F_HW_CSUM) != 0;
+}
+/* 
+* Enable/Disable RX checksum offload
+*/
+static int dmfe_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+#ifdef CHECKSUM
+	board_info_t *db = (board_info_t *)dev->priv;
+	db->rx_csum = data;
+
+	if(netif_running(dev)) {
+		dmfe_stop(dev);
+		dmfe_open(dev);
+	} else
+		dmfe_init_dm9000(dev);
+#else
+	printk(KERN_ERR "DM9:Don't support checksum\n");
+#endif
+	return 0;
+}
+/* 
+* Enable/Disable TX checksum offload
+*/
+static int dmfe_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+#ifdef CHECKSUM
+	if (data)
+		dev->features |= NETIF_F_HW_CSUM;
+	else
+		dev->features &= ~NETIF_F_HW_CSUM;
+#else
+	printk(KERN_ERR "DM9:Don't support checksum\n");
+#endif
+
+	return 0;
+}
+//=========================================
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,28)  /* for kernel 2.4.28 */
+static struct ethtool_ops dmfe_ethtool_ops = {
+	.get_drvinfo		= dmfe_get_drvinfo,
+	.get_settings		= dmfe_get_settings,
+	.set_settings		= dmfe_set_settings,
+	.get_link			= dmfe_get_link,
+	.nway_reset		= dmfe_nway_reset,
+	.get_rx_csum		= dmfe_get_rx_csum,
+	.set_rx_csum		= dmfe_set_rx_csum,
+	.get_tx_csum		= dmfe_get_tx_csum,
+	.set_tx_csum		= dmfe_set_tx_csum,
+};
+#endif
 
 #ifdef MODULE
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Davicom DM9000A/DM9010 ISA/uP Fast Ethernet Driver");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) 
 MODULE_PARM(mode, "i");
 MODULE_PARM(irq, "i");
 MODULE_PARM(iobase, "i");
+#else
+module_param(mode, int, 0);
+module_param(irq, int, 0);
+module_param(iobase, int, 0);
+#endif           
 MODULE_PARM_DESC(mode,"Media Speed, 0:10MHD, 1:10MFD, 4:100MHD, 5:100MFD");
 MODULE_PARM_DESC(irq,"EtherLink IRQ number");
 MODULE_PARM_DESC(iobase, "EtherLink I/O base address");
@@ -1096,7 +1581,7 @@ MODULE_PARM_DESC(iobase, "EtherLink I/O base address");
    when user used insmod to add module, system invoked init_module()
    to initilize and register.
 */
-int init_module(void)
+int __init init_module(void)
 {
 	switch(mode) {
 		case DM9KS_10MHD:
@@ -1108,7 +1593,7 @@ int init_module(void)
 		default:
 			media_mode = DM9KS_AUTO;
 	}
-	dmfe_dev = dm9ks_probe();
+	dmfe_dev = dmfe_probe();
 	if(IS_ERR(dmfe_dev))
 		return PTR_ERR(dmfe_dev);
 	return 0;
@@ -1117,7 +1602,7 @@ int init_module(void)
    when user used rmmod to delete module, system invoked clean_module()
    to  un-register DEVICE.
 */
-void cleanup_module(void)
+void __exit cleanup_module(void)
 {
 	struct net_device *dev = dmfe_dev;
 	DMFE_DBUG(0, "clean_module()", 0);
-- 
1.5.3.3



More information about the uClinux-dev mailing list