rpms/kernel/FC-4 jwltest-3c59x-resume-debug.patch, NONE, 1.1.12.1 jwltest-3c59x-resume.patch, NONE, 1.1.14.1 jwltest-acpi-dsdt-initrd.patch, NONE, 1.1.20.1 jwltest-b44-link-check.patch, NONE, 1.1.22.1 jwltest-ipw2100-1_1_0.patch, NONE, 1.1.24.1 jwltest-libata-atapi.patch, NONE, 1.1.4.1 jwltest-pci-d3hot-d0.patch, NONE, 1.1.10.1 jwltest-sundance-icplus.patch, NONE, 1.1.4.1

fedora-cvs-commits at redhat.com fedora-cvs-commits at redhat.com
Thu Sep 1 18:32:14 UTC 2005


Author: linville

Update of /cvs/dist/rpms/kernel/FC-4
In directory cvs.devel.redhat.com:/tmp/cvs-serv8249

Added Files:
      Tag: private-linville-fc4-jwltest-16-branch
	jwltest-3c59x-resume-debug.patch jwltest-3c59x-resume.patch 
	jwltest-acpi-dsdt-initrd.patch jwltest-b44-link-check.patch 
	jwltest-ipw2100-1_1_0.patch jwltest-libata-atapi.patch 
	jwltest-pci-d3hot-d0.patch jwltest-sundance-icplus.patch 
Log Message:


jwltest-3c59x-resume-debug.patch:
 3c59x.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 44 insertions(+)

--- NEW FILE jwltest-3c59x-resume-debug.patch ---
--- linux-2.6.12/drivers/net/3c59x.c.orig	2005-07-05 14:31:33.215024067 -0400
+++ linux-2.6.12/drivers/net/3c59x.c	2005-07-05 14:31:20.407728199 -0400
@@ -979,6 +979,20 @@ static int vortex_suspend (struct pci_de
 static int vortex_resume (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	int pm;
+	u16 pmcsr;
+
+	pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (pm) {
+		u16 state;
+
+		printk (KERN_ERR PFX "Entering %s\n", __FUNCTION__);
+		pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pmcsr);
+		state = pmcsr & PCI_PM_CTRL_STATE_MASK;
+		printk (KERN_ERR PFX "pdev->current_state %d\n",
+		        pdev->current_state);
+		printk (KERN_ERR PFX "pmcsr state %d\n", state);
+	}
 
 	if (dev && dev->priv) {
 		if (netif_running(dev)) {
@@ -986,6 +1000,18 @@ static int vortex_resume (struct pci_dev
 			netif_device_attach(dev);
 		}
 	}
+
+	if (pm) {
+		u16 state;
+
+		printk (KERN_ERR PFX "Exiting %s\n", __FUNCTION__);
+		pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pmcsr);
+		state = pmcsr & PCI_PM_CTRL_STATE_MASK;
+		printk (KERN_ERR PFX "pdev->current_state %d\n",
+		        pdev->current_state);
+		printk (KERN_ERR PFX "pmcsr state %d\n", state);
+	}
+
 	return 0;
 }
 
@@ -1576,9 +1602,27 @@ vortex_up(struct net_device *dev)
 	struct vortex_private *vp = netdev_priv(dev);
 	unsigned int config;
 	int i;
+	int pm;
+	u16 pmcsr;
 
 	if (VORTEX_PCI(vp)) {
+		printk (KERN_ERR PFX "Calling pci_enable_device\n");
 		pci_enable_device(VORTEX_PCI(vp));
+
+		pm = pci_find_capability(VORTEX_PCI(vp), PCI_CAP_ID_PM);
+		if (pm) {
+			u16 state;
+
+			pci_read_config_word(VORTEX_PCI(vp), pm + PCI_PM_CTRL,
+			                     &pmcsr);
+			state = pmcsr & PCI_PM_CTRL_STATE_MASK;
+			printk (KERN_ERR PFX
+			        "VORTEX_PCI(vp)->current_state %d\n",
+			        VORTEX_PCI(vp)->current_state);
+			printk (KERN_ERR PFX "pmcsr state %d\n", state);
+		}
+
+		printk (KERN_ERR PFX "Calling pci_restore_state\n");
 		pci_restore_state(VORTEX_PCI(vp));
 	}
 

jwltest-3c59x-resume.patch:
 3c59x.c |   14 ++++----------
 1 files changed, 4 insertions(+), 10 deletions(-)

--- NEW FILE jwltest-3c59x-resume.patch ---
--- linux-2.6.12/drivers/net/3c59x.c.orig	2005-07-01 17:04:31.254440604 -0400
+++ linux-2.6.12/drivers/net/3c59x.c	2005-07-01 17:26:11.163398335 -0400
@@ -795,7 +795,6 @@ struct vortex_private {
 		partner_flow_ctrl:1,			/* Partner supports flow control */
 		has_nway:1,
 		enable_wol:1,					/* Wake-on-LAN is enabled */
-		pm_state_valid:1,				/* pci_dev->saved_config_space has sane contents */
 		open:1,
 		medialock:1,
 		must_free_region:1,				/* Flag: if zero, Cardbus owns the I/O region */
@@ -1523,7 +1522,6 @@ static int __devinit vortex_probe1(struc
 	dev->poll_controller = poll_vortex; 
 #endif
 	if (pdev) {
-		vp->pm_state_valid = 1;
  		pci_save_state(VORTEX_PCI(vp));
  		acpi_set_WOL(dev);
 	}
@@ -1580,10 +1578,8 @@ vortex_up(struct net_device *dev)
 	int i;
 
 	if (VORTEX_PCI(vp)) {
-		pci_set_power_state(VORTEX_PCI(vp), PCI_D0);	/* Go active */
-		if (vp->pm_state_valid)
-			pci_restore_state(VORTEX_PCI(vp));
 		pci_enable_device(VORTEX_PCI(vp));
+		pci_restore_state(VORTEX_PCI(vp));
 	}
 
 	/* Before initializing select the active media port. */
@@ -2742,7 +2738,6 @@ vortex_down(struct net_device *dev, int 
 		outl(0, ioaddr + DownListPtr);
 
 	if (final_down && VORTEX_PCI(vp)) {
-		vp->pm_state_valid = 1;
 		pci_save_state(VORTEX_PCI(vp));
 		acpi_set_WOL(dev);
 	}
@@ -3051,7 +3046,7 @@ static int vortex_ioctl(struct net_devic
 	/* The kernel core really should have pci_get_power_state() */
 
 	if(state != 0)
-		pci_set_power_state(VORTEX_PCI(vp), PCI_D0);
+		pci_enable_device(VORTEX_PCI(vp));
 	spin_lock_irqsave(&vp->lock, flags);
 	EL3WINDOW(4);
 	err = generic_mii_ioctl(&vp->mii, if_mii(rq), cmd, NULL);
@@ -3271,9 +3266,8 @@ static void __devexit vortex_remove_one 
 	unregister_netdev(dev);
 
 	if (VORTEX_PCI(vp)) {
-		pci_set_power_state(VORTEX_PCI(vp), PCI_D0);	/* Go active */
-		if (vp->pm_state_valid)
-			pci_restore_state(VORTEX_PCI(vp));
+		pci_enable_device(VORTEX_PCI(vp)); /* necessary */
+		pci_restore_state(VORTEX_PCI(vp));
 		pci_disable_device(VORTEX_PCI(vp));
 	}
 	/* Should really use issue_and_wait() here */

jwltest-acpi-dsdt-initrd.patch:
 drivers/acpi/Kconfig        |   13 ++++
 drivers/acpi/osl.c          |  115 +++++++++++++++++++++++++++++++++++++-------
 drivers/acpi/tables/tbget.c |    8 ++-
 init/main.c                 |   16 +++---
 4 files changed, 126 insertions(+), 26 deletions(-)

--- NEW FILE jwltest-acpi-dsdt-initrd.patch ---
--- linux-2.6.12/drivers/acpi/Kconfig.orig	2005-06-17 15:48:29.000000000 -0400
+++ linux-2.6.12/drivers/acpi/Kconfig	2005-06-22 12:23:14.467811177 -0400
@@ -352,4 +352,17 @@ config ACPI_HOTPLUG_MEMORY
 		$>modprobe acpi_memhotplug 
 endif	# ACPI
 
+config ACPI_INITRD
+	bool "Read DSDT from initrd or initramfs"
+	depends on ACPI && BLK_DEV_INITRD && !ACPI_CUSTOM_DSDT
+	default n
+	help
+	  The DSDT (Differentiated System Description Table) often needs to be
+	  overridden because of broken BIOS implementations. If you want to use
+	  a customized DSDT, please use the mkinitrd tool (mkinitrd package) to
+	  attach the DSDT to the initrd or initramfs 
+	  (see http://gaugusch.at/kernel.shtml for details)
+	  If there is no DSDT found in the initrd, the DSDT from the BIOS is
+	  used. It is save to say yes here.
+
 endmenu
--- linux-2.6.12/drivers/acpi/osl.c.orig	2005-06-17 15:48:29.000000000 -0400
+++ linux-2.6.12/drivers/acpi/osl.c	2005-06-22 12:23:14.469810910 -0400
@@ -44,7 +44,10 @@
 #include <asm/uaccess.h>
 
 #include <linux/efi.h>
-
+#ifdef CONFIG_ACPI_INITRD
+#include<linux/syscalls.h>
+#include <linux/initrd.h>
+#endif
 
 #define _COMPONENT		ACPI_OS_SERVICES
 ACPI_MODULE_NAME	("osl")
@@ -246,25 +249,105 @@ acpi_os_predefined_override (const struc
 	return AE_OK;
 }
 
-acpi_status
-acpi_os_table_override (struct acpi_table_header *existing_table,
-			struct acpi_table_header **new_table)
-{
-	if (!existing_table || !new_table)
-		return AE_BAD_PARAMETER;
+#ifdef CONFIG_ACPI_INITRD
+static char *
+acpi_find_dsdt_initrd(void)
+{
+	static const char signature[] = "INITRDDSDT123DSDT123";
+	char *dsdt_start = NULL;
+	char *dsdt_buffer = NULL;
+	unsigned long len = 0, len2 = 0;
+	int fd;
+	char ramfs_dsdt_name[10] = "/DSDT.aml";
+	struct kstat stat;
+
+	/* try to get dsdt from tail of initrd */
+	if ((fd = sys_open(ramfs_dsdt_name, O_RDONLY, 0)) < 0) {
+		if (initrd_start) {
+			char *data = (char *)initrd_start;
+
+			printk(KERN_INFO PREFIX "Looking for DSDT in initrd...");
+
+			/* Search for the start signature */
+			while (data < (char *)initrd_end - sizeof(signature) - 4) {
+				if (!memcmp(data, signature, sizeof(signature))) {
+					data += sizeof(signature);
+					if (!memcmp(data, "DSDT", 4))
+						dsdt_start = data;
+					break;
+				}
+				data++;
+			}
 
-#ifdef CONFIG_ACPI_CUSTOM_DSDT
-	if (strncmp(existing_table->signature, "DSDT", 4) == 0)
-		*new_table = (struct acpi_table_header*)AmlCode;
-	else
+			if (dsdt_start){
+				printk(PREFIX " found at offset %zu",
+				       dsdt_start - (char *)initrd_start);
+				len = (char*) initrd_end - dsdt_start;
+				printk(", size: %lu bytes\n", len);
+				dsdt_buffer = ACPI_MEM_ALLOCATE(len + 1);
+				memcpy(dsdt_buffer, dsdt_start, len);
+				*(dsdt_buffer + len + 1)= '\0';
+			}					
+			else
+				printk(" not found!\n");
+		}
+	}
+	/* get dsdt from initramfs */
+	else{
+		printk(KERN_INFO PREFIX "Looking for DSDT in initramfs...");
+		if (vfs_stat(ramfs_dsdt_name, &stat) < 0){
+			printk ("error getting stats for file %s\n", ramfs_dsdt_name);
+			return NULL;
+		}
+		
+		len = stat.size;
+		dsdt_buffer = ACPI_MEM_ALLOCATE(len + 1);
+		if (!dsdt_buffer) {
+			printk("Could not allocate %lu bytes of memory\n", len);
+			return NULL;
+		}
+		printk (" found %s ...", ramfs_dsdt_name);
+		
+		len2 = sys_read (fd, (char __user *) dsdt_buffer, len);
+		if (len2 < len ){
+			printk(PREFIX "\nError trying to read %lu bytes from %s\n", 
+			       len, ramfs_dsdt_name);
+			ACPI_MEM_FREE (dsdt_buffer);
+			dsdt_buffer = NULL;
+		}
+		else{
+			printk(" successfully read %lu bytes from %s\n", 
+			       len, ramfs_dsdt_name);
+			*(dsdt_buffer + len + 1) = '\0';
+		}
+	}
+	if (!dsdt_buffer)
+	    printk(" not found!\n");
+	return dsdt_buffer;
+}
+#endif
+	
+acpi_status
+	acpi_os_table_override (struct acpi_table_header *existing_table,
+				struct acpi_table_header **new_table)
+	{
+		if (!existing_table || !new_table)
+			return AE_BAD_PARAMETER;
+		
 		*new_table = NULL;
-#else
-	*new_table = NULL;
+		if (strncmp(existing_table->signature, "DSDT", 4) == 0) {
+#ifdef CONFIG_ACPI_CUSTOM_DSDT
+			*new_table = (struct acpi_table_header*)AmlCode;
+#elif defined(CONFIG_ACPI_INITRD)
+			*new_table = (struct acpi_table_header*)acpi_find_dsdt_initrd();
 #endif
+			if (*new_table)
+				printk(KERN_INFO PREFIX "Using customized DSDT\n");
+		}
 	return AE_OK;
-}
-
-static irqreturn_t
+	}
+ 
+ static irqreturn_t
 acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	return (*acpi_irq_handler)(acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
--- linux-2.6.12/drivers/acpi/tables/tbget.c.orig	2005-06-17 15:48:29.000000000 -0400
+++ linux-2.6.12/drivers/acpi/tables/tbget.c	2005-06-22 12:23:14.471810644 -0400
@@ -45,7 +45,6 @@
 #include <acpi/acpi.h>
 #include <acpi/actables.h>
 
-
 #define _COMPONENT          ACPI_TABLES
 	 ACPI_MODULE_NAME    ("tbget")
 
@@ -287,12 +286,17 @@ acpi_tb_table_override (
 			acpi_format_exception (status)));
 		return_ACPI_STATUS (status);
 	}
-
+	
 	/* Copy the table info */
 
 	ACPI_REPORT_INFO (("Table [%4.4s] replaced by host OS\n",
 		table_info->pointer->signature));
 
+#ifdef CONFIG_ACPI_INITRD
+	if (new_table)
+	    ACPI_MEM_FREE(new_table);
+#endif
+
 	return_ACPI_STATUS (AE_OK);
 }
 
--- linux-2.6.12/init/main.c.orig	2005-06-22 12:16:17.014413511 -0400
+++ linux-2.6.12/init/main.c	2005-06-22 12:23:14.473810378 -0400
@@ -520,8 +520,6 @@ asmlinkage void __init start_kernel(void
 
 	check_bugs();
 
-	acpi_early_init(); /* before LAPIC and SMP init */
-
 	/* Do the rest non-__init'ed, we're now alive */
 	rest_init();
 }
@@ -651,6 +649,14 @@ static int init(void * unused)
 	 */
 	child_reaper = current;
 
+	/*
+	 * Do this before initcalls, because some drivers want to access
+	 * firmware files.
+	 */
+	populate_rootfs();
+
+	acpi_early_init(); /* before LAPIC and SMP init */
+
 	/* Sets up cpus_possible() */
 	smp_prepare_cpus(max_cpus);
 
@@ -661,12 +667,6 @@ static int init(void * unused)
 
 	cpuset_init_smp();
 
-	/*
-	 * Do this before initcalls, because some drivers want to access
-	 * firmware files.
-	 */
-	populate_rootfs();
-
 	do_basic_setup();
 
 	sched_init_smp();

jwltest-b44-link-check.patch:
 b44.c |    3 +++
 1 files changed, 3 insertions(+)

--- NEW FILE jwltest-b44-link-check.patch ---
--- linux-2.6.11/drivers/net/b44.c.orig	2005-06-07 09:51:48.349772547 -0400
+++ linux-2.6.11/drivers/net/b44.c	2005-06-07 09:55:19.579618942 -0400
@@ -1286,6 +1286,9 @@
 	b44_init_hw(bp);
 	bp->flags |= B44_FLAG_INIT_COMPLETE;
 
+	netif_carrier_off(dev);
+	b44_check_phy(bp);
+
 	spin_unlock_irq(&bp->lock);
 
 	init_timer(&bp->timer);

jwltest-ipw2100-1_1_0.patch:
 Documentation/networking/README.ipw2100               |  162 
 drivers/net/wireless/Kconfig                          |   55 
 drivers/net/wireless/Makefile                         |    4 
 drivers/net/wireless/ieee80211/ieee80211.h            |   85 
 drivers/net/wireless/ieee80211/ieee80211_crypt.c      |    4 
 drivers/net/wireless/ieee80211/ieee80211_crypt.h      |    6 
 drivers/net/wireless/ieee80211/ieee80211_crypt_ccmp.c |    3 
 drivers/net/wireless/ieee80211/ieee80211_crypt_tkip.c |    3 
 drivers/net/wireless/ieee80211/ieee80211_crypt_wep.c  |    4 
 drivers/net/wireless/ieee80211/ieee80211_module.c     |   50 
 drivers/net/wireless/ieee80211/ieee80211_rx.c         |  226 
 drivers/net/wireless/ieee80211/ieee80211_tx.c         |  113 
 drivers/net/wireless/ieee80211/ieee80211_wx.c         |  148 
 drivers/net/wireless/ipw2100.c                        | 8649 +++++++++++++++++
 drivers/net/wireless/ipw2100.h                        | 1278 ++
 drivers/net/wireless/ipw2100/LICENSE                  |  339 
 drivers/net/wireless/ipw2100/Makefile                 |   15 
 drivers/net/wireless/ipw2100/ipw2100.c                | 8972 ------------------
 drivers/net/wireless/ipw2100/ipw2100.h                | 1287 --
 19 files changed, 10409 insertions(+), 10994 deletions(-)

--- NEW FILE jwltest-ipw2100-1_1_0.patch ---
--- linux-2.6.12/Documentation/networking/README.ipw2100.orig	2005-06-22 13:38:36.756298804 -0400
+++ linux-2.6.12/Documentation/networking/README.ipw2100	2005-06-22 13:39:36.938279261 -0400
@@ -1,32 +1,59 @@
 
-Intel PRO/Wireless 2100 802.11b Driver for Linux
+===========================
+Intel(R) PRO/Wireless 2100 Network Connection Driver for Linux
 README.ipw2100
 
-October 13, 2004
+March 14, 2005
 
+===========================
+Index
+---------------------------
+0. Introduction
+1. Release 1.1.0 Current Features
+2. Command Line Parameters
+3. Sysfs Helper Files
+4. Radio Kill Switch
+5. Dynamic Firmware
+6. Power Management
+7. Support
+8. License
 
-Release 0.56 Current Features
+
+===========================
+0. Introduction
 ------------ -----   -----       ----       ---       --         -     
 
-- IBSS and BSS modes
-- 802.11 fragmentation
+This document provides a brief overview of the features supported by the 
+IPW2100 driver project.  The main project website, where the latest 
+development version of the driver can be found, is:
+
+	http://ipw2100.sourceforge.net
+
+There you can find the not only the latest releases, but also information about
+potential fixes and patches, as well as links to the development mailing list
+for the driver project.
+
+
+===========================
+1. Release 1.1.0 Current Supported Features
+---------------------------     
+- Managed (BSS) and Ad-Hoc (IBSS)
 - WEP (shared key and open)
-- wireless extension support 
-- 802.1x EAP via xsupplicant
+- Wireless Tools support 
+- 802.1x (tested with XSupplicant 1.0.1)
+
+Enabled (but not supported) features:
 - Monitor/RFMon mode
-- transmit power control
-- long/short preamble support
-- power states support (ACPI)
+- WPA/WPA2
 
-TODO
------------- -----   -----       ----       ---       --         -     
-- Fix bugs...  The biggies:
-  C3 corruption
-  Fragmentation
+The distinction between officially supported and enabled is a reflection
+on the amount of validation and interoperability testing that has been
+performed on a given feature.
 
 
-Command Line Parameters
------------- -----   -----       ----       ---       --         -     
+===========================
+2. Command Line Parameters
+---------------------------     
 
 If the driver is built as a module, the following optional parameters are used
 by entering them on the command line with the modprobe command using this
@@ -34,54 +61,82 @@ syntax:
 
 	modprobe ipw2100 [<option>=<VAL1><,VAL2>...]
 
-For example, to set the interface name for driver, entering:
-
-	modprobe ipw2100 if_name=wlan%d
+For example, to disable the radio on driver loading, enter:
 
-results in the ipw2100 driver defaulting to the wlan prefix, with the system
-assigning a unique number in place of %d.  The default interface name is eth%d.
+	modprobe ipw2100 disable=1
 
 The ipw2100 driver supports the following module parameters:
 
 Name		Value		Example:
 debug		0x0-0xffffffff	debug=1024
-if_name		string		if_name=wlan%d
 mode		0,1,2		mode=1   /* AdHoc */
 channel		int		channel=3 /* Only valid in AdHoc or Monitor */
 associate	boolean		associate=0 /* Do NOT auto associate */
 disable		boolean		disable=1 /* Do not power the HW */
 
 
-Radio Kill Switch
------------- -----   -----       ----       ---       --         -
-Most laptops provide the ability for the user to physically disable the radio.
-Some vendors have implemented this as a physical switch that requires no
-software to turn the radio off and on.  On other laptops, however, the switch
-is controlled through a button being pressed and a software driver then making
-calls to turn the radio off and on.  This is referred to as a "software based
-RF kill switch"
+===========================
+3. Sysfs Helper Files
+---------------------------     
 
-To determine if you have such a switch, you can check the contents of:
+There are several ways to control the behavior of the driver.  Many of the 
+general capabilities are exposed through the Wireless Tools (iwconfig).  There
+are a few capabilities that are exposed through entries in the Linux Sysfs.
 
-	/sys/bus/pci/drivers/ipw2100/*/rf_kill
 
-A value of:
+----- Driver Level ------
+For the driver level files, look in /sys/bus/pci/drivers/ipw2100/
+
+  debug_level  
 	
-	Radio is {en,dis}abled by RF switch
+	This controls the same global as the 'debug' module parameter.  For 
+        information on the various debugging levels available, run the 'dvals'
+	script found in the driver source directory.
 
-means that you have an RF switch and the radio is in the state 
-described.
+	NOTE:  'debug_level' is only enabled if CONFIG_IPW2100_DEBUG is turn
+	       on.
 
-A value of:
+----- Device Level ------
+For the device level files look in
+	
+	/sys/bus/pci/drivers/ipw2100/{PCI-ID}/
 
-	Your hardware does not have an RF switch
+For example:
+	/sys/bus/pci/drivers/ipw2100/0000:02:01.0
 
-is self explanatory.  In this case you should not need to worry about 
-enabling the radio.
+For the device level files, see /sys/bus/pci/drivers/ipw2100:
 
+  rf_kill
+	read - 
+	0 = RF kill not enabled (radio on)
+	1 = SW based RF kill active (radio off)
+	2 = HW based RF kill active (radio off)
+	3 = Both HW and SW RF kill active (radio off)
+	write -
+	0 = If SW based RF kill active, turn the radio back on
+	1 = If radio is on, activate SW based RF kill
+
+	NOTE: If you enable the SW based RF kill and then toggle the HW
+  	based RF kill from ON -> OFF -> ON, the radio will NOT come back on
+
+
+===========================
+4. Radio Kill Switch
+---------------------------
+Most laptops provide the ability for the user to physically disable the radio.
+Some vendors have implemented this as a physical switch that requires no
+software to turn the radio off and on.  On other laptops, however, the switch
+is controlled through a button being pressed and a software driver then making
+calls to turn the radio off and on.  This is referred to as a "software based
+RF kill switch"
 
-Dynamic Firmware
------------- -----   -----       ----       ---       --         -     
+See the Sysfs helper file 'rf_kill' for determining the state of the RF switch
+on your system.
+
+
+===========================
+5. Dynamic Firmware
+---------------------------     
 As the firmware is licensed under a restricted use license, it can not be 
 included within the kernel sources.  To enable the IPW2100 you will need a 
 firmware image to load into the wireless NIC's processors.
@@ -91,8 +146,9 @@ You can obtain these images from <http:/
 See INSTALL for instructions on installing the firmware.
 
 
-Power Management
------------- -----   -----       ----       ---       --         -     
+===========================
+6. Power Management
+---------------------------     
 The IPW2100 supports the configuration of the Power Save Protocol 
 through a private wireless extension interface.  The IPW2100 supports 
[...22272 lines suppressed...]
+
+
+int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf, size_t max)
+{
+	char ver[MAX_FW_VERSION_LEN];
+	u32 len = MAX_FW_VERSION_LEN;
+	u32 tmp;
+	int i;
+	/* firmware version is an ascii string (max len of 14) */
+	if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM,
+				ver, &len))
+		return -EIO;
+	tmp = max;
+	if (len >= max)
+		len = max - 1;
+	for (i = 0; i < len; i++)
+		buf[i] = ver[i];
+	buf[i] = '\0';
+	return tmp;
+}
+
+int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf, size_t max)
+{
+	u32 ver;
+	u32 len = sizeof(ver);
+	/* microcode version is a 32 bit integer */
+	if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION,
+				&ver, &len))
+		return -EIO;
+	return snprintf(buf, max, "%08X", ver);
+}
+
+/*
+ * On exit, the firmware will have been freed from the fw list
+ */
+int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
+{
+	/* firmware is constructed of N contiguous entries, each entry is
+	 * structured as:
+	 *
+	 * offset    sie         desc
+	 * 0         4           address to write to
+	 * 4         2           length of data run
+         * 6         length      data
+	 */
+	unsigned int addr;
+	unsigned short len;
+
+	const unsigned char *firmware_data = fw->fw.data;
+	unsigned int firmware_data_left = fw->fw.size;
+
+	while (firmware_data_left > 0) {
+	   	addr = *(u32 *)(firmware_data);
+		firmware_data      += 4;
+		firmware_data_left -= 4;
+
+	   	len = *(u16 *)(firmware_data);
+		firmware_data      += 2;
+		firmware_data_left -= 2;
+
+		if (len > 32) {
+			IPW_DEBUG_ERROR(
+			       "Invalid firmware run-length of %d bytes\n",
+			       len);
+			return -EINVAL;
+		}
+
+		write_nic_memory(priv->net_dev, addr, len, firmware_data);
+		firmware_data      += len;
+		firmware_data_left -= len;
+	}
+
+	return 0;
+}
+
+struct symbol_alive_response {
+	u8 cmd_id;
+	u8 seq_num;
+	u8 ucode_rev;
+	u8 eeprom_valid;
+	u16 valid_flags;
+	u8 IEEE_addr[6];
+	u16 flags;
+	u16 pcb_rev;
+	u16 clock_settle_time;	// 1us LSB
+	u16 powerup_settle_time;	// 1us LSB
+	u16 hop_settle_time;	// 1us LSB
+	u8 date[3];		// month, day, year
+	u8 time[2];		// hours, minutes
+	u8 ucode_valid;
+};
+
+int ipw2100_ucode_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
+{
+	struct net_device *dev = priv->net_dev;
+	const unsigned char *microcode_data = fw->uc.data;
+	unsigned int microcode_data_left = fw->uc.size;
+
+	struct symbol_alive_response response;
+	int i, j;
+	u8 data;
+
+	/* Symbol control */
+	write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
+	readl((void *)(dev->base_addr));
+	write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
+	readl((void *)(dev->base_addr));
+
+	/* HW config */
+	write_nic_byte(dev, 0x210014, 0x72);	/* fifo width =16 */
+	readl((void *)(dev->base_addr));
+	write_nic_byte(dev, 0x210014, 0x72);	/* fifo width =16 */
+	readl((void *)(dev->base_addr));
+
+	/* EN_CS_ACCESS bit to reset control store pointer */
+	write_nic_byte(dev, 0x210000, 0x40);
+	readl((void *)(dev->base_addr));
+	write_nic_byte(dev, 0x210000, 0x0);
+	readl((void *)(dev->base_addr));
+	write_nic_byte(dev, 0x210000, 0x40);
+	readl((void *)(dev->base_addr));
+
+	/* copy microcode from buffer into Symbol */
+
+	while (microcode_data_left > 0) {
+		write_nic_byte(dev, 0x210010, *microcode_data++);
+		write_nic_byte(dev, 0x210010, *microcode_data++);
+		microcode_data_left -= 2;
+	}
+
+	/* EN_CS_ACCESS bit to reset the control store pointer */
+	write_nic_byte(dev, 0x210000, 0x0);
+	readl((void *)(dev->base_addr));
+
+	/* Enable System (Reg 0)
+	 * first enable causes garbage in RX FIFO */
+	write_nic_byte(dev, 0x210000, 0x0);
+	readl((void *)(dev->base_addr));
+	write_nic_byte(dev, 0x210000, 0x80);
+	readl((void *)(dev->base_addr));
+
+	/* Reset External Baseband Reg */
+	write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
+	readl((void *)(dev->base_addr));
+	write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
+	readl((void *)(dev->base_addr));
+
+	/* HW Config (Reg 5) */
+	write_nic_byte(dev, 0x210014, 0x72);	// fifo width =16
+	readl((void *)(dev->base_addr));
+	write_nic_byte(dev, 0x210014, 0x72);	// fifo width =16
+	readl((void *)(dev->base_addr));
+
+	/* Enable System (Reg 0)
+	 * second enable should be OK */
+	write_nic_byte(dev, 0x210000, 0x00);	// clear enable system
+	readl((void *)(dev->base_addr));
+	write_nic_byte(dev, 0x210000, 0x80);	// set enable system
+
+	/* check Symbol is enabled - upped this from 5 as it wasn't always
+	 * catching the update */
+	for (i = 0; i < 10; i++) {
+		udelay(10);
+
+		/* check Dino is enabled bit */
+		read_nic_byte(dev, 0x210000, &data);
+		if (data & 0x1)
+			break;
+	}
+
+	if (i == 10) {
+		IPW_DEBUG_ERROR("%s: Error initializing Symbol\n",
+		       dev->name);
+		return -EIO;
+	}
+
+	/* Get Symbol alive response */
+	for (i = 0; i < 30; i++) {
+		/* Read alive response structure */
+		for (j = 0;
+		     j < (sizeof(struct symbol_alive_response) >> 1);
+		     j++)
+			read_nic_word(dev, 0x210004,
+				      ((u16 *)&response) + j);
+
+		if ((response.cmd_id == 1) &&
+		    (response.ucode_valid == 0x1))
+			break;
+		udelay(10);
+	}
+
+	if (i == 30) {
+		IPW_DEBUG_ERROR("%s: No response from Symbol - hw not alive\n",
+		       dev->name);
+		printk_buf(IPW_DL_ERROR, (u8*)&response, sizeof(response));
+		return -EIO;
+	}
+
+	return 0;
+}

jwltest-libata-atapi.patch:
 libata.h |    2 +-
 1 files changed, 1 insertion(+), 1 deletion(-)

--- NEW FILE jwltest-libata-atapi.patch ---
--- linux-2.6.12/include/linux/libata.h.orig	2005-08-25 14:14:43.897051684 -0400
+++ linux-2.6.12/include/linux/libata.h	2005-08-25 14:14:52.513903753 -0400
@@ -37,7 +37,7 @@
 #undef ATA_VERBOSE_DEBUG	/* yet more debugging output */
 #undef ATA_IRQ_TRAP		/* define to ack screaming irqs */
 #undef ATA_NDEBUG		/* define to disable quick runtime checks */
-#undef ATA_ENABLE_ATAPI		/* define to enable ATAPI support */
+#define ATA_ENABLE_ATAPI	/* define to enable ATAPI support */
 #undef ATA_ENABLE_PATA		/* define to enable PATA support in some
 				 * low-level drivers */
 #undef ATAPI_ENABLE_DMADIR	/* enables ATAPI DMADIR bridge support */

jwltest-pci-d3hot-d0.patch:
 drivers/pci/pci.c       |   52 ++++++++++++++++++++++++++++++++++++++++++++----
 drivers/pci/setup-res.c |    2 -
 include/linux/pci.h     |    2 +
 3 files changed, 51 insertions(+), 5 deletions(-)

--- NEW FILE jwltest-pci-d3hot-d0.patch ---
--- linux-2.6.12/include/linux/pci.h.orig	2005-07-07 16:01:11.852353507 -0400
+++ linux-2.6.12/include/linux/pci.h	2005-07-07 16:02:10.176581506 -0400
@@ -225,6 +225,7 @@
 #define  PCI_PM_CAP_PME_D3cold  0x8000  /* PME# from D3 (cold) */
 #define PCI_PM_CTRL		4	/* PM control and status register */
 #define  PCI_PM_CTRL_STATE_MASK	0x0003	/* Current power state (D0 to D3) */
+#define  PCI_PM_CTRL_NO_SOFT_RESET	0x0004	/* No reset for D3hot->D0 */
 #define  PCI_PM_CTRL_PME_ENABLE	0x0100	/* PME pin enable */
 #define  PCI_PM_CTRL_DATA_SEL_MASK	0x1e00	/* Data select (??) */
 #define  PCI_PM_CTRL_DATA_SCALE_MASK	0x6000	/* Data scale (??) */
@@ -812,6 +813,7 @@ int __must_check pci_set_mwi(struct pci_
 void pci_clear_mwi(struct pci_dev *dev);
 int __must_check pci_set_dma_mask(struct pci_dev *dev, u64 mask);
 int __must_check pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
+void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
 int pci_assign_resource(struct pci_dev *dev, int i);
 
 /* ROM control related routines */
--- linux-2.6.12/drivers/pci/setup-res.c.orig	2005-06-17 15:48:29.000000000 -0400
+++ linux-2.6.12/drivers/pci/setup-res.c	2005-07-07 16:01:21.070125186 -0400
@@ -26,7 +26,7 @@
 #include "pci.h"
 
 
-static void
+void
 pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
 {
 	struct pci_bus_region region;
--- linux-2.6.12/drivers/pci/pci.c.orig	2005-07-07 16:01:11.854353241 -0400
+++ linux-2.6.12/drivers/pci/pci.c	2005-07-07 16:01:21.068125453 -0400
@@ -222,6 +222,37 @@ pci_find_parent_resource(const struct pc
 }
 
 /**
+ * pci_restore_bars - restore a devices BAR values (e.g. after wake-up)
+ * @dev: PCI device to have its BARs restored
+ *
+ * Restore the BAR values for a given device, so as to make it
+ * accessible by its driver.
+ */
+static void
+pci_restore_bars(struct pci_dev *dev)
+{
+	int i, numres;
+
+	switch (dev->hdr_type) {
+	case PCI_HEADER_TYPE_NORMAL:
+		numres = 6;
+		break;
+	case PCI_HEADER_TYPE_BRIDGE:
+		numres = 2;
+		break;
+	case PCI_HEADER_TYPE_CARDBUS:
+		numres = 1;
+		break;
+	default:
+		/* Should never get here, but just in case... */
+		return;
+	}
+
+	for (i = 0; i < numres; i ++)
+		pci_update_resource(dev, &dev->resource[i], i);
+}
+
+/**
  * pci_set_power_state - Set the power state of a PCI device
  * @dev: PCI device to be suspended
  * @state: PCI power state (D0, D1, D2, D3hot, D3cold) we're entering
@@ -239,7 +270,7 @@ pci_find_parent_resource(const struct pc
 int
 pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 {
-	int pm;
+	int pm, need_restore = 0;
 	u16 pmcsr, pmc;
 
 	/* bound the state we're entering */
@@ -278,14 +309,17 @@ pci_set_power_state(struct pci_dev *dev,
 			return -EIO;
 	}
 
+	pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+
 	/* If we're in D3, force entire word to 0.
 	 * This doesn't affect PME_Status, disables PME_En, and
 	 * sets PowerState to 0.
 	 */
-	if (dev->current_state >= PCI_D3hot)
+	if (dev->current_state >= PCI_D3hot) {
+		if (!(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
+			need_restore = 1;
 		pmcsr = 0;
-	else {
-		pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+	} else {
 		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
 		pmcsr |= state;
 	}
@@ -301,6 +335,16 @@ pci_set_power_state(struct pci_dev *dev,
 		udelay(200);
 	dev->current_state = state;
 
+	/* According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT
+	 * INTERFACE SPECIFICATION, REV. 1.2", a device transitioning
+	 * from D3hot to D0 _may_ perform an internal reset, thereby
+	 * going to "D0 Uninitialized" rather than "D0 Initialized".
+	 * In that case, we need to restore at least the BARs so that
+	 * the device will be accessible to its driver.
+	 */
+	if (need_restore)
+		pci_restore_bars(dev);
+
 	return 0;
 }
 

jwltest-sundance-icplus.patch:
 Makefile          |    1 
 sundance-icplus.c | 1895 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1896 insertions(+)

--- NEW FILE jwltest-sundance-icplus.patch ---
--- linux-2.6.12/drivers/net/sundance-icplus.c.orig	2005-08-25 13:57:51.958876430 -0400
+++ linux-2.6.12/drivers/net/sundance-icplus.c	2005-08-25 14:12:06.609006080 -0400
@@ -0,0 +1,1895 @@
+/* sundance.c: A Linux device driver for the Sundance ST201 "Alta". */
+/*
+	Written 1999-2000 by Donald Becker.
+
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
+
+	The author may be reached as becker at scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
+
+	Support and updates available at
+	http://www.scyld.com/network/sundance.html
+
+
+	Version LK1.01a (jgarzik):
+	- Replace some MII-related magic numbers with constants
+
+	Version LK1.02 (D-Link):
+	- Add new board to PCI ID list
+	- Fix multicast bug
+
+	Version LK1.03 (D-Link):
+	- New Rx scheme, reduce Rx congestion
+	- Option to disable flow control
+
+	Version LK1.04 (D-Link):
+	- Tx timeout recovery
+	- More support for ethtool.
+
+	Version LK1.04a:
+	- Remove unused/constant members from struct pci_id_info
+	(which then allows removal of 'drv_flags' from private struct)
+	(jgarzik)
+	- If no phy is found, fail to load that board (jgarzik)
+	- Always start phy id scan at id 1 to avoid problems (Donald Becker)
+	- Autodetect where mii_preable_required is needed,
+	default to not needed.  (Donald Becker)
+
+	Version LK1.04b:
+	- Remove mii_preamble_required module parameter (Donald Becker)
+	- Add per-interface mii_preamble_required (setting is autodetected)
+	  (Donald Becker)
+	- Remove unnecessary cast from void pointer (jgarzik)
+	- Re-align comments in private struct (jgarzik)
+
+	Version LK1.04c (jgarzik):
+	- Support bitmapped message levels (NETIF_MSG_xxx), and the
+	  two ethtool ioctls that get/set them
+	- Don't hand-code MII ethtool support, use standard API/lib
+
+	Version LK1.04d:
+	- Merge from Donald Becker's sundance.c: (Jason Lunz)
+		* proper support for variably-sized MTUs
+		* default to PIO, to fix chip bugs
+	- Add missing unregister_netdev (Jason Lunz)
+	- Add CONFIG_SUNDANCE_MMIO config option (jgarzik)
+	- Better rx buf size calculation (Donald Becker)
+
+	Version LK1.05 (D-Link):
+	- Fix DFE-580TX packet drop issue (for DL10050C)
+	- Fix reset_tx logic
+
+	Version LK1.06 (D-Link):
+	- Fix crash while unloading driver
+
+	Versin LK1.06b (D-Link):
+	- New tx scheme, adaptive tx_coalesce
+
+	Version LK1.07 (D-Link):
+	- Fix tx bugs in big-endian machines
+	- Remove unused max_interrupt_work module parameter, the new
+	  NAPI-like rx scheme doesn't need it.
+	- Remove redundancy get_stats() in intr_handler(), those
+	  I/O access could affect performance in ARM-based system
+	- Add Linux software VLAN support
+
+	Version LK1.08 (D-Link):
+	- Fix bug of custom mac address
+	(StationAddr register only accept word write)
+
+	Version LK1.09 (D-Link):
+	- Fix the flowctrl bug.
+	- Set Pause bit in MII ANAR if flow control enabled.
+
+	Version LK1.10 (D-Link):
+	- Fix tx timeout when MaxCollions error.
+
+	Version LK1.11 (IC Plus) <Jesse Huang>
+	- Start phy id scan at id 0.
+
+	Version LK1.12 (IC Plus):
+	- Change Vendor from Sundance to IC Plus
+	- Change MODULE_DESCRIPTION to "IC Plus Fast Ethernet Driver"
+	- Add Device ID 0200
+
+	Version LK1.13 (IC Plus)
+	- Update Global reset
+	
+	Version LK1.14 (IC Plus) <Jesse Huang>
+	-Fix parameter "media" for change speed function. //20040817Jesse_ChangeSpeed
+	
+	Version LK1.15 (IC Plus) <Jesse Huang>
+	-Mask memory base address and IO base address bit 0 to 6.//20040826Jesse_mask_BaseAddr
+	
+	Version LK1.16 (IC Plus) <Jesse Huang>
+	-Support for kernel 2.6.x
+	
+	Version LK1.17b (IC Plus) <Jesse Huang>
+	- Modify function form pci_dma_sync_single() to pci_dma_sync_single_for_cpu()
+	- (Thanks for Moz Lala's support)
+	
+	Version LK1.19 (IC Plus) <Jesse Huang>
+	- After 2.6.11, changed slot_name to pci_name().
+*/
+
+#define DRV_NAME	"sundance"
+#define DRV_VERSION	"1.01+LK1.19"
+#define DRV_RELDATE	"03-08-2005"
+
+
+/* The user-configurable values.
+   These may be modified when a driver module is loaded.*/
+static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
+   Typical is a 64 element hash table based on the Ethernet CRC.  */
+static int multicast_filter_limit = 32;
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1518 effectively disables this feature.
+   This chip can receive into offset buffers, so the Alpha does not
+   need a copy-align. */
+static int rx_copybreak;
+static int flowctrl=1;
+
+/* media[] specifies the media type the NIC operates at.
+		 autosense	Autosensing active media.
+		 10mbps_hd 	10Mbps half duplex.
+		 10mbps_fd 	10Mbps full duplex.
+		 100mbps_hd 	100Mbps half duplex.
+		 100mbps_fd 	100Mbps full duplex.
+		 0		Autosensing active media.
+		 1	 	10Mbps half duplex.
+		 2	 	10Mbps full duplex.
+		 3	 	100Mbps half duplex.
+		 4	 	100Mbps full duplex.
+*/
+#define MAX_UNITS 8
+static char *media[MAX_UNITS];
+
+
+/* Operational parameters that are set at compile time. */
+
+/* Keep the ring sizes a power of two for compile efficiency.
+   The compiler will convert <unsigned>'%'<2^N> into a bit mask.
+   Making the Tx ring too large decreases the effectiveness of channel
+   bonding and packet priority, and more than 128 requires modifying the
+   Tx error recovery.
+   Large receive rings merely waste memory. */
+#define TX_RING_SIZE	32
+#define TX_QUEUE_LEN	(TX_RING_SIZE - 1) /* Limit ring entries actually used.  */
+#define RX_RING_SIZE	64
+#define RX_BUDGET	32
+#define TX_TOTAL_SIZE	TX_RING_SIZE*sizeof(struct netdev_desc)
+#define RX_TOTAL_SIZE	RX_RING_SIZE*sizeof(struct netdev_desc)
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (4*HZ)
+#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer.*/
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+#if !defined(__OPTIMIZE__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+/* Include files, designed to support most kernel versions 2.0.0 and later. */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#ifndef _COMPAT_WITH_OLD_KERNEL
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#else
+#include "crc32.h"
+#include "ethtool.h"
+#include "mii.h"
+#include "compat.h"
+#endif
+
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Written by Donald Becker\n"
+KERN_INFO "  http://www.scyld.com/network/sundance.html\n";
+
+MODULE_AUTHOR("Donald Becker <becker at scyld.com>");
+// 04/13/2004 MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
+MODULE_DESCRIPTION("IC Plus Fast Ethernet driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s");
+MODULE_PARM(flowctrl, "i");
+MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
+MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]");
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This driver is designed for the Sundance Technologies "Alta" ST201 chip.
+
+II. Board-specific settings
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+This driver uses two statically allocated fixed-size descriptor lists
+formed into rings by a branch from the final descriptor to the beginning of
+the list.  The ring sizes are set at compile time by RX/TX_RING_SIZE.
+Some chips explicitly use only 2^N sized rings, while others use a
+'next descriptor' pointer that the driver forms into rings.
+
+IIIb/c. Transmit/Receive Structure
+
+This driver uses a zero-copy receive and transmit scheme.
+The driver allocates full frame size skbuffs for the Rx ring buffers at
+open() time and passes the skb->data field to the chip as receive data
+buffers.  When an incoming frame is less than RX_COPYBREAK bytes long,
+a fresh skbuff is allocated and the frame is copied to the new skbuff.
+When the incoming frame is larger, the skbuff is passed directly up the
+protocol stack.  Buffers consumed this way are replaced by newly allocated
+skbuffs in a later phase of receives.
+
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames.  New boards are typically used in generously configured machines
+and the underfilled buffers have negligible impact compared to the benefit of
+a single allocation size, so the default value of zero results in never
+copying packets.  When copying is done, the cost is usually mitigated by using
+a combined copy/checksum routine.  Copying also preloads the cache, which is
+most useful with small frames.
+
+A subtle aspect of the operation is that the IP header at offset 14 in an
+ethernet frame isn't longword aligned for further processing.
+Unaligned buffers are permitted by the Sundance hardware, so
+frames are received into the skbuff at an offset of "+2", 16-byte aligning
+the IP header.
+
+IIId. Synchronization
+
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and interrupt handling software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'lp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
+clears both the tx_full and tbusy flags.
+
+IV. Notes
+
+IVb. References
+
+The Sundance ST201 datasheet, preliminary version.
+http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+
+IVc. Errata
+
+*/
+
+/* Work-around for Kendin chip bugs. */
+#ifndef CONFIG_SUNDANCE_MMIO
+#define USE_IO_OPS 1
+#endif
+
+static struct pci_device_id sundance_pci_tbl[] __devinitdata = {
+	{0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0},
+	{0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1},
+	{0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2},
+	{0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3},
+	{0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{0,}
+};
+MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
+
+enum {
+	netdev_io_size = 128
+};
+
+struct pci_id_info {
+        const char *name;
+};
+static struct pci_id_info pci_id_tbl[] = {
+	{"D-Link DFE-550TX FAST Ethernet Adapter"},
+	{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
+	{"D-Link DFE-580TX 4 port Server Adapter"},
+	{"D-Link DFE-530TXS FAST Ethernet Adapter"},
+	{"D-Link DL10050-based FAST Ethernet Adapter"},
+// 04/13/2004 	{"Sundance Technology Alta"},
+    {"IC Plus IP100 Fast Ethernet Adapter"},
+    {"IC Plus IP100A Fast Ethernet Adapter" },
+	{0,},			/* 0 terminated list. */
+};
+
+/* Offsets to the device registers.
+   Unlike software-only systems, device drivers interact with complex hardware.
+   It's not useful to define symbolic names for every register bit in the
+   device.  The name can only partially document the semantics and make
+   the driver longer and more difficult to read.
+   In general, only the important configuration values or bits changed
+   multiple times should be defined symbolically.
+*/
+enum alta_offsets {
+	DMACtrl = 0x00,
+	TxListPtr = 0x04,
+	TxDMABurstThresh = 0x08,
+	TxDMAUrgentThresh = 0x09,
+	TxDMAPollPeriod = 0x0a,
+	RxDMAStatus = 0x0c,
+	RxListPtr = 0x10,
+	DebugCtrl0 = 0x1a,
+	DebugCtrl1 = 0x1c,
+	RxDMABurstThresh = 0x14,
+	RxDMAUrgentThresh = 0x15,
+	RxDMAPollPeriod = 0x16,
+	LEDCtrl = 0x1a,
+	ASICCtrl = 0x30,
+	EEData = 0x34,
+	EECtrl = 0x36,
+	TxStartThresh = 0x3c,
+	RxEarlyThresh = 0x3e,
+	FlashAddr = 0x40,
+	FlashData = 0x44,
+	TxStatus = 0x46,
+	TxFrameId = 0x47,
+	DownCounter = 0x18,
+	IntrClear = 0x4a,
+	IntrEnable = 0x4c,
+	IntrStatus = 0x4e,
+	MACCtrl0 = 0x50,
+	MACCtrl1 = 0x52,
+	StationAddr = 0x54,
+	MaxFrameSize = 0x5A,
+	RxMode = 0x5c,
+	MIICtrl = 0x5e,
+	MulticastFilter0 = 0x60,
+	MulticastFilter1 = 0x64,
+	RxOctetsLow = 0x68,
+	RxOctetsHigh = 0x6a,
+	TxOctetsLow = 0x6c,
+	TxOctetsHigh = 0x6e,
+	TxFramesOK = 0x70,
+	RxFramesOK = 0x72,
+	StatsCarrierError = 0x74,
+	StatsLateColl = 0x75,
+	StatsMultiColl = 0x76,
+	StatsOneColl = 0x77,
+	StatsTxDefer = 0x78,
+	RxMissed = 0x79,
+	StatsTxXSDefer = 0x7a,
+	StatsTxAbort = 0x7b,
+	StatsBcastTx = 0x7c,
+	StatsBcastRx = 0x7d,
+	StatsMcastTx = 0x7e,
+	StatsMcastRx = 0x7f,
+	/* Aliased and bogus values! */
+	RxStatus = 0x0c,
+};
+enum ASICCtrl_HiWord_bit {
+	GlobalReset = 0x0001,
+	RxReset = 0x0002,
+	TxReset = 0x0004,
+	DMAReset = 0x0008,
+	FIFOReset = 0x0010,
+	NetworkReset = 0x0020,
+	HostReset = 0x0040,
+	ResetBusy = 0x0400,
+};
+
+/* Bits in the interrupt status/mask registers. */
+enum intr_status_bits {
+	IntrSummary=0x0001, IntrPCIErr=0x0002, IntrMACCtrl=0x0008,
+	IntrTxDone=0x0004, IntrRxDone=0x0010, IntrRxStart=0x0020,
+	IntrDrvRqst=0x0040,
+	StatsMax=0x0080, LinkChange=0x0100,
+	IntrTxDMADone=0x0200, IntrRxDMADone=0x0400,
+};
+
+/* Bits in the RxMode register. */
+enum rx_mode_bits {
+	AcceptAllIPMulti=0x20, AcceptMultiHash=0x10, AcceptAll=0x08,
+	AcceptBroadcast=0x04, AcceptMulticast=0x02, AcceptMyPhys=0x01,
+};
+/* Bits in MACCtrl. */
+enum mac_ctrl0_bits {
+	EnbFullDuplex=0x20, EnbRcvLargeFrame=0x40,
+	EnbFlowCtrl=0x100, EnbPassRxCRC=0x200,
+};
+enum mac_ctrl1_bits {
+	StatsEnable=0x0020,	StatsDisable=0x0040, StatsEnabled=0x0080,
+	TxEnable=0x0100, TxDisable=0x0200, TxEnabled=0x0400,
+	RxEnable=0x0800, RxDisable=0x1000, RxEnabled=0x2000,
+};
+
+/* The Rx and Tx buffer descriptors. */
+/* Note that using only 32 bit fields simplifies conversion to big-endian
+   architectures. */
+struct netdev_desc {
+	u32 next_desc;
+	u32 status;
+	struct desc_frag { u32 addr, length; } frag[1];
+};
+
+/* Bits in netdev_desc.status */
+enum desc_status_bits {
+	DescOwn=0x8000,
+	DescEndPacket=0x4000,
+	DescEndRing=0x2000,
+	LastFrag=0x80000000,
+	DescIntrOnTx=0x8000,
+	DescIntrOnDMADone=0x80000000,
+	DisableAlign = 0x00000001,
+};
+
+#define PRIV_ALIGN	15 	/* Required alignment mask */
+/* Use  __attribute__((aligned (L1_CACHE_BYTES)))  to maintain alignment
+   within the structure. */
+#define MII_CNT		4
+struct netdev_private {
+	/* Descriptor rings first for alignment. */
+	struct netdev_desc *rx_ring;
+	struct netdev_desc *tx_ring;
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+        dma_addr_t tx_ring_dma;
+        dma_addr_t rx_ring_dma;
+	struct net_device_stats stats;
+	struct timer_list timer;		/* Media monitoring timer. */
+	/* Frequently used values: keep some adjacent for cache effect. */
+	spinlock_t lock;
+	spinlock_t rx_lock;			/* Group with Tx control cache line. */
+	int msg_enable;
+	int chip_id;
+	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
+	unsigned int rx_buf_sz;			/* Based on MTU+slack. */
+	struct netdev_desc *last_tx;		/* Last Tx descriptor used. */
+	unsigned int cur_tx, dirty_tx;
+	/* These values are keep track of the transceiver/media in use. */
+	unsigned int flowctrl:1;
+	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int an_enable:1;
+	unsigned int speed;
+	struct tasklet_struct rx_tasklet;
+	struct tasklet_struct tx_tasklet;
+	int budget;
+	int cur_task;
+	/* Multicast and receive mode. */
+	spinlock_t mcastlock;			/* SMP lock multicast updates. */
+	u16 mcast_filter[4];
+	/* MII transceiver section. */
+	struct mii_if_info mii_if;
+	int mii_preamble_required;
+	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
+	struct pci_dev *pci_dev;
+	void __iomem *base;
+	unsigned char pci_rev_id;
+};
+
+/* The station address location in the EEPROM. */
+#define EEPROM_SA_OFFSET	0x10
+#define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \
+			IntrDrvRqst | IntrTxDone | StatsMax | \
+			LinkChange)
+
+static int  change_mtu(struct net_device *dev, int new_mtu);
+static int  eeprom_read(void __iomem *ioaddr, int location);
+static int  mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
+static int  netdev_open(struct net_device *dev);
+static void check_duplex(struct net_device *dev);
+static void netdev_timer(unsigned long data);
+static void tx_timeout(struct net_device *dev);
+static void init_ring(struct net_device *dev);
+static int  start_tx(struct sk_buff *skb, struct net_device *dev);
+static int reset_tx (struct net_device *dev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) 
+static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+#else
+static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+#endif
+static void rx_poll(unsigned long data);
+static void tx_poll(unsigned long data);
+static void refill_rx (struct net_device *dev);
+static void netdev_error(struct net_device *dev, int intr_status);
+static void netdev_error(struct net_device *dev, int intr_status);
+static void set_rx_mode(struct net_device *dev);
+static int __set_mac_addr(struct net_device *dev);
+static struct net_device_stats *get_stats(struct net_device *dev);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int  netdev_close(struct net_device *dev);
+
+
+
+static int __devinit sundance_probe1 (struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	struct net_device *dev;
+	struct netdev_private *np;
+	static int card_idx;
+	int chip_idx = ent->driver_data;
+	int irq;
+	int i;
+	void __iomem *ioaddr;
+	u16 mii_ctl,mii_avt;
+	void *ring_space;
+	dma_addr_t ring_dma;
+#ifdef USE_IO_OPS
+	int bar = 0;
+#else
+	int bar = 1;
+#endif
+
+
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
+
+	if (pci_enable_device(pdev))
+		return -EIO;
+	pci_set_master(pdev);
+
+	irq = pdev->irq;
+
+	dev = alloc_etherdev(sizeof(*np));
+	if (!dev)
+		return -ENOMEM;
+	SET_MODULE_OWNER(dev);
+
+	if (pci_request_regions(pdev, DRV_NAME))
+		goto err_out_netdev;
+
+	ioaddr = pci_iomap(pdev, bar, netdev_io_size);
+	if (!ioaddr)
+		goto err_out_res;
+
+	for (i = 0; i < 3; i++)
+		((u16 *)dev->dev_addr)[i] =
+			le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET));
+
+	dev->base_addr = (unsigned long)ioaddr;
+	dev->irq = irq;
+
+	np = dev->priv;
+	np->base = ioaddr;
+	np->pci_dev = pdev;
+	np->chip_id = chip_idx;
+	np->msg_enable = (1 << debug) - 1;
+	spin_lock_init(&np->lock);
+	tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev);
+	tasklet_init(&np->tx_tasklet, tx_poll, (unsigned long)dev);
+
+	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
+	if (!ring_space)
+		goto err_out_cleardev;
+	np->tx_ring = (struct netdev_desc *)ring_space;
+	np->tx_ring_dma = ring_dma;
+
+	ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
+	if (!ring_space)
+		goto err_out_unmap_tx;
+	np->rx_ring = (struct netdev_desc *)ring_space;
+	np->rx_ring_dma = ring_dma;
+
+	np->mii_if.dev = dev;
+	np->mii_if.mdio_read = mdio_read;
+	np->mii_if.mdio_write = mdio_write;
+	np->mii_if.phy_id_mask = 0x1f;
+	np->mii_if.reg_num_mask = 0x1f;
+
+	/* The chip-specific entries in the device structure. */
+	dev->open = &netdev_open;
+	dev->hard_start_xmit = &start_tx;
+	dev->stop = &netdev_close;
+	dev->get_stats = &get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+	dev->do_ioctl = &netdev_ioctl;
+	dev->tx_timeout = &tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->change_mtu = &change_mtu;
+	pci_set_drvdata(pdev, dev);
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
+
+	i = register_netdev(dev);
+	if (i)
+		goto err_out_unmap_rx;
+
+	printk(KERN_INFO "%s: %s at %p, ",
+		   dev->name, pci_id_tbl[chip_idx].name, ioaddr);
+	for (i = 0; i < 5; i++)
+			printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+
+	if (1) {
+		int phy, phy_idx = 0;
+		np->phys[0] = 1;		/* Default setting */
+		np->mii_preamble_required++;
+		//for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {//Modify by Jesse
+		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
+			int mii_status = mdio_read(dev, phy, MII_BMSR);
+			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				np->phys[phy_idx++] = phy;
+				np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
+				if ((mii_status & 0x0040) == 0)
+					np->mii_preamble_required++;
+				printk(KERN_INFO "%s: MII PHY found at address %d, status "
+					   "0x%4.4x advertising %4.4x.\n",
+					   dev->name, phy, mii_status, np->mii_if.advertising);
+			}
+		}
+		np->mii_preamble_required--;
+
+		if (phy_idx == 0) {
+			printk(KERN_INFO "%s: No MII transceiver found, aborting.  ASIC status %x\n",
+				   dev->name, ioread32(ioaddr + ASICCtrl));
+			goto err_out_unregister;
+		}
+
+		np->mii_if.phy_id = np->phys[0];
+	}
+
+	/* Parse override configuration */
+	np->an_enable = 1;
+	if (card_idx < MAX_UNITS) {
+		if (media[card_idx] != NULL) {
+			np->an_enable = 0;
+			if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
+			    strcmp (media[card_idx], "4") == 0) {
+				np->speed = 100;
+				np->mii_if.full_duplex = 1;
+			} else if (strcmp (media[card_idx], "100mbps_hd") == 0
+				   || strcmp (media[card_idx], "3") == 0) {
+				np->speed = 100;
+				np->mii_if.full_duplex = 0;
+			} else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
+				   strcmp (media[card_idx], "2") == 0) {
+				np->speed = 10;
+				np->mii_if.full_duplex = 1;
+			} else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
+				   strcmp (media[card_idx], "1") == 0) {
+				np->speed = 10;
+				np->mii_if.full_duplex = 0;
+			} else {
+				np->an_enable = 1;
+			}
+		}
+		if (flowctrl == 1)
+			np->flowctrl = 1;
+	}
+
+	/* Fibre PHY? */
+	if (ioread32 (ioaddr + ASICCtrl) & 0x80) {
+		/* Default 100Mbps Full */
+		if (np->an_enable) {
+			np->speed = 100;
+			np->mii_if.full_duplex = 1;
+			np->an_enable = 0;
+		}
+	}
+	/* Reset PHY */
+	mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET);
+	mdelay (300);
+	/* If flow control enabled, we need to advertise it.*/
+	if (np->flowctrl)
+		mdio_write (dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising | 0x0400);
+	//mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);//20040817Jesse_ChangeSpeed: Remove
+	/* Force media type */
+	if (!np->an_enable) {
+		//20040817Jesse_ChangeSpeed:remove
+/*		mii_ctl = 0;
+		mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0;
+		mii_ctl |= (np->mii_if.full_duplex) ? BMCR_FULLDPLX : 0;
+		mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl);
+		printk (KERN_INFO "Override speed=%d, %s duplex\n",
+			np->speed, np->mii_if.full_duplex ? "Full" : "Half");*/
+                
+      //20040817Jesse_ChangeSpeed:Add
+		mii_ctl=(mdio_read(dev,np->phys[0],MII_BMCR)&0x0000ffff);
+      mii_avt=(mdio_read(dev,np->phys[0],MII_ADVERTISE)&~(ADVERTISE_100FULL+ADVERTISE_100HALF+ADVERTISE_10FULL+ADVERTISE_10HALF));
+      if(np->speed==100)
+		{
+		   mii_avt|=(np->mii_if.full_duplex)?ADVERTISE_100FULL:ADVERTISE_100HALF;
+		}
+		else
+		{
+		   mii_avt|=(np->mii_if.full_duplex)?ADVERTISE_10FULL:ADVERTISE_10HALF;
+		}
+                mdio_write(dev,np->phys[0],MII_ADVERTISE,mii_avt);
+                mdio_write(dev,np->phys[0],MII_BMCR,mii_ctl|0x1000|0x200);
+	}
+	else
+   {
+	mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);//20040817Jesse_ChangeSpeed: move to here
+   }
+   //20040817Jesse_ChangeSpeed: Add
+   for(i=1000;i;i--)
+	{
+	   mdelay(1);
+      if(mdio_read(dev,np->phys[0],MII_BMSR)&0x20)break;
+   }
+   
+	/* Perhaps move the reset here? */
+	/* Reset the chip to erase previous misconfiguration. */
+	if (netif_msg_hw(np))
+		printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl));
+
+	// 07/24/2004 Grace set AUTOINIT
+	//iowrite16(0x007f, ioaddr + ASICCtrl + 2);
+	iowrite16(0x00ff, ioaddr + ASICCtrl + 2);
+	if (netif_msg_hw(np))
+		printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl));
+
+	card_idx++;
+	return 0;
+
+err_out_unregister:
+	unregister_netdev(dev);
+err_out_unmap_rx:
+        pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
+err_out_unmap_tx:
+        pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);
+err_out_cleardev:
+	pci_set_drvdata(pdev, NULL);
+	pci_iounmap(pdev, ioaddr);
+err_out_res:
+	pci_release_regions(pdev);
+err_out_netdev:
+	kfree (dev);
+	return -ENODEV;
+}
+
+static int change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > 8191)) /* Set by RxDMAFrameLen */
+		return -EINVAL;
+	if (netif_running(dev))
+		return -EBUSY;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
+static int __devinit eeprom_read(void __iomem *ioaddr, int location)
+{
+	int boguscnt = 1000;		/* Typical 190 ticks. */
+	iowrite16(0x0200 | (location & 0xff), ioaddr + EECtrl);
+	do {
+		if (! (ioread16(ioaddr + EECtrl) & 0x8000)) {
+			return ioread16(ioaddr + EEData);
+		}
+	} while (--boguscnt > 0);
+	return 0;
+}
+
+/*  MII transceiver control section.
+	Read and write the MII registers using software-generated serial
+	MDIO protocol.  See the MII specifications or DP83840A data sheet
+	for details.
+
+	The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+	met by back-to-back 33Mhz PCI cycles. */
+#define mdio_delay() ioread8(mdio_addr)
+
+enum mii_reg_bits {
+	MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
+};
+#define MDIO_EnbIn  (0)
+#define MDIO_WRITE0 (MDIO_EnbOutput)
+#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
+
+/* Generate the preamble required for initial synchronization and
+   a few older transceivers. */
+static void mdio_sync(void __iomem *mdio_addr)
+{
+	int bits = 32;
+
+	/* Establish sync by sending at least 32 logic ones. */
+	while (--bits >= 0) {
+		iowrite8(MDIO_WRITE1, mdio_addr);
+		mdio_delay();
+		iowrite8(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
+		mdio_delay();
+	}
+}
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	struct netdev_private *np = dev->priv;
+	void __iomem *mdio_addr = np->base + MIICtrl;
+	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	int i, retval = 0;
+
+	if (np->mii_preamble_required)
+		mdio_sync(mdio_addr);
+
+	/* Shift the read command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+		iowrite8(dataval, mdio_addr);
+		mdio_delay();
+		iowrite8(dataval | MDIO_ShiftClk, mdio_addr);
+		mdio_delay();
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		iowrite8(MDIO_EnbIn, mdio_addr);
+		mdio_delay();
+		retval = (retval << 1) | ((ioread8(mdio_addr) & MDIO_Data) ? 1 : 0);
+		iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+		mdio_delay();
+	}
+	return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	struct netdev_private *np = dev->priv;
+	void __iomem *mdio_addr = np->base + MIICtrl;
+	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+	int i;
+
+	if (np->mii_preamble_required)
+		mdio_sync(mdio_addr);
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+		iowrite8(dataval, mdio_addr);
+		mdio_delay();
+		iowrite8(dataval | MDIO_ShiftClk, mdio_addr);
+		mdio_delay();
+	}
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
+		iowrite8(MDIO_EnbIn, mdio_addr);
+		mdio_delay();
+		iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+		mdio_delay();
+	}
+	return;
+}
+
+static int netdev_open(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	void __iomem *ioaddr = np->base;
+	int i;
+
+	/* Do we need to reset the chip??? */
+
+	i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+	if (i)
+		return i;
+
+	if (netif_msg_ifup(np))
+		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
+			   dev->name, dev->irq);
+	init_ring(dev);
+
+	iowrite32(np->rx_ring_dma, ioaddr + RxListPtr);
+	/* The Tx list pointer is written as packets are queued. */
+
+	/* Initialize other registers. */
+	__set_mac_addr(dev);
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+	iowrite16(dev->mtu + 18, ioaddr + MaxFrameSize);
+#else
+	iowrite16(dev->mtu + 14, ioaddr + MaxFrameSize);
+#endif
+	if (dev->mtu > 2047)
+		iowrite32(ioread32(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);
+
+	/* Configure the PCI bus bursts and FIFO thresholds. */
+
+	if (dev->if_port == 0)
+		dev->if_port = np->default_port;
+
+	np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+
+	set_rx_mode(dev);
+	iowrite16(0, ioaddr + IntrEnable);
+	iowrite16(0, ioaddr + DownCounter);
+	/* Set the chip to poll every N*320nsec. */
+	iowrite8(100, ioaddr + RxDMAPollPeriod);
+	iowrite8(127, ioaddr + TxDMAPollPeriod);
+	/* Fix DFE-580TX packet drop issue */
+	if (np->pci_rev_id >= 0x14)
+		iowrite8(0x01, ioaddr + DebugCtrl1);
+	netif_start_queue(dev);
+	
+	// 04/19/2005 Jesse fix for complete initial step
+	spin_lock(&np->lock);
+	reset_tx(dev);
+	spin_unlock(&np->lock);
+	iowrite16(0x200, ioaddr + DMACtrl);
+	iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
+
+	if (netif_msg_ifup(np))
+		printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "
+			   "MAC Control %x, %4.4x %4.4x.\n",
+			   dev->name, ioread32(ioaddr + RxStatus), ioread8(ioaddr + TxStatus),
+			   ioread32(ioaddr + MACCtrl0),
+			   ioread16(ioaddr + MACCtrl1), ioread16(ioaddr + MACCtrl0));
+
+	/* Set the timer to check for link beat. */
+	init_timer(&np->timer);
+	np->timer.expires = jiffies + 3*HZ;
+	np->timer.data = (unsigned long)dev;
+	np->timer.function = &netdev_timer;				/* timer handler */
+	add_timer(&np->timer);
+
+	/* Enable interrupts by setting the interrupt mask. */
+	iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
+	
+	return 0;
+}
+
+static void check_duplex(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	void __iomem *ioaddr = np->base;
+	int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
+	int negotiated = mii_lpa & np->mii_if.advertising;
+	int duplex;
+
+	/* Force media */
+	if (!np->an_enable || mii_lpa == 0xffff) {
+		if (np->mii_if.full_duplex)
+			iowrite16 (ioread16 (ioaddr + MACCtrl0) | EnbFullDuplex,
+				ioaddr + MACCtrl0);
+		return;
+	}
+
+	/* Autonegotiation */
+	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
+	if (np->mii_if.full_duplex != duplex) {
+		np->mii_if.full_duplex = duplex;
+		if (netif_msg_link(np))
+			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
+				   "negotiated capability %4.4x.\n", dev->name,
+				   duplex ? "full" : "half", np->phys[0], negotiated);
+		iowrite16(ioread16(ioaddr + MACCtrl0) | duplex ? 0x20 : 0, ioaddr + MACCtrl0);
+	}
+}
+
+static void netdev_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netdev_private *np = dev->priv;
+	void __iomem *ioaddr = np->base;
+	int next_tick = 10*HZ;
+
+	if (netif_msg_timer(np)) {
+		printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, "
+			   "Tx %x Rx %x.\n",
+			   dev->name, ioread16(ioaddr + IntrEnable),
+			   ioread8(ioaddr + TxStatus), ioread32(ioaddr + RxStatus));
+	}
+	check_duplex(dev);
+	np->timer.expires = jiffies + next_tick;
+	add_timer(&np->timer);
+}
+
+static void tx_timeout(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	void __iomem *ioaddr = np->base;
+	unsigned long flag;
+
+	netif_stop_queue(dev);
+	tasklet_disable(&np->tx_tasklet);
+	iowrite16(0, ioaddr + IntrEnable);
+	printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
+		   "TxFrameId %2.2x,"
+		   " resetting...\n", dev->name, ioread8(ioaddr + TxStatus),
+		   ioread8(ioaddr + TxFrameId));
+
+	{
+		int i;
+		for (i=0; i<TX_RING_SIZE; i++) {
+			printk(KERN_DEBUG "%02x %08x %08x %08x(%02x) %08x %08x\n", i,
+				np->tx_ring_dma + i*sizeof(*np->tx_ring),
+				le32_to_cpu(np->tx_ring[i].next_desc),
+				le32_to_cpu(np->tx_ring[i].status),
+				(le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff,
+				le32_to_cpu(np->tx_ring[i].frag[0].addr),
+				le32_to_cpu(np->tx_ring[i].frag[0].length));
+		}
+		printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
+			ioread32(np->base + TxListPtr),
+			netif_queue_stopped(dev));
+		printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
+			np->cur_tx, np->cur_tx % TX_RING_SIZE,
+			np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
+		printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
+		printk(KERN_DEBUG "cur_task=%d\n", np->cur_task);
+	}
+	spin_lock_irqsave(&np->lock, flag);
+
+	/* Stop and restart the chip's Tx processes . */
+	reset_tx(dev);
+	spin_unlock_irqrestore(&np->lock, flag);
+
+	dev->if_port = 0;
+
+	dev->trans_start = jiffies;
+	np->stats.tx_errors++;
+	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
+		netif_wake_queue(dev);
+	}
+	iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
+	tasklet_enable(&np->tx_tasklet);
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void init_ring(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	np->cur_rx = np->cur_tx = 0;
+	np->dirty_rx = np->dirty_tx = 0;
+	np->cur_task = 0;
+
+	np->rx_buf_sz = (dev->mtu <= 1520 ? PKT_BUF_SZ : dev->mtu + 16);
+
+	/* Initialize all Rx descriptors. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma +
+			((i+1)%RX_RING_SIZE)*sizeof(*np->rx_ring));
+		np->rx_ring[i].status = 0;
+		np->rx_ring[i].frag[0].length = 0;
+		np->rx_skbuff[i] = 0;
+	}
+
+	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
+		np->rx_skbuff[i] = skb;
+		if (skb == NULL)
+			break;
+		skb->dev = dev;		/* Mark as being used by this device. */
+		skb_reserve(skb, 2);	/* 16 byte align the IP header. */
+		np->rx_ring[i].frag[0].addr = cpu_to_le32(
+			pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz,
+				PCI_DMA_FROMDEVICE));
+		np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag);
+	}
+	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		np->tx_skbuff[i] = 0;
+		np->tx_ring[i].status = 0;
+	}
+	return;
+}
+
+static void tx_poll (unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netdev_private *np = dev->priv;
+	unsigned head = np->cur_task % TX_RING_SIZE;
+	struct netdev_desc *txdesc =
+		&np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE];
+
+	/* Chain the next pointer */
+	for (; np->cur_tx - np->cur_task > 0; np->cur_task++) {
+		int entry = np->cur_task % TX_RING_SIZE;
+		txdesc = &np->tx_ring[entry];
+		if (np->last_tx) {
+			np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma +
+				entry*sizeof(struct netdev_desc));
+		}
+		np->last_tx = txdesc;
+	}
+	/* Indicate the latest descriptor of tx ring */
+	txdesc->status |= cpu_to_le32(DescIntrOnTx);
+
+	if (ioread32 (np->base + TxListPtr) == 0)
+		iowrite32 (np->tx_ring_dma + head * sizeof(struct netdev_desc),
+			np->base + TxListPtr);
+	return;
+}
+
+static int
+start_tx (struct sk_buff *skb, struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	struct netdev_desc *txdesc;
+	unsigned entry;
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = np->cur_tx % TX_RING_SIZE;
+	np->tx_skbuff[entry] = skb;
+	txdesc = &np->tx_ring[entry];
+
+	txdesc->next_desc = 0;
+	txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign);
+	txdesc->frag[0].addr = cpu_to_le32 (pci_map_single (np->pci_dev, skb->data,
+							skb->len,
+							PCI_DMA_TODEVICE));
+	txdesc->frag[0].length = cpu_to_le32 (skb->len | LastFrag);
+
+	/* Increment cur_tx before tasklet_schedule() */
+	np->cur_tx++;
+	mb();
+	/* Schedule a tx_poll() task */
+	tasklet_schedule(&np->tx_tasklet);
+
+	/* On some architectures: explicitly flush cache lines here. */
+	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1
+			&& !netif_queue_stopped(dev)) {
+		/* do nothing */
+	} else {
+		netif_stop_queue (dev);
+	}
+	dev->trans_start = jiffies;
+	if (netif_msg_tx_queued(np)) {
+		printk (KERN_DEBUG
+			"%s: Transmit frame #%d queued in slot %d.\n",
+			dev->name, np->cur_tx, entry);
+	}
+	return 0;
+}
+
+/* Reset hardware tx and free all of tx buffers */
+static int
+reset_tx (struct net_device *dev)
+{
+	struct netdev_private *np = (struct netdev_private*) dev->priv;
+	void __iomem *ioaddr = np->base;
+	struct sk_buff *skb;
+	int i;
+	int irq = in_interrupt();
+
+	/* Reset tx logic, TxListPtr will be cleaned */
+	iowrite16 (TxDisable, ioaddr + MACCtrl1);
+	iowrite16 (TxReset | DMAReset | FIFOReset | NetworkReset,
+			ioaddr + ASICCtrl + 2);
+	for (i=50; i > 0; i--) {
+		if ((ioread16(ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+			break;
+		mdelay(1);
+	}
+	/* free all tx skbuff */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		skb = np->tx_skbuff[i];
+		if (skb) {
+			pci_unmap_single(np->pci_dev,
+				np->tx_ring[i].frag[0].addr, skb->len,
+				PCI_DMA_TODEVICE);
+			if (irq)
+				dev_kfree_skb_irq (skb);
+			else
+				dev_kfree_skb (skb);
+			np->tx_skbuff[i] = 0;
+			np->stats.tx_dropped++;
+		}
+	}
+	np->cur_tx = np->dirty_tx = 0;
+	np->cur_task = 0;
+	iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
+	return 0;
+}
+
+/* The interrupt handler cleans up after the Tx thread,
+   and schedule a Rx thread work */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+#else
+static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+#endif
+{
+	struct net_device *dev = (struct net_device *)dev_instance;
+	struct netdev_private *np = netdev_priv(dev);
+	void __iomem *ioaddr = np->base;
+	int hw_frame_id;
+	int tx_cnt;
+	int tx_status;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+        irqreturn_t intr_handled=IRQ_HANDLED;//IRQ_NONE;
+#endif
+
+	do {
+		int intr_status = ioread16(ioaddr + IntrStatus);
+		iowrite16(intr_status, ioaddr + IntrStatus);
+
+		if (netif_msg_intr(np))
+			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
+				   dev->name, intr_status);
+
+		if (!(intr_status & DEFAULT_INTR))
+			break;
+
+		if (intr_status & (IntrRxDMADone)) {
+			iowrite16(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone),
+					ioaddr + IntrEnable);
+			if (np->budget < 0)
+				np->budget = RX_BUDGET;
+			tasklet_schedule(&np->rx_tasklet);
+		}
+		if (intr_status & (IntrTxDone | IntrDrvRqst)) {
+			tx_status = ioread16 (ioaddr + TxStatus);
+			for (tx_cnt=32; tx_status & 0x80; --tx_cnt) {
+				if (netif_msg_tx_done(np))
+					printk
+					    ("%s: Transmit status is %2.2x.\n",
+				     	dev->name, tx_status);
+				if (tx_status & 0x1e) {
+					np->stats.tx_errors++;
+					if (tx_status & 0x10)
+						np->stats.tx_fifo_errors++;
+					if (tx_status & 0x08)
+						np->stats.collisions++;
+					if (tx_status & 0x02)
+						np->stats.tx_window_errors++;
+					/* This reset has not been verified!. */
+					if (tx_status & 0x10) {	/* Reset the Tx. */
+						np->stats.tx_fifo_errors++;
+						spin_lock(&np->lock);
+						reset_tx(dev);
+						spin_unlock(&np->lock);
+					}
+					if (tx_status & 0x1e) {
+					/* It could fail to restart the tx when MaxCollions, need to try more times */
+						int i = 10;
+						do {
+							iowrite16 (ioread16(ioaddr + MACCtrl1) | TxEnable, ioaddr + MACCtrl1);
+							if (ioread16(ioaddr + MACCtrl1) & TxEnabled)
+								break;
+							mdelay(1);
+						} while (--i);
+					}
+				}
+				/* Yup, this is a documentation bug.  It cost me *hours*. */
+				iowrite16 (0, ioaddr + TxStatus);
+				tx_status = ioread16 (ioaddr + TxStatus);
+				if (tx_cnt < 0)
+					break;
+			}
+			hw_frame_id = (tx_status >> 8) & 0xff;
+		} else 	{
+			hw_frame_id = ioread8(ioaddr + TxFrameId);
+		}
+
+		if (np->pci_rev_id >= 0x14) {
+			spin_lock(&np->lock);
+			for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+				int entry = np->dirty_tx % TX_RING_SIZE;
+				struct sk_buff *skb;
+				int sw_frame_id;
+				sw_frame_id = (le32_to_cpu(
+					np->tx_ring[entry].status) >> 2) & 0xff;
+				if (sw_frame_id == hw_frame_id &&
+					!(le32_to_cpu(np->tx_ring[entry].status)
+					& 0x00010000))
+						break;
+				if (sw_frame_id == (hw_frame_id + 1) %
+					TX_RING_SIZE)
+						break;
+				skb = np->tx_skbuff[entry];
+				/* Free the original skb. */
+				pci_unmap_single(np->pci_dev,
+					np->tx_ring[entry].frag[0].addr,
+					skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_irq (np->tx_skbuff[entry]);
+				np->tx_skbuff[entry] = 0;
+				np->tx_ring[entry].frag[0].addr = 0;
+				np->tx_ring[entry].frag[0].length = 0;
+			}
+			spin_unlock(&np->lock);
+		} else {
+			spin_lock(&np->lock);
+			for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+				int entry = np->dirty_tx % TX_RING_SIZE;
+				struct sk_buff *skb;
+				if (!(le32_to_cpu(np->tx_ring[entry].status)
+							& 0x00010000))
+					break;
+				skb = np->tx_skbuff[entry];
+				/* Free the original skb. */
+				pci_unmap_single(np->pci_dev,
+					np->tx_ring[entry].frag[0].addr,
+					skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_irq (np->tx_skbuff[entry]);
+				np->tx_skbuff[entry] = 0;
+				np->tx_ring[entry].frag[0].addr = 0;
+				np->tx_ring[entry].frag[0].length = 0;
+			}
+			spin_unlock(&np->lock);
+		}
+
+		if (netif_queue_stopped(dev) &&
+			np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
+			/* The ring is no longer full, clear busy flag. */
+			netif_wake_queue (dev);
+		}
+		/* Abnormal error summary/uncommon events handlers. */
+		if (intr_status & (IntrPCIErr | LinkChange | StatsMax))
+			netdev_error(dev, intr_status);
+	} while (0);
+	if (netif_msg_intr(np))
+		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
+			   dev->name, ioread16(ioaddr + IntrStatus));
+	iowrite32(5000, ioaddr + DownCounter);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+    return intr_handled;
+#endif
+
+}
+
+static void rx_poll(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netdev_private *np = dev->priv;
+	int entry = np->cur_rx % RX_RING_SIZE;
+	int boguscnt = np->budget;
+	void __iomem *ioaddr = np->base;
+	int received = 0;
+
+	/* If EOP is set on the next entry, it's a new packet. Send it up. */
+	while (1) {
+		struct netdev_desc *desc = &(np->rx_ring[entry]);
+		u32 frame_status = le32_to_cpu(desc->status);
+		int pkt_len;
+
+		if (--boguscnt < 0) {
+			goto not_done;
+		}
+		if (!(frame_status & DescOwn))
+			break;
+		pkt_len = frame_status & 0x1fff;	/* Chip omits the CRC. */
+		if (netif_msg_rx_status(np))
+			printk(KERN_DEBUG "  netdev_rx() status was %8.8x.\n",
+				   frame_status);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) 
+		pci_dma_sync_single(np->pci_dev, desc->frag[0].addr,np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+#else
+		pci_dma_sync_single_for_cpu(np->pci_dev, desc->frag[0].addr,np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+#endif
+
+		if (frame_status & 0x001f4000) {
+			/* There was a error. */
+			if (netif_msg_rx_err(np))
+				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
+					   frame_status);
+			np->stats.rx_errors++;
+			if (frame_status & 0x00100000) np->stats.rx_length_errors++;
+			if (frame_status & 0x00010000) np->stats.rx_fifo_errors++;
+			if (frame_status & 0x00060000) np->stats.rx_frame_errors++;
+			if (frame_status & 0x00080000) np->stats.rx_crc_errors++;
+			if (frame_status & 0x00100000) {
+				printk(KERN_WARNING "%s: Oversized Ethernet frame,"
+					   " status %8.8x.\n",
+					   dev->name, frame_status);
+			}
+		} else {
+			struct sk_buff *skb;
+#ifndef final_version
+			if (netif_msg_rx_status(np))
+				printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
+					   ", bogus_cnt %d.\n",
+					   pkt_len, boguscnt);
+#endif
+			/* Check if the packet is long enough to accept without copying
+			   to a minimally-sized skbuff. */
+			if (pkt_len < rx_copybreak
+				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
+				skb_put(skb, pkt_len);
+			} else {
+				pci_unmap_single(np->pci_dev,
+					desc->frag[0].addr,
+					np->rx_buf_sz,
+					PCI_DMA_FROMDEVICE);
+				skb_put(skb = np->rx_skbuff[entry], pkt_len);
+				np->rx_skbuff[entry] = NULL;
+			}
+			skb->protocol = eth_type_trans(skb, dev);
+			/* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+		}
+		entry = (entry + 1) % RX_RING_SIZE;
+		received++;
+	}
+	np->cur_rx = entry;
+	refill_rx (dev);
+	np->budget -= received;
+	iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
+	return;
+
+not_done:
+	np->cur_rx = entry;
+	refill_rx (dev);
+	if (!received)
+		received = 1;
+	np->budget -= received;
+	if (np->budget <= 0)
+		np->budget = RX_BUDGET;
+	tasklet_schedule(&np->rx_tasklet);
+	return;
+}
+
+static void refill_rx (struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int entry;
+	int cnt = 0;
+
+	/* Refill the Rx ring buffers. */
+	for (;(np->cur_rx - np->dirty_rx + RX_RING_SIZE) % RX_RING_SIZE > 0;
+		np->dirty_rx = (np->dirty_rx + 1) % RX_RING_SIZE) {
+		struct sk_buff *skb;
+		entry = np->dirty_rx % RX_RING_SIZE;
+		if (np->rx_skbuff[entry] == NULL) {
+			skb = dev_alloc_skb(np->rx_buf_sz);
+			np->rx_skbuff[entry] = skb;
+			if (skb == NULL)
+				break;		/* Better luck next round. */
+			skb->dev = dev;		/* Mark as being used by this device. */
+			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+			np->rx_ring[entry].frag[0].addr = cpu_to_le32(
+				pci_map_single(np->pci_dev, skb->tail,
+					np->rx_buf_sz, PCI_DMA_FROMDEVICE));
+		}
+		/* Perhaps we need not reset this field. */
+		np->rx_ring[entry].frag[0].length =
+			cpu_to_le32(np->rx_buf_sz | LastFrag);
+		np->rx_ring[entry].status = 0;
+		cnt++;
+	}
+	return;
+}
+static void netdev_error(struct net_device *dev, int intr_status)
+{
+	struct netdev_private *np = dev->priv;
+	void __iomem *ioaddr = np->base;
+	u16 mii_ctl, mii_advertise, mii_lpa;
+	int speed;
+
+	if (intr_status & LinkChange) {
+		if (np->an_enable) {
+			mii_advertise = mdio_read (dev, np->phys[0], MII_ADVERTISE);
+			mii_lpa= mdio_read (dev, np->phys[0], MII_LPA);
+			mii_advertise &= mii_lpa;
+			printk (KERN_INFO "%s: Link changed: ", dev->name);
+			if (mii_advertise & ADVERTISE_100FULL) {
+				np->speed = 100;
+				printk ("100Mbps, full duplex\n");
+			} else if (mii_advertise & ADVERTISE_100HALF) {
+				np->speed = 100;
+				printk ("100Mbps, half duplex\n");
+			} else if (mii_advertise & ADVERTISE_10FULL) {
+				np->speed = 10;
+				printk ("10Mbps, full duplex\n");
+			} else if (mii_advertise & ADVERTISE_10HALF) {
+				np->speed = 10;
+				printk ("10Mbps, half duplex\n");
+			} else
+				printk ("\n");
+
+		} else {
+			mii_ctl = mdio_read (dev, np->phys[0], MII_BMCR);
+			speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
+			np->speed = speed;
+			printk (KERN_INFO "%s: Link changed: %dMbps ,",
+				dev->name, speed);
+			printk ("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ?
+				"full" : "half");
+		}
+		check_duplex (dev);
+		if (np->flowctrl && np->mii_if.full_duplex) {
+			iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200,
+				ioaddr + MulticastFilter1+2);
+			iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl,
+				ioaddr + MACCtrl0);
+		}
+	}
+	if (intr_status & StatsMax) {
+		get_stats(dev);
+	}
+	if (intr_status & IntrPCIErr) {
+		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
+			   dev->name, intr_status);
+		/* We must do a global reset of DMA to continue. */
+	}
+}
+
+static struct net_device_stats *get_stats(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	void __iomem *ioaddr = np->base;
+	int i;
+
+	/* We should lock this segment of code for SMP eventually, although
+	   the vulnerability window is very small and statistics are
+	   non-critical. */
+	/* The chip only need report frame silently dropped. */
+	np->stats.rx_missed_errors	+= ioread8(ioaddr + RxMissed);
+	np->stats.tx_packets += ioread16(ioaddr + TxFramesOK);
+	np->stats.rx_packets += ioread16(ioaddr + RxFramesOK);
+	np->stats.collisions += ioread8(ioaddr + StatsLateColl);
+	np->stats.collisions += ioread8(ioaddr + StatsMultiColl);
+	np->stats.collisions += ioread8(ioaddr + StatsOneColl);
+	np->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError);
+	ioread8(ioaddr + StatsTxDefer);
+	for (i = StatsTxDefer; i <= StatsMcastRx; i++)
+		ioread8(ioaddr + i);
+	np->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow);
+	np->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16;
+	np->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow);
+	np->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16;
+
+	return &np->stats;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	void __iomem *ioaddr = np->base;
+	u16 mc_filter[4];			/* Multicast hash filter */
+	u32 rx_mode;
+	int i;
+
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		/* Unconditionally log net taps. */
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+		memset(mc_filter, 0xff, sizeof(mc_filter));
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys;
+	} else if ((dev->mc_count > multicast_filter_limit)
+			   ||  (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to match, or accept all multicasts. */
+		memset(mc_filter, 0xff, sizeof(mc_filter));
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+	} else if (dev->mc_count) {
+		struct dev_mc_list *mclist;
+		int bit;
+		int index;
+		int crc;
+		memset (mc_filter, 0, sizeof (mc_filter));
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+		     i++, mclist = mclist->next) {
+			crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
+			for (index=0, bit=0; bit < 6; bit++, crc <<= 1)
+				if (crc & 0x80000000) index |= 1 << bit;
+			mc_filter[index/16] |= (1 << (index % 16));
+		}
+		rx_mode = AcceptBroadcast | AcceptMultiHash | AcceptMyPhys;
+	} else {
+		iowrite8(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode);
+		return;
+	}
+	if (np->mii_if.full_duplex && np->flowctrl)
+		mc_filter[3] |= 0x0200;
+
+	for (i = 0; i < 4; i++)
+		iowrite16(mc_filter[i], ioaddr + MulticastFilter0 + i*2);
+	iowrite8(rx_mode, ioaddr + RxMode);
+}
+
+static int __set_mac_addr(struct net_device *dev)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	u16 addr16;
+
+	addr16 = (dev->dev_addr[0] | (dev->dev_addr[1] << 8));
+	iowrite16(addr16, np->base + StationAddr);
+	addr16 = (dev->dev_addr[2] | (dev->dev_addr[3] << 8));
+	iowrite16(addr16, np->base + StationAddr+2);
+	addr16 = (dev->dev_addr[4] | (dev->dev_addr[5] << 8));
+	iowrite16(addr16, np->base + StationAddr+4);
+	return 0;
+}
+
+
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct netdev_private *np = dev->priv;
+	u32 ethcmd;
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+        switch (ethcmd) {
+		/* get constant driver settings/info */
+        	case ETHTOOL_GDRVINFO: {
+			struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+			strcpy(info.driver, DRV_NAME);
+			strcpy(info.version, DRV_VERSION);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) 
+		   strcpy(info.bus_info, np->pci_dev->slot_name);
+#else
+		   strcpy(info.bus_info, pci_name(np->pci_dev));
+#endif						
+			memset(&info.fw_version, 0, sizeof(info.fw_version));
+			if (copy_to_user(useraddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+
+		/* get media settings */
+		case ETHTOOL_GSET: {
+			struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+			spin_lock_irq(&np->lock);
+			mii_ethtool_gset(&np->mii_if, &ecmd);
+			spin_unlock_irq(&np->lock);
+			if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+				return -EFAULT;
+			return 0;
+		}
+		/* set media settings */
+		case ETHTOOL_SSET: {
+			int r;
+			struct ethtool_cmd ecmd;
+			if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+				return -EFAULT;
+			spin_lock_irq(&np->lock);
+			r = mii_ethtool_sset(&np->mii_if, &ecmd);
+			spin_unlock_irq(&np->lock);
+			return r;
+		}
+
+		/* restart autonegotiation */
+		case ETHTOOL_NWAY_RST: {
+			return mii_nway_restart(&np->mii_if);
+		}
+
+		/* get link status */
+		case ETHTOOL_GLINK: {
+			struct ethtool_value edata = {ETHTOOL_GLINK};
+			edata.data = mii_link_ok(&np->mii_if);
+			if (copy_to_user(useraddr, &edata, sizeof(edata)))
+				return -EFAULT;
+			return 0;
+		}
+
+		/* get message-level */
+		case ETHTOOL_GMSGLVL: {
+			struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+			edata.data = np->msg_enable;
+			if (copy_to_user(useraddr, &edata, sizeof(edata)))
+				return -EFAULT;
+			return 0;
+		}
+		/* set message-level */
+		case ETHTOOL_SMSGLVL: {
+			struct ethtool_value edata;
+			if (copy_from_user(&edata, useraddr, sizeof(edata)))
+				return -EFAULT;
+			np->msg_enable = edata.data;
+			return 0;
+		}
+
+		default:
+		return -EOPNOTSUPP;
+
+        }
+}
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct netdev_private *np = dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
+	int i;
+	void __iomem *ioaddr = np->base;
+
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
+	}
+	switch (cmd) {
+		case SIOCDEVPRIVATE:
+		for (i=0; i<TX_RING_SIZE; i++) {
+			printk(KERN_DEBUG "%02x %08x %08x %08x(%02x) %08x %08x\n", i,
+				np->tx_ring_dma + i*sizeof(*np->tx_ring),
+				le32_to_cpu(np->tx_ring[i].next_desc),
+				le32_to_cpu(np->tx_ring[i].status),
+				(le32_to_cpu(np->tx_ring[i].status) >> 2)
+					& 0xff,
+				le32_to_cpu(np->tx_ring[i].frag[0].addr),
+				le32_to_cpu(np->tx_ring[i].frag[0].length));
+		}
+		printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
+			ioread32(np->base + TxListPtr),
+			netif_queue_stopped(dev));
+		printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
+			np->cur_tx, np->cur_tx % TX_RING_SIZE,
+			np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
+		printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
+		printk(KERN_DEBUG "cur_task=%d\n", np->cur_task);
+		printk(KERN_DEBUG "TxStatus=%04x\n", ioread16(ioaddr + TxStatus));
+			return 0;
+	}
+
+
+	return rc;
+}
+
+static int netdev_close(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	void __iomem *ioaddr = np->base;
+	struct sk_buff *skb;
+	int i;
+
+	netif_stop_queue(dev);
+
+	if (netif_msg_ifdown(np)) {
+		printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x "
+			   "Rx %4.4x Int %2.2x.\n",
+			   dev->name, ioread8(ioaddr + TxStatus),
+			   ioread32(ioaddr + RxStatus), ioread16(ioaddr + IntrStatus));
+		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
+			   dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
+	}
+
+	/* Stop the chip's Rx processes. */
+	iowrite16(RxDisable | StatsDisable, ioaddr + MACCtrl1);
+	iowrite16(0x100, ioaddr + DMACtrl);
+	
+	/* Stop the chip's Tx processes. */
+	iowrite16(0x400, ioaddr + DMACtrl);
+	iowrite16(TxDisable, ioaddr + MACCtrl1);
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	iowrite16(0x0000, ioaddr + IntrEnable);
+
+	/* Wait and kill tasklet */
+	tasklet_kill(&np->rx_tasklet);
+	tasklet_kill(&np->tx_tasklet);
+
+#ifdef __i386__
+	if (netif_msg_hw(np)) {
+		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
+			   (int)(np->tx_ring_dma));
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk(" #%d desc. %4.4x %8.8x %8.8x.\n",
+				   i, np->tx_ring[i].status, np->tx_ring[i].frag[0].addr,
+				   np->tx_ring[i].frag[0].length);
+		printk("\n"KERN_DEBUG "  Rx ring %8.8x:\n",
+			   (int)(np->rx_ring_dma));
+		for (i = 0; i < /*RX_RING_SIZE*/4 ; i++) {
+			printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
+				   i, np->rx_ring[i].status, np->rx_ring[i].frag[0].addr,
+				   np->rx_ring[i].frag[0].length);
+		}
+	}
+#endif /* __i386__ debugging only */
+
+	free_irq(dev->irq, dev);
+
+	del_timer_sync(&np->timer);
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].status = 0;
+		np->rx_ring[i].frag[0].addr = 0xBADF00D0; /* An invalid address. */
+		skb = np->rx_skbuff[i];
+		if (skb) {
+			pci_unmap_single(np->pci_dev,
+				np->rx_ring[i].frag[0].addr, np->rx_buf_sz,
+				PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(skb);
+			np->rx_skbuff[i] = 0;
+		}
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		skb = np->tx_skbuff[i];
+		if (skb) {
+			pci_unmap_single(np->pci_dev,
+				np->tx_ring[i].frag[0].addr, skb->len,
+				PCI_DMA_TODEVICE);
+			dev_kfree_skb(skb);
+			np->tx_skbuff[i] = 0;
+		}
+	}
+
+	return 0;
+}
+
+static void __devexit sundance_remove1 (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	if (dev) {
+		struct netdev_private *np = dev->priv;
+
+		unregister_netdev(dev);
+        	pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring,
+			np->rx_ring_dma);
+	        pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring,
+			np->tx_ring_dma);
+		pci_release_regions(pdev);
+#ifndef USE_IO_OPS
+		iounmap((char *)(dev->base_addr));
+#endif
+		kfree(dev);
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
+static struct pci_driver sundance_driver = {
+	.name		= DRV_NAME,
+	.id_table	= sundance_pci_tbl,
+	.probe		= sundance_probe1,
+	.remove		= __devexit_p(sundance_remove1),
+};
+
+static int __init sundance_init(void)
+{
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
+	return pci_module_init(&sundance_driver);
+}
+
+static void __exit sundance_exit(void)
+{
+	pci_unregister_driver(&sundance_driver);
+}
+
+module_init(sundance_init);
+module_exit(sundance_exit);
+
+
--- linux-2.6.12/drivers/net/Makefile.orig	2005-08-25 13:57:51.959876296 -0400
+++ linux-2.6.12/drivers/net/Makefile	2005-08-25 13:57:56.622255045 -0400
@@ -66,6 +66,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfi
 obj-$(CONFIG_MII) += mii.o
 
 obj-$(CONFIG_SUNDANCE) += sundance.o
+obj-$(CONFIG_SUNDANCE) += sundance-icplus.o
 obj-$(CONFIG_HAMACHI) += hamachi.o
 obj-$(CONFIG_NET) += Space.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o




More information about the fedora-cvs-commits mailing list