patch-2.1.110 linux/drivers/net/tlan.c

Next file: linux/drivers/net/tlan.h
Previous file: linux/drivers/net/sk_g16.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.109/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
@@ -3,20 +3,23 @@
  *  Linux ThunderLAN Driver
  *
  *  tlan.c
- *  by James Banks, james.banks@caldera.com
+ *  by James Banks
  *
- *  (C) 1997 Caldera, Inc.
+ *  (C) 1997-1998 Caldera, Inc.
+ *  (C) 1998 James Banks
  *
  *  This software may be used and distributed according to the terms
  *  of the GNU Public License, incorporated herein by reference.
  *
- ** This file is best viewed/edited with tabstop=4 and colums>=132.
+ ** This file is best viewed/edited with columns>=132.
  *
  ** Useful (if not required) reading:
  *
  *		Texas Instruments, ThunderLAN Programmer's Guide,
  *			TI Literature Number SPWU013A
  *			available in PDF format from www.ti.com
+ *		Level One, LXT901 and LXT970 Data Sheets
+ *			available in PDF format from www.level1.com
  *		National Semiconductor, DP83840A Data Sheet
  *			available in PDF format from www.national.com
  *		Microchip Technology, 24C01A/02A/04A Data Sheet
@@ -29,6 +32,7 @@
 
 #include "tlan.h"
 
+#include <linux/bios32.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/etherdevice.h>
@@ -49,53 +53,105 @@
 
 static  int		debug = 0;
 static	int		aui = 0;
+static	int		sa_int = 0;
+static	int		bbuf = 0;
+static	int		duplex = 0;
+static	int		speed = 0;
 static	u8		*TLanPadBuffer;
 static	char		TLanSignature[] = "TLAN";
-static	int		TLanVersionMajor = 0;
-static	int		TLanVersionMinor = 38;
+static	int		TLanVersionMajor = 1;
+static	int		TLanVersionMinor = 0;
 
 
-static	TLanPciId TLanDeviceList[] = {
+static	TLanAdapterEntry TLanAdapterList[] = {
 	{ PCI_VENDOR_ID_COMPAQ, 
 	  PCI_DEVICE_ID_NETELLIGENT_10,
-	  "Compaq Netelligent 10"
+	  "Compaq Netelligent 10 T PCI UTP",
+	  TLAN_ADAPTER_ACTIVITY_LED,
+	  0x83
 	},
 	{ PCI_VENDOR_ID_COMPAQ,
 	  PCI_DEVICE_ID_NETELLIGENT_10_100,
-	  "Compaq Netelligent 10/100"
+	  "Compaq Netelligent 10/100 TX PCI UTP",
+	  TLAN_ADAPTER_ACTIVITY_LED,
+	  0x83
 	}, 
 	{ PCI_VENDOR_ID_COMPAQ,
 	  PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED,
-	  "Compaq Integrated NetFlex-3/P"
+	  "Compaq Integrated NetFlex-3/P",
+	  TLAN_ADAPTER_NONE,
+	  0x83
 	}, 
 	{ PCI_VENDOR_ID_COMPAQ,
 	  PCI_DEVICE_ID_NETFLEX_3P,
-	  "Compaq NetFlex-3/P"
+	  "Compaq NetFlex-3/P",
+	  TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY,
+	  0x83
 	},
 	{ PCI_VENDOR_ID_COMPAQ,
 	  PCI_DEVICE_ID_NETFLEX_3P_BNC,
-	  "Compaq NetFlex-3/P"
+	  "Compaq NetFlex-3/P",
+	  TLAN_ADAPTER_NONE,
+	  0x83
 	},
 	{ PCI_VENDOR_ID_COMPAQ,
 	  PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT,
-	  "Compaq ProLiant Netelligent 10/100"
+	  "Compaq Netelligent Integrated 10/100 TX UTP",
+	  TLAN_ADAPTER_NONE,
+	  0x83
 	},
 	{ PCI_VENDOR_ID_COMPAQ,
 	  PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL,
-	  "Compaq Dual Port Netelligent 10/100"
+	  "Compaq Netelligent Dual 10/100 TX PCI UTP",
+	  TLAN_ADAPTER_NONE,
+	  0x83
 	},
 	{ PCI_VENDOR_ID_COMPAQ,
 	  PCI_DEVICE_ID_DESKPRO_4000_5233MMX,
-	  "Compaq Deskpro 4000 5233MMX"
+	  "Compaq Netelligent 10/100 TX Embedded UTP",
+	  TLAN_ADAPTER_NONE,
+	  0x83
+	},
+	{ PCI_VENDOR_ID_OLICOM,
+	  PCI_DEVICE_ID_OLICOM_OC2183,
+	  "Olicom OC-2183/2185",
+	  TLAN_ADAPTER_USE_INTERN_10,
+	  0xF8
+	},
+	{ PCI_VENDOR_ID_OLICOM,
+	  PCI_DEVICE_ID_OLICOM_OC2325,
+	  "Olicom OC-2325",
+	  TLAN_ADAPTER_UNMANAGED_PHY,
+	  0xF8
+	},
+	{ PCI_VENDOR_ID_OLICOM,
+	  PCI_DEVICE_ID_OLICOM_OC2326,
+	  "Olicom OC-2326",
+	  TLAN_ADAPTER_USE_INTERN_10,
+	  0xF8
+	},
+	{ PCI_VENDOR_ID_COMPAQ,
+	  PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100,
+	  "Compaq Netelligent 10/100 TX UTP",
+	  TLAN_ADAPTER_ACTIVITY_LED,
+	  0x83
+	},
+	{ PCI_VENDOR_ID_COMPAQ,
+	  PCI_DEVICE_ID_NETELLIGENT_10_T2,
+	  "Compaq Netelligent 10 T/2 PCI UTP/Coax",
+	  TLAN_ADAPTER_NONE,
+	  0x83
 	},
 	{ 0,
 	  0,
-	  NULL
+	  NULL,
+	  0,
+	  0
 	} /* End of List */
 };
 
 
-static int	TLan_PciProbe( u8 *, u8 *, int *, u8 *, u32 *, u32 * );
+static int	TLan_PciProbe( u8 *, u8 *, u8 *, u8 *, u32 *, u32 * );
 static int	TLan_Init( struct device * );
 static int	TLan_Open(struct device *dev);
 static int	TLan_StartTx(struct sk_buff *, struct device *);
@@ -116,28 +172,37 @@
 static void	TLan_Timer( unsigned long );
 
 static void	TLan_ResetLists( struct device * );
+static void	TLan_FreeLists( struct device * );
 static void	TLan_PrintDio( u16 );
 static void	TLan_PrintList( TLanList *, char *, int );
 static void	TLan_ReadAndClearStats( struct device *, int );
-static int	TLan_Reset( struct device * );
+static void	TLan_ResetAdapter( struct device * );
+static void	TLan_FinishReset( struct device * );
 static void	TLan_SetMac( struct device *, int areg, char *mac );
 
-static int	TLan_PhyNop( struct device * );
 static void	TLan_PhyPrint( struct device * );
-static void	TLan_PhySelect( struct device * );
+static void	TLan_PhyDetect( struct device * );
+static void	TLan_PhyPowerDown( struct device * );
+static void	TLan_PhyPowerUp( struct device * );
+static void	TLan_PhyReset( struct device * );
+static void	TLan_PhyStartLink( struct device * );
+static void	TLan_PhyFinishAutoNeg( struct device * );
+/*
+static int	TLan_PhyNop( struct device * );
 static int	TLan_PhyInternalCheck( struct device * );
 static int	TLan_PhyInternalService( struct device * );
 static int	TLan_PhyDp83840aCheck( struct device * );
+*/
 
-static int	TLan_MiiReadReg(u16, u16, u16, u16 *);
+static int	TLan_MiiReadReg( struct device *, u16, u16, u16 * );
 static void	TLan_MiiSendData( u16, u32, unsigned );
-static void	TLan_MiiSync(u16);
-static void	TLan_MiiWriteReg(u16, u16, u16, u16);
+static void	TLan_MiiSync( u16 );
+static void	TLan_MiiWriteReg( struct device *, u16, u16, u16 );
 
 static void	TLan_EeSendStart( u16 );
 static int	TLan_EeSendByte( u16, u8, int );
 static void	TLan_EeReceiveByte( u16, u8 *, int );
-static int	TLan_EeReadByte( u16, u8, u8 * );
+static int	TLan_EeReadByte( struct device *, u8, u8 * );
 
 
 static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = {
@@ -151,6 +216,25 @@
 	TLan_HandleRxEOC
 };
 
+static inline void
+TLan_SetTimer( struct device *dev, u32 ticks, u32 type )
+{
+	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+
+	cli();
+	if ( priv->timer.function != NULL ) {
+		return;
+	}
+	priv->timer.function = &TLan_Timer;
+	sti();
+
+	priv->timer.data = (unsigned long) dev;
+	priv->timer.expires = jiffies + ticks;
+	priv->timerSetAt = jiffies;
+	priv->timerType = type;
+	add_timer( &priv->timer );
+
+} /* TLan_SetTimer */
 
 
 /*****************************************************************************
@@ -176,7 +260,7 @@
 	 *
 	 *	This function begins the setup of the driver creating a
 	 *	pad buffer, finding all TLAN devices (matching
-	 *	TLanDeviceList entries), and creating and initializing a
+	 *	TLanAdapterList entries), and creating and initializing a
 	 *	device structure for each adapter.
 	 *
 	 **************************************************************/
@@ -188,14 +272,14 @@
 	struct device	*dev;
 	size_t		dev_size;
 	u8		dfn;
-	u32		dl_ix;
+	u32		index;
 	int		failed;
 	int		found;
 	u32		io_base;
-	int		irq;
+	u8		irq;
 	u8		rev;
 
-	printk( "TLAN driver, v%d.%d, (C) 1997 Caldera, Inc.\n",
+	printk( "TLAN driver, v%d.%d, (C) 1997-8 Caldera, Inc.\n",
 		TLanVersionMajor,
 		TLanVersionMinor
 	      );
@@ -211,8 +295,7 @@
 
 	dev_size = sizeof(struct device) + sizeof(TLanPrivateInfo);
 
-	while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ) ) )
- {
+	while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &index ) ) ) {
 		dev = (struct device *) kmalloc( dev_size, GFP_KERNEL );
 		if ( dev == NULL ) {
 			printk( "TLAN:  Could not allocate memory for device.\n" );
@@ -227,23 +310,37 @@
 		dev->irq = irq;
 		dev->init = TLan_Init;
 
-		priv->pciBus = bus;
-		priv->pciDeviceFn = dfn;
-		priv->pciRevision = rev;
-		priv->pciEntry = dl_ix;
+		priv->adapter =    &TLanAdapterList[index];
+		priv->adapterRev = rev;
+		priv->aui =        aui;
+		if ( ( duplex != 1 ) && ( duplex != 2 ) ) {
+			duplex = 0;
+		}
+		priv->duplex =     duplex;
+		if ( ( speed != 10 ) && ( speed != 100 ) ) {
+			speed = 0;
+		}
+		priv->speed =      speed;
+		priv->sa_int =     sa_int;
+		priv->debug =      debug;
 
 		ether_setup( dev );
 
 		failed = register_netdev( dev );
 
 		if ( failed ) {
-			printk( "TLAN:  Could not register network device.  Freeing struct.\n" );
+			printk( "TLAN:  Could not register device.\n" );
 			kfree( dev );
 		} else {
 			priv->nextDevice = TLanDevices;
 			TLanDevices = dev;
 			TLanDevicesInstalled++;
-			printk("TLAN:  %s irq=%2d io=%04x, %s\n", dev->name, (int) irq, io_base, TLanDeviceList[dl_ix].deviceName );
+			printk("TLAN:  %s irq=%2d io=%04x, %s, Rev. %d\n",
+				dev->name,
+				(int) dev->irq,
+				(int) dev->base_addr,
+				priv->adapter->deviceLabel,
+				priv->adapterRev );
 		}
 	}
 	
@@ -276,11 +373,12 @@
 	struct device	*dev;
 	TLanPrivateInfo	*priv;
 
-	while (TLanDevicesInstalled) {
+	while ( TLanDevicesInstalled ) {
 		dev = TLanDevices;
 		priv = (TLanPrivateInfo *) dev->priv;
-		if ( priv->dmaStorage )
+		if ( priv->dmaStorage ) {
 			kfree( priv->dmaStorage );
+		}
 		release_region( dev->base_addr, 0x10 );
 		unregister_netdev( dev );
 		TLanDevices = priv->nextDevice;
@@ -315,54 +413,79 @@
 	 
 extern int tlan_probe( struct device *dev )
 {
+	TLanPrivateInfo	*priv;
 	static int	pad_allocated = 0;
 	int		found;
-	TLanPrivateInfo	*priv;
-	u8		bus, dfn, rev;
-	int		irq;
-	u32		io_base, dl_ix;
-
-	found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix );
-	if ( found ) {
-		dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL );
-		if ( dev->priv == NULL ) {
-			printk( "TLAN:  Could not allocate memory for device.\n" );
+	u8		bus, dfn, irq, rev;
+	u32		io_base, index;
+
+	found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &index );
+
+	if ( ! found ) {
+		return -ENODEV;
+	}
+
+	dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL );
+	
+	if ( dev->priv == NULL ) {
+		printk( "TLAN:  Could not allocate memory for device.\n" );
+		return  -ENOMEM;
+	}
+
+	memset( dev->priv, 0, sizeof(TLanPrivateInfo) );
+
+	if ( ! pad_allocated ) {
+		TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, 
+//						( GFP_KERNEL | GFP_DMA )
+						( GFP_KERNEL )
+					      );
+		if ( TLanPadBuffer == NULL ) {
+			printk( "TLAN:  Could not allocate memory for padding.\n" );
+			kfree( dev->priv );
+			return -ENOMEM;
+		} else {
+			pad_allocated = 1;
+			memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE );
 		}
-		memset( dev->priv, 0, sizeof(TLanPrivateInfo) );
-		priv = (TLanPrivateInfo *) dev->priv;
+	}
 
-		dev->name = priv->devName;
-		strcpy( priv->devName, "    " );
+	priv = (TLanPrivateInfo *) dev->priv;
 
-		dev = init_etherdev( dev, sizeof(TLanPrivateInfo) );
+	dev->name = priv->devName;
+	strcpy( priv->devName, "    " );
 
-		dev->base_addr = io_base;
-		dev->irq = irq;
+	dev = init_etherdev( dev, sizeof(TLanPrivateInfo) );
 
-		priv->pciBus = bus;
-		priv->pciDeviceFn = dfn;
-		priv->pciRevision = rev;
-		priv->pciEntry = dl_ix;
-
-		if ( ! pad_allocated ) {
-			TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, GFP_KERNEL | GFP_DMA );
-			if ( TLanPadBuffer == NULL ) {
-				printk( "TLAN:  Could not allocate memory for pad buffer.\n" );
-			} else {
-				pad_allocated = 1;
-				memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE );
-			}
-		}
-		printk("TLAN %d.%d:  %s irq=%2d io=%04x, %s\n",TLanVersionMajor,
-			TLanVersionMinor,
-			dev->name, 
-			(int) irq, 
-			io_base, 
-			TLanDeviceList[dl_ix].deviceName );
-		TLan_Init( dev );
+	dev->base_addr = io_base;
+	dev->irq = irq;
+
+
+	priv->adapter =    &TLanAdapterList[index];
+	priv->adapterRev = rev;
+	priv->aui =        dev->mem_start & 0x01;
+	priv->duplex =     ( ( dev->mem_start & 0x0C ) == 0x0C ) ? 0 : ( dev->mem_start & 0x0C ) >> 2;
+	priv->speed =      ( ( dev->mem_start & 0x30 ) == 0x30 ) ? 0 : ( dev->mem_start & 0x30 ) >> 4;
+	if ( priv->speed == 0x1 ) {
+		priv->speed = TLAN_SPEED_10;
+	} else if ( priv->speed == 0x2 ) {
+		priv->speed = TLAN_SPEED_100;
 	}
+	priv->sa_int =     dev->mem_start & 0x02;
+	priv->debug =      dev->mem_end;
+
+
+	printk("TLAN %d.%d:  %s irq=%2d io=%04x, %s, Rev. %d\n",
+		TLanVersionMajor,
+		TLanVersionMinor,
+		dev->name, 
+		(int) irq, 
+		io_base,
+		priv->adapter->deviceLabel,
+		priv->adapterRev );
+
+	TLan_Init( dev );
 			
-   	return ( ( found ) ? 0 : -ENODEV );
+   	return 0;
 
 } /* tlan_probe */
 
@@ -390,7 +513,7 @@
 	 *				of the adapter.
 	 *
 	 *	This function searches for an adapter with PCI vendor
-	 *	and device IDs matching those in the TLanDeviceList.
+	 *	and device IDs matching those in the TLanAdapterList.
 	 *	The function 'remembers' the last device it found,
 	 *	and so finds a new device (if anymore are to be found)
 	 *	each time the function is called.  It then looks up
@@ -398,7 +521,7 @@
 	 *
 	 **************************************************************/
 
-int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, int *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix )
+int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix )
 {
 	static int dl_index = 0;
 	static int pci_index = 0;
@@ -409,43 +532,43 @@
 	int	reg;
 
 
-	if ( ! pci_present() ) {
+	if ( ! pcibios_present() ) {
 		printk( "TLAN:   PCI Bios not present.\n" );
 		return 0;
 	}
 
-	for (; TLanDeviceList[dl_index].vendorId != 0; dl_index++) {
+	for (; TLanAdapterList[dl_index].vendorId != 0; dl_index++) {
 
 		not_found = pcibios_find_device(
-			TLanDeviceList[dl_index].vendorId,
-			TLanDeviceList[dl_index].deviceId,
+			TLanAdapterList[dl_index].vendorId,
+			TLanAdapterList[dl_index].deviceId,
 			pci_index,
 			pci_bus,
 			pci_dfn
 		);
 
 		if ( ! not_found ) {
-			struct pci_dev *pdev = pci_find_slot(*pci_bus, *pci_dfn);
 
 			TLAN_DBG(
 				TLAN_DEBUG_GNRL,
 				"TLAN:  found: Vendor Id = 0x%hx, Device Id = 0x%hx\n",
-				TLanDeviceList[dl_index].vendorId,
-				TLanDeviceList[dl_index].deviceId
+				TLanAdapterList[dl_index].vendorId,
+				TLanAdapterList[dl_index].deviceId
 			);
 
-			pci_read_config_byte ( pdev, PCI_REVISION_ID, pci_rev);
-			*pci_irq = pdev->irq;
-			pci_read_config_word ( pdev, PCI_COMMAND, &pci_command);
-			pci_read_config_byte ( pdev, PCI_LATENCY_TIMER, &pci_latency);
+			pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_REVISION_ID, pci_rev);
+			pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_INTERRUPT_LINE, pci_irq);
+			pcibios_read_config_word ( *pci_bus,  *pci_dfn, PCI_COMMAND, &pci_command);
+			pcibios_read_config_dword( *pci_bus,  *pci_dfn, PCI_BASE_ADDRESS_0, pci_io_base);
+			pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_LATENCY_TIMER, &pci_latency);
 
 			if (pci_latency < 0x10) {
-				pci_write_config_byte( pdev, PCI_LATENCY_TIMER, 0xff);
+				pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff);
 				TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    Setting latency timer to max.\n");
 			}
 
-			for ( reg = 0; reg <= 5; reg ++ ) {
-				*pci_io_base = pdev->base_address[reg];
+			for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg +=4 ) {
+				pcibios_read_config_dword( *pci_bus, *pci_dfn, reg, pci_io_base);
 				if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) {
 					*pci_io_base &= PCI_BASE_ADDRESS_IO_MASK;
 					TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    IO mapping is available at %x.\n", *pci_io_base);
@@ -458,8 +581,9 @@
 			if ( *pci_io_base == 0 )
 				printk("TLAN:    IO mapping not available, ignoring device.\n");
 
-			if (pci_command & PCI_COMMAND_MASTER) {
-				TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    Bus mastering is active.\n");
+			if ( ! ( pci_command & PCI_COMMAND_MASTER ) ) {
+				pcibios_write_config_word ( *pci_bus,  *pci_dfn, PCI_COMMAND, pci_command | PCI_COMMAND_MASTER );
+				printk( "TLAN:  Activating PCI bus mastering for this device.\n" );
 			}
 
 			pci_index++;
@@ -500,9 +624,9 @@
 
 int TLan_Init( struct device *dev )
 {
-	int				dma_size;
-	int				err;
-	int				i;
+	int		dma_size;
+	int		err;
+	int		i;
 	TLanPrivateInfo	*priv;
 
 	priv = (TLanPrivateInfo *) dev->priv;
@@ -517,8 +641,14 @@
 	}
 	request_region( dev->base_addr, 0x10, TLanSignature );
 
-	dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
+	if ( bbuf ) {
+		dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
 	           * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE );
+	} else {
+		dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
+	           * ( sizeof(TLanList) );
+	}
+
 	priv->dmaStorage = kmalloc( dma_size, GFP_KERNEL | GFP_DMA );
 	if ( priv->dmaStorage == NULL ) {
 		printk( "TLAN:  Could not allocate lists and buffers for %s.\n",
@@ -529,19 +659,24 @@
 	priv->rxList = (TLanList *) 
 		       ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 );
 	priv->txList = priv->rxList + TLAN_NUM_RX_LISTS;
-	priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS );
-	priv->txBuffer = priv->rxBuffer
-			 + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
+
+	if ( bbuf ) {
+		priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS );
+		priv->txBuffer = priv->rxBuffer
+				 + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
+	}
 
 	err = 0;
 	for ( i = 0;  i < 6 ; i++ )
-		err |= TLan_EeReadByte( dev->base_addr,
-					(u8) 0x83 + i,
+		err |= TLan_EeReadByte( dev,
+					(u8) priv->adapter->addrOfs + i,
 					(u8 *) &dev->dev_addr[i] );
-	if ( err )
+	if ( err ) {
 		printk( "TLAN:  %s: Error reading MAC from eeprom: %d\n",
 			dev->name,
 			err );
+	}
+
 	dev->addr_len = 6;
 
 	dev->open = &TLan_Open;
@@ -550,12 +685,6 @@
 	dev->get_stats = &TLan_GetStats;
 	dev->set_multicast_list = &TLan_SetMulticastList;
 
-#ifndef MODULE
-
-	aui = dev->mem_start & 0x01;
-	debug = dev->mem_end;
-
-#endif /* MODULE */
 
 	return 0;
 
@@ -583,16 +712,21 @@
 
 int TLan_Open( struct device *dev )
 {
-	int				err;
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	int		err;
 
 	priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION );
-	err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev);
+	if ( priv->sa_int ) {
+		TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:   Using SA_INTERRUPT\n" ); 
+		err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ | SA_INTERRUPT, TLanSignature, dev );
+	} else {
+		err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );
+	}
 	if ( err ) {
-		printk( "TLAN:  Cannot open %s because IRQ %d is already in use.\n", dev->name , dev->irq );
+		printk( "TLAN:  Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );
 		return -EAGAIN;
 	}
-
+	
 	MOD_INC_USE_COUNT;
 
 	dev->tbusy = 0;
@@ -604,27 +738,9 @@
 	*/
 	TLan_ResetLists( dev );
 	TLan_ReadAndClearStats( dev, TLAN_IGNORE );
-	TLan_Reset( dev );
-	TLan_Reset( dev );
-	TLan_SetMac( dev, 0, dev->dev_addr );
-	outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
-	if ( debug >= 1 )
-		outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
-
-	init_timer( &priv->timer );
-	priv->timer.data = (unsigned long) dev;
-	priv->timer.function = &TLan_Timer;
-	if ( priv->phyFlags & TLAN_PHY_AUTONEG ) {
-		priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY;
-		priv->timerSetAt = jiffies;
-		priv->timerType = TLAN_TIMER_LINK;
-		add_timer( &priv->timer );
-	} else {
-		outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
-		outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
-	}
+	TLan_ResetAdapter( dev );
 
-	TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  Device %s opened.  Revision = %x\n", dev->name, priv->tlanRev );
+	TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Opened.  TLAN Chip Rev: %x\n", dev->name, priv->tlanRev );
 
 	return 0;
 
@@ -657,27 +773,37 @@
 int TLan_StartTx( struct sk_buff *skb, struct device *dev )
 {
 	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-	TLanList		*tail_list;
-	u8				*tail_buffer;
-	int				pad;
+	TLanList	*tail_list;
+	u8		*tail_buffer;
+	int		pad;
 
 	if ( ! priv->phyOnline ) {
 		TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  %s PHY is not ready\n", dev->name );
-		dev_kfree_skb( skb );
+		dev_kfree_skb( skb, FREE_WRITE );
 		return 0;
 	}
 
 	tail_list = priv->txList + priv->txTail;
+
 	if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {
 		TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail );
 		dev->tbusy = 1;
 		priv->txBusyCount++;
 		return 1;
 	}
+
 	tail_list->forward = 0;
-	tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
-	memcpy( tail_buffer, skb->data, skb->len );
+
+	if ( bbuf ) {
+		tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
+		memcpy( tail_buffer, skb->data, skb->len );
+	} else {
+		tail_list->buffer[0].address = virt_to_bus( skb->data );
+		tail_list->buffer[9].address = (u32) skb;
+	}
+
 	pad = TLAN_MIN_FRAME_SIZE - skb->len;
+
 	if ( pad > 0 ) {
 		tail_list->frameSize = (u16) skb->len + pad;
 		tail_list->buffer[0].count = (u32) skb->len;
@@ -689,7 +815,7 @@
 		tail_list->buffer[1].count = 0;
 		tail_list->buffer[1].address = 0;
 	}
-	/* are we transferring? */
+
 	cli();
 	tail_list->cStat = TLAN_CSTAT_READY;
 	if ( ! priv->txInProgress ) {
@@ -700,17 +826,19 @@
 		outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD );
 	} else {
 		TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Adding buffer %d to TX channel\n", priv->txTail );
-		if ( priv->txTail == 0 )
+		if ( priv->txTail == 0 ) {
 			( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list );
-		else
+		} else {
 			( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list );
+		}
 	}
 	sti();
-	priv->txTail++;
-	if ( priv->txTail >= TLAN_NUM_TX_LISTS )
-		priv->txTail = 0;
 
-	dev_kfree_skb( skb );
+	CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
+
+	if ( bbuf ) {
+		dev_kfree_skb( skb, FREE_WRITE );
+	}
 		
 	dev->trans_start = jiffies;
 	return 0;
@@ -743,35 +871,34 @@
 
 void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	u32				ack;
+	u32		ack;
 	struct device	*dev;
-	u32				host_cmd;
-	u16				host_int;
-	int				type;
+	u32		host_cmd;
+	u16		host_int;
+	int		type;
 
 	dev = (struct device *) dev_id;
 
-	if ( dev->interrupt )
-		printk( "TLAN:   Re-entering interrupt handler for %s: %d.\n" , dev->name, dev->interrupt );
-	dev->interrupt++;
-
 	cli();
+	if ( dev->interrupt ) {
+		printk( "TLAN:   Re-entering interrupt handler for %s: %ld.\n" , dev->name, dev->interrupt );
+	}
+	dev->interrupt++;
 
 	host_int = inw( dev->base_addr + TLAN_HOST_INT );
-	outw( host_int, dev->base_addr + TLAN_HOST_INT ); /* Deactivate Ints */
+	outw( host_int, dev->base_addr + TLAN_HOST_INT );
 
 	type = ( host_int & TLAN_HI_IT_MASK ) >> 2;
 
 	ack = TLanIntVector[type]( dev, host_int );
 
-	sti();
-
 	if ( ack ) {
 		host_cmd = TLAN_HC_ACK | ack | ( type << 18 );
 		outl( host_cmd, dev->base_addr + TLAN_HOST_CMD );
 	}
 
 	dev->interrupt--;
+	sti();
 
 } /* TLan_HandleInterrupts */
 
@@ -802,10 +929,11 @@
 
 	TLan_ReadAndClearStats( dev, TLAN_RECORD );
 	outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
-	if ( priv->timerSetAt != 0 )
+	if ( priv->timer.function != NULL )
 		del_timer( &priv->timer );
 	free_irq( dev->irq, dev );
-	TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:   Device %s closed.\n", dev->name );
+	TLan_FreeLists( dev );
+	TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  Device %s closed.\n", dev->name );
 
 	MOD_DEC_USE_COUNT;
 
@@ -882,11 +1010,11 @@
 void TLan_SetMulticastList( struct device *dev )
 {	
 	struct dev_mc_list	*dmi = dev->mc_list;
-	u32					hash1 = 0;
-	u32					hash2 = 0;
-	int					i;
-	u32					offset;
-	u8					tmp;
+	u32			hash1 = 0;
+	u32			hash2 = 0;
+	int			i;
+	u32			offset;
+	u8			tmp;
 
 	if ( dev->flags & IFF_PROMISC ) {
 		tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
@@ -989,19 +1117,24 @@
 u32 TLan_HandleTxEOF( struct device *dev, u16 host_int )
 {
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
-	int				eoc = 0;
-	TLanList		*head_list;
-	u32				ack = 1;
+	int		eoc = 0;
+	TLanList	*head_list;
+	u32		ack = 1;
 
 	TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
 	host_int = 0;
 	head_list = priv->txList + priv->txHead;
+
+	if ( ! bbuf ) {
+		dev_kfree_skb( (struct sk_buff *) head_list->buffer[9].address, FREE_WRITE );
+		head_list->buffer[9].address = 0;
+	}
+
 	if ( head_list->cStat & TLAN_CSTAT_EOC )
 		eoc = 1;
 	if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
 		printk( "TLAN:  Received interrupt for uncompleted TX frame.\n" );
 	}
-	/* printk( "Ack %d CSTAT=%hx\n", priv->txHead, head_list->cStat ); */
 
 #if LINUX_KERNEL_VERSION > 0x20100
 	priv->stats->tx_bytes += head_list->frameSize;
@@ -1009,9 +1142,7 @@
 
 	head_list->cStat = TLAN_CSTAT_UNUSED;
 	dev->tbusy = 0;
-	priv->txHead++;
-	if ( priv->txHead >= TLAN_NUM_TX_LISTS )
-		priv->txHead = 0;
+	CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS );
 	if ( eoc ) {
 		TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
 		head_list = priv->txList + priv->txHead;
@@ -1022,17 +1153,13 @@
 			priv->txInProgress = 0;
 		}
 	}
-	TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
-	if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) {
-		if ( priv->timerSetAt == 0 ) {
-			/* printk("TxEOF Starting timer...\n"); */
-			priv->timerSetAt = jiffies;
-			priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
-			priv->timerType = TLAN_TIMER_ACT;
-			add_timer( &priv->timer );
-		} else if ( priv->timerType == TLAN_TIMER_ACT ) {
+
+	if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
+		TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+		if ( priv->timer.function == NULL ) {
+			TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
+		} else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
 			priv->timerSetAt = jiffies;
-			/* printk("TxEOF continuing timer...\n"); */
 		}
 	}
 
@@ -1093,7 +1220,7 @@
 	 *	of the list.  If the frame was the last in the Rx
 	 *	channel (EOC), the function restarts the receive channel
 	 *	by sending an Rx Go command to the adapter.  Then it
-	 *	activates/continues the activity LED.
+	 *	activates/continues the the activity LED.
 	 *
 	 **************************************************************/
 
@@ -1112,11 +1239,14 @@
 	host_int = 0;
 	head_list = priv->rxList + priv->rxHead;
 	tail_list = priv->rxList + priv->rxTail;
-	if ( head_list->cStat & TLAN_CSTAT_EOC )
+
+	if ( head_list->cStat & TLAN_CSTAT_EOC ) {
 		eoc = 1;
+	}
+
 	if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
 		printk( "TLAN:  Received interrupt for uncompleted RX frame.\n" );
-	} else {
+	} else if ( bbuf ) {
 		skb = dev_alloc_skb( head_list->frameSize + 7 );
 		if ( skb == NULL ) { 
 			printk( "TLAN:  Couldn't allocate memory for received data.\n" );
@@ -1125,7 +1255,6 @@
 			skb->dev = dev;
 			skb_reserve( skb, 2 );
 			t = (void *) skb_put( skb, head_list->frameSize );
-			/* printk( " %hd %p %p\n", head_list->frameSize, skb->data, t ); */
 
 #if LINUX_KERNEL_VERSION > 0x20100
 			priv->stats->rx_bytes += head_list->frameSize;
@@ -1135,17 +1264,39 @@
 			skb->protocol = eth_type_trans( skb, dev );
 			netif_rx( skb );
 		}
+	} else {
+		skb = (struct sk_buff *) head_list->buffer[9].address;
+		head_list->buffer[9].address = 0;
+		skb_trim( skb, head_list->frameSize );
+
+#if LINUX_KERNEL_VERSION > 0x20100
+			priv->stats->rx_bytes += head_list->frameSize;
+#endif
+
+		skb->protocol = eth_type_trans( skb, dev );
+		netif_rx( skb );
+
+		skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
+		if ( skb == NULL ) {
+			printk( "TLAN:  Couldn't allocate memory for received data.\n" );
+			/* If this ever happened it would be a problem */
+		} else {
+			skb->dev = dev;
+			skb_reserve( skb, 2 );
+			t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE );
+			head_list->buffer[0].address = virt_to_bus( t );
+			head_list->buffer[9].address = (u32) skb;
+		}
 	}
+
 	head_list->forward = 0;
 	head_list->frameSize = TLAN_MAX_FRAME_SIZE;
 	head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
 	tail_list->forward = virt_to_bus( head_list );
-	priv->rxHead++;
-	if ( priv->rxHead >= TLAN_NUM_RX_LISTS )
-		priv->rxHead = 0;
-	priv->rxTail++;
-	if ( priv->rxTail >= TLAN_NUM_RX_LISTS )
-		priv->rxTail = 0;
+
+	CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS );
+	CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS );
+
 	if ( eoc ) { 
 		TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE:  Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
 		head_list = priv->rxList + priv->rxHead;
@@ -1153,19 +1304,16 @@
 		ack |= TLAN_HC_GO | TLAN_HC_RT;
 		priv->rxEocCount++;
 	}
-	TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
-	if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) {
-		if ( priv->timerSetAt == 0 )  {
-			/* printk("RxEOF Starting timer...\n"); */
-			priv->timerSetAt = jiffies;
-			priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
-			priv->timerType = TLAN_TIMER_ACT;
-			add_timer( &priv->timer );
-		} else if ( priv->timerType == TLAN_TIMER_ACT ) {
-			/* printk("RxEOF tarting continuing timer...\n"); */
+
+	if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
+		TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+		if ( priv->timer.function == NULL )  {
+			TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
+		} else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
 			priv->timerSetAt = jiffies;
 		}
 	}
+
 	dev->last_rx = jiffies;
 
 	return ack;
@@ -1195,7 +1343,7 @@
 u32 TLan_HandleDummy( struct device *dev, u16 host_int )
 {
 	host_int = 0;
-	printk( "TLAN:  Dummy interrupt on %s.\n", dev->name );
+	printk( "TLAN:  Test interrupt on %s.\n", dev->name );
 	return 1;
 
 } /* TLan_HandleDummy */
@@ -1270,45 +1418,49 @@
 
 u32 TLan_HandleStatusCheck( struct device *dev, u16 host_int )
 {	
-	u32				ack;
-	u32				error;
-	u8				net_sts;
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	u32		ack;
+	u32		error;
+	u8		net_sts;
+	u32		phy;
+	u16		tlphy_ctl;
+	u16		tlphy_sts;
 	
 	ack = 1;
 	if ( host_int & TLAN_HI_IV_MASK ) {
 		error = inl( dev->base_addr + TLAN_CH_PARM );
-		printk( "TLAN:   Adaptor Check on device %s err = 0x%x\n", dev->name, error );
+		printk( "TLAN:  %s: Adaptor Error = 0x%x\n", dev->name, error );
 		TLan_ReadAndClearStats( dev, TLAN_RECORD );
 		outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
+		TLan_FreeLists( dev );
 		TLan_ResetLists( dev );
-		TLan_Reset( dev );
+		TLan_ResetAdapter( dev );
 		dev->tbusy = 0;
-		TLan_SetMac( dev, 0, dev->dev_addr );
-		if ( priv->timerType == 0 ) {
-			if ( priv->phyFlags & TLAN_PHY_AUTONEG ) {
-				priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY;
-				priv->timerSetAt = jiffies;
-				priv->timerType = TLAN_TIMER_LINK;
-				add_timer( &priv->timer );
-			} else {
-				/*printk( " RX GO---->\n" ); */
-				outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
-				outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
-			}
-		}
 		ack = 0;
 	} else {
+		TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Status Check\n", dev->name );
+		phy = priv->phy[priv->phyNum];
+
 		net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS );
-		if ( net_sts )
+		if ( net_sts ) {
 			TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts );
-		if ( net_sts & TLAN_NET_STS_MIRQ ) {
-			(*priv->phyService)( dev );
+			TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s:    Net_Sts = %x\n", dev->name, (unsigned) net_sts );
+		}
+		if ( ( net_sts & TLAN_NET_STS_MIRQ ) &&  ( priv->phyNum == 0 ) ) {
+			TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts );
+			TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl );
+        		if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
+                		tlphy_ctl |= TLAN_TC_SWAPOL;
+                		TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);
+        		} else if ( ( tlphy_sts & TLAN_TS_POLOK ) && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
+                		tlphy_ctl &= ~TLAN_TC_SWAPOL;
+                		TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);
+        		}
+
 			if (debug) {
 				TLan_PhyPrint( dev );
 			}
 		}
-		TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  Status Check! %s Net_Sts=%x\n", dev->name, (unsigned) net_sts );
 	}
 
 	return ack;
@@ -1341,8 +1493,8 @@
 u32 TLan_HandleRxEOC( struct device *dev, u16 host_int )
 {
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
-	TLanList		*head_list;
-	u32				ack = 1;
+	TLanList	*head_list;
+	u32		ack = 1;
 
 	host_int = 0;
 	if (  priv->tlanRev < 0x30 ) {
@@ -1402,34 +1554,44 @@
 void TLan_Timer( unsigned long data )
 {
 	struct device	*dev = (struct device *) data;
-	u16		gen_sts;
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	u32		elapsed;
 
-	/* printk( "TLAN:  %s Entered Timer, type = %d\n", dev->name, priv->timerType ); */
+	priv->timer.function = NULL;
 
 	switch ( priv->timerType ) {
-		case TLAN_TIMER_LINK:
-			TLan_MiiReadReg( dev->base_addr, priv->phyAddr, MII_GEN_STS, &gen_sts );
-			if ( gen_sts & MII_GS_LINK ) {
-				priv->phyOnline = 1;
-				outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
-				outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
-				priv->timerSetAt = 0;
-				priv->timerType = 0;
-			} else {
-				priv->timer.expires = jiffies + ( TLAN_TIMER_LINK_DELAY * 2 );
-				add_timer( &priv->timer );
-			}
+		case TLAN_TIMER_PHY_PDOWN:
+			TLan_PhyPowerDown( dev );
 			break;
-		case TLAN_TIMER_ACT:
-			if ( jiffies - priv->timerSetAt >= TLAN_TIMER_ACT_DELAY ) {
-				TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
-				priv->timerSetAt = 0;
-				priv->timerType = 0;
-			} else {
-				priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;
-				add_timer( &priv->timer );
+		case TLAN_TIMER_PHY_PUP:
+			TLan_PhyPowerUp( dev );
+			break;
+		case TLAN_TIMER_PHY_RESET:
+			TLan_PhyReset( dev );
+			break;
+		case TLAN_TIMER_PHY_START_LINK:
+			TLan_PhyStartLink( dev );
+			break;
+		case TLAN_TIMER_PHY_FINISH_AN:
+			TLan_PhyFinishAutoNeg( dev );
+			break;
+		case TLAN_TIMER_FINISH_RESET:
+			TLan_FinishReset( dev );
+			break;
+		case TLAN_TIMER_ACTIVITY:
+			cli();
+			if ( priv->timer.function == NULL ) {
+				elapsed = jiffies - priv->timerSetAt;
+				if ( elapsed >= TLAN_TIMER_ACT_DELAY ) {
+					TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
+				} else  {
+					priv->timer.function = &TLan_Timer;
+					priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;
+					sti();
+					add_timer( &priv->timer );
+				}
 			}
+			sti();
 			break;
 		default:
 			break;
@@ -1468,13 +1630,19 @@
 	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
 	int		i;
 	TLanList	*list;
+	struct sk_buff	*skb;
+	void		*t = NULL;
 
 	priv->txHead = 0;
 	priv->txTail = 0;
 	for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
 		list = priv->txList + i;
 		list->cStat = TLAN_CSTAT_UNUSED;
-		list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+		if ( bbuf ) {
+			list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+		} else {
+			list->buffer[0].address = 0;
+		}
 		list->buffer[2].count = 0;
 		list->buffer[2].address = 0;
 	}
@@ -1486,7 +1654,21 @@
 		list->cStat = TLAN_CSTAT_READY;
 		list->frameSize = TLAN_MAX_FRAME_SIZE;
 		list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
-		list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+		if ( bbuf ) {
+			list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+		} else {
+			skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
+			if ( skb == NULL ) {
+				printk( "TLAN:  Couldn't allocate memory for received data.\n" );
+				/* If this ever happened it would be a problem */
+			} else {
+				skb->dev = dev;
+				skb_reserve( skb, 2 );
+				t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE );
+			}
+			list->buffer[0].address = virt_to_bus( t );
+			list->buffer[9].address = (u32) skb;
+		}
 		list->buffer[1].count = 0;
 		list->buffer[1].address = 0;
 		if ( i < TLAN_NUM_RX_LISTS - 1 )
@@ -1498,6 +1680,36 @@
 } /* TLan_ResetLists */
 
 
+void TLan_FreeLists( struct device *dev )
+{
+	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+	int		i;
+	TLanList	*list;
+	struct sk_buff	*skb;
+
+	if ( ! bbuf ) {
+		for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
+			list = priv->txList + i;
+			skb = (struct sk_buff *) list->buffer[9].address;
+			if ( skb ) {
+				dev_kfree_skb( skb, FREE_WRITE );
+				list->buffer[9].address = 0;
+			}
+		}
+
+		for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) {
+			list = priv->rxList + i;
+			skb = (struct sk_buff *) list->buffer[9].address;
+			if ( skb ) {
+				dev_kfree_skb( skb, FREE_READ );
+				list->buffer[9].address = 0;
+			}
+		}
+	}
+
+} /* TLan_FreeLists */
+
+
 
 
 	/***************************************************************
@@ -1509,7 +1721,7 @@
 	 *		io_base		Base IO port of the device of
 	 *				which to print DIO registers.
 	 *
-	 *	This function prints out all the internal (DIO)
+	 *	This function prints out all the the internal (DIO)
 	 *	registers of a TLAN chip.
 	 *
 	 **************************************************************/
@@ -1588,11 +1800,11 @@
 void TLan_ReadAndClearStats( struct device *dev, int record )
 {
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
-	u32				tx_good, tx_under;
-	u32				rx_good, rx_over;
-	u32				def_tx, crc, code;
-	u32				multi_col, single_col;
-	u32				excess_col, late_col, loss;
+	u32		tx_good, tx_under;
+	u32		rx_good, rx_over;
+	u32		def_tx, crc, code;
+	u32		multi_col, single_col;
+	u32		excess_col, late_col, loss;
 
 	outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR );
 	tx_good  = inb( dev->base_addr + TLAN_DIO_DATA );
@@ -1660,7 +1872,8 @@
 	 *
 	 **************************************************************/
 
-int TLan_Reset( struct device *dev )
+void
+TLan_ResetAdapter( struct device *dev )
 {
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
 	int		i;
@@ -1668,11 +1881,14 @@
 	u32		data;
 	u8		data8;
 
+	priv->tlanFullDuplex = FALSE;
 /*  1.	Assert reset bit. */
 
 	data = inl(dev->base_addr + TLAN_HOST_CMD);
 	data |= TLAN_HC_AD_RST;
 	outl(data, dev->base_addr + TLAN_HOST_CMD);
+	
+	udelay(1000);
 
 /*  2.	Turn off interrupts. ( Probably isn't necessary ) */
 
@@ -1708,37 +1924,97 @@
 		data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC;
 		TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, data8 );
 	}
-	TLan_PhySelect( dev );
+	TLan_PhyDetect( dev );
 	data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN;
-	if ( priv->phyFlags & TLAN_PHY_BIT_RATE ) {
+	if ( priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY ) {
 		data |= TLAN_NET_CFG_BIT;
-		if ( aui == 1 ) {
+		if ( priv->aui == 1 ) {
 			TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x0a );
+		} else if ( priv->duplex == TLAN_DUPLEX_FULL ) {
+			TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x00 );
+			priv->tlanFullDuplex = TRUE;
 		} else {
 			TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 );
 		}
 	}
-	if ( priv->phyFlags & TLAN_PHY_INTERNAL ) {
+	if ( priv->phyNum == 0 ) {
 		data |= TLAN_NET_CFG_PHY_EN;
 	}
 	TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data );
-	(*priv->phyCheck)( dev ); 
-	data8 = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP;
-	TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data8 );
-	data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5; 
-	if ( priv->phyFlags & TLAN_PHY_INTS ) {
-		data8 |= TLAN_NET_MASK_MASK7; 
+
+	if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) {
+		TLan_FinishReset( dev );
+	} else {
+		TLan_PhyPowerDown( dev );
 	}
-	TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data8 );
+
+} /* TLan_ResetAdapter */
+
+
+
+
+void
+TLan_FinishReset( struct device *dev )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	u8		data;
+	u32		phy;
+	u8		sio;
+	u16		status;
+	u16		tlphy_ctl;
+
+	phy = priv->phy[priv->phyNum];
+
+	data = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP;
+	if ( priv->tlanFullDuplex ) {
+		data |= TLAN_NET_CMD_DUPLEX;
+	}
+	TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data );
+	data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5; 
+	if ( priv->phyNum == 0 ) {
+		data |= TLAN_NET_MASK_MASK7; 
+	}
+	TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data );
 	TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, TLAN_MAX_FRAME_SIZE );
 
-	if ( priv->phyFlags & TLAN_PHY_UNMANAGED ) {
-		priv->phyOnline = 1;
+	if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) {
+		status = MII_GS_LINK;
+		printk( "TLAN:  %s: Link forced.\n", dev->name );
+	} else {
+		TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+		udelay( 1000 );
+		TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+		if ( status & MII_GS_LINK ) {
+			printk( "TLAN:  %s: Link active.\n", dev->name );
+			TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
+		}
 	}
 
-	return 0;
+	if ( priv->phyNum == 0 ) {
+        	TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl );
+        	tlphy_ctl |= TLAN_TC_INTEN;
+        	TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl );
+        	sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO );
+        	sio |= TLAN_NET_SIO_MINTEN;
+        	TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio );
+	}
+
+	if ( status & MII_GS_LINK ) {
+		TLan_SetMac( dev, 0, dev->dev_addr );
+		priv->phyOnline = 1;
+		outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
+		if ( debug >= 1 ) {
+			outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
+		}
+		outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
+		outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
+	} else {
+		printk( "TLAN:  %s: Link inactive, will retry in 10 secs...\n", dev->name );
+		TLan_SetTimer( dev, 1000, TLAN_TIMER_FINISH_RESET );
+		return;
+	}
 
-} /* TLan_Reset */
+} /* TLan_FinishReset */
 
 
 
@@ -1754,7 +2030,7 @@
 	 *		areg	The AREG to set the address in (0 - 3).
 	 *		mac	A pointer to an array of chars.  Each
 	 *			element stores one byte of the address.
-	 *			That is, it isn't in ASCII.
+	 *			IE, it isn't in ascii.
 	 *
 	 *	This function transfers a MAC address to one of the
 	 *	TLAN AREGs (address registers).  The TLAN chip locks
@@ -1788,56 +2064,10 @@
 
 	ThunderLAN Driver PHY Layer Routines
 
-	The TLAN chip can drive any number of PHYs (physical devices).  Rather
-	than having lots of 'if' or '#ifdef' statements, I have created a
-	second driver layer for the PHYs.  Each PHY can be identified from its
-	id in registers 2 and 3, and can be given a Check and Service routine
-	that will be called when the adapter is reset and when the adapter
-	receives a Network Status interrupt, respectively.
-	
 ******************************************************************************
 *****************************************************************************/
 
 
-static TLanPhyIdEntry	TLanPhyIdTable[] = {
-	  { 0x4000,
-	    0x5014,
-	    &TLan_PhyInternalCheck,
-	    &TLan_PhyInternalService,
-	    TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
-	  { 0x4000,
-	    0x5015,
-	    &TLan_PhyInternalCheck,
-	    &TLan_PhyInternalService,
-	    TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
-	  { 0x4000,
-	    0x5016,
-	    &TLan_PhyInternalCheck,
-	    &TLan_PhyInternalService,
-	    TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
-	  { 0x2000,
-	    0x5C00,
-	    &TLan_PhyDp83840aCheck,
-	    &TLan_PhyNop,
-	    TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG },
-	  { 0x2000,
-	    0x5C01,
-	    &TLan_PhyDp83840aCheck,
-	    &TLan_PhyNop,
-	    TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG },
-	  { 0x7810,
-	    0x0000,
-	    &TLan_PhyDp83840aCheck,
-	    &TLan_PhyNop,
-	    TLAN_PHY_AUTONEG },
-	  { 0x0000,
-	    0x0000,
-	    NULL,
-	    NULL,
-	    0
-	  }
-	};
-
 
 	/*********************************************************************
 	 *	TLan_PhyPrint
@@ -1845,10 +2075,10 @@
 	 *	Returns:
 	 *		Nothing
 	 *	Parms:
-	 *		dev	A pointer to the device structure of the adapter
-	 *			which the desired PHY is located.
+	 *		dev	A pointer to the device structure of the
+	 *			TLAN device having the PHYs to be detailed.
 	 *				
-	 *	This function prints the registers a PHY.
+	 *	This function prints the registers a PHY (aka tranceiver).
 	 *
 	 ********************************************************************/
 
@@ -1856,30 +2086,27 @@
 {
 	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
 	u16 i, data0, data1, data2, data3, phy;
-	u32 io;
 
-	phy = priv->phyAddr;
-	io = dev->base_addr;
+	phy = priv->phy[priv->phyNum];
 
-	if ( ( phy > 0 ) && ( phy <= TLAN_PHY_MAX_ADDR ) ) {
+	if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) {
+		printk( "TLAN:   Device %s, Unmanaged PHY.\n", dev->name );
+	} else if ( phy <= TLAN_PHY_MAX_ADDR ) {
 		printk( "TLAN:   Device %s, PHY 0x%02x.\n", dev->name, phy );
 		printk( "TLAN:      Off.  +0     +1     +2     +3 \n" );
                 for ( i = 0; i < 0x20; i+= 4 ) {
 			printk( "TLAN:      0x%02x", i );
-			TLan_MiiReadReg( io, phy, i, &data0 );
+			TLan_MiiReadReg( dev, phy, i, &data0 );
 			printk( " 0x%04hx", data0 );
-			TLan_MiiReadReg( io, phy, i + 1, &data1 );
+			TLan_MiiReadReg( dev, phy, i + 1, &data1 );
 			printk( " 0x%04hx", data1 );
-			TLan_MiiReadReg( io, phy, i + 2, &data2 );
+			TLan_MiiReadReg( dev, phy, i + 2, &data2 );
 			printk( " 0x%04hx", data2 );
-			TLan_MiiReadReg( io, phy, i + 3, &data3 );
+			TLan_MiiReadReg( dev, phy, i + 3, &data3 );
 			printk( " 0x%04hx\n", data3 );
 		}
 	} else {
-		printk( "TLAN:   Device %s, PHY 0x%02x (Unmanaged/Unknown).\n",
-			dev->name,
-			phy
-		      );
+		printk( "TLAN:   Device %s, Invalid PHY.\n", dev->name );
 	}
 
 } /* TLan_PhyPrint */
@@ -1888,7 +2115,7 @@
 
 
 	/*********************************************************************
-	 *	TLan_PhySelect
+	 *	TLan_PhyDetect
 	 *
 	 *	Returns:
 	 *		Nothing
@@ -1896,352 +2123,271 @@
 	 *		dev	A pointer to the device structure of the adapter
 	 *			for which the PHY needs determined.
 	 *
-	 *	This function decides which PHY amoung those attached to the
-	 *	TLAN chip is to be used.  The TLAN chip can be attached to
-	 *	multiple PHYs, and the driver needs to decide which one to
-	 *	talk to.  Currently this routine picks the PHY with the lowest
-	 *	address as the internal PHY address is 0x1F, the highest
-	 *	possible.  This strategy assumes that there can be only one
-	 *	other PHY, and, if it exists, it is the one to be used.  If
-	 *	token ring PHYs are ever supported, this routine will become
-	 *	a little more interesting...
+	 *	So far I've found that adapters which have external PHYs
+	 *	may also use the internal PHY for part of the functionality.
+	 *	(eg, AUI/Thinnet).  This function finds out if this TLAN
+	 *	chip has an internal PHY, and then finds the first external
+	 *	PHY (starting from address 0) if it exists).
 	 *
 	 ********************************************************************/
 
-void TLan_PhySelect( struct device *dev )
+void TLan_PhyDetect( struct device *dev )
 {
 	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-	int		 	phy;
-	int			entry;
-	u16			id_hi[TLAN_PHY_MAX_ADDR + 1];
-	u16			id_lo[TLAN_PHY_MAX_ADDR + 1];
-	u16			hi;
-	u16			lo;
-	u16			vendor;
-	u16			device;
-
-	priv->phyCheck = &TLan_PhyNop;	/* Make sure these aren't ever NULL */
-	priv->phyService = &TLan_PhyNop;
-	
-	vendor = TLanDeviceList[priv->pciEntry].vendorId;
-	device = TLanDeviceList[priv->pciEntry].deviceId;
+	u16		control;
+	u16		hi;
+	u16		lo;
+	u32		phy;
 
-	/*
-	 * This is a bit uglier than I'd like, but the 0xF130 device must
-	 * NOT be assigned a valid PHY as it uses an unmanaged, bit-rate
-	 * PHY.  It is simplest just to use another goto, rather than
-	 * nesting the two for loops in the if statement.
-	 */
-	if ( ( vendor == PCI_VENDOR_ID_COMPAQ ) &&
-	     ( device == PCI_DEVICE_ID_NETFLEX_3P ) ) {
-		entry = 0;
-		phy = 0;
-		goto FINISH;
+	if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) {
+		priv->phyNum = 0xFFFF;
+		return;
 	}
 
-	for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) {
-		hi = lo = 0;
-		TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_HI, &hi );
-		TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_LO, &lo );
-		id_hi[phy] = hi;
-		id_lo[phy] = lo;
-		TLAN_DBG( TLAN_DEBUG_GNRL,
-			  "TLAN: Phy %2x, hi = %hx, lo = %hx\n",
-			  phy,
-			  hi,
-			  lo
-			);
+	TLan_MiiReadReg( dev, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi );
+
+	if ( hi != 0xFFFF ) {
+		priv->phy[0] = TLAN_PHY_MAX_ADDR;
+	} else {
+		priv->phy[0] = TLAN_PHY_NONE;
 	}
 
+	priv->phy[1] = TLAN_PHY_NONE;
 	for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) {
-		if ( ( aui == 1 ) && ( phy != TLAN_PHY_MAX_ADDR ) ) {
-			if ( id_hi[phy] != 0xFFFF ) {
-				TLan_MiiSync(dev->base_addr);
-				TLan_MiiWriteReg(dev->base_addr,
-						 phy,
-						 MII_GEN_CTL,
-						 MII_GC_PDOWN | 
-						 MII_GC_LOOPBK | 
-						 MII_GC_ISOLATE );
-
-			}
-			continue;
-		}
-		for ( entry = 0; TLanPhyIdTable[entry].check; entry++) {
-			if ( ( id_hi[phy] == TLanPhyIdTable[entry].idHi ) &&
-			     ( id_lo[phy] == TLanPhyIdTable[entry].idLo ) ) {
-				TLAN_DBG( TLAN_DEBUG_GNRL,
-					  "TLAN: Selected Phy %hx\n",
-					  phy
-					);
-				goto FINISH;
+		TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &control );
+		TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &hi );
+		TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &lo );
+		if ( ( control != 0xFFFF ) || ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) {
+			TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: PHY found at %02x %04x %04x %04x\n", phy, control, hi, lo );
+			if ( ( priv->phy[1] == TLAN_PHY_NONE ) && ( phy != TLAN_PHY_MAX_ADDR ) ) {
+				priv->phy[1] = phy;
 			}
 		}
 	}
 
-	entry = 0;
-	phy = 0;
-
-FINISH:
-	
-	if ( ( entry == 0 ) && ( phy == 0 ) ) {
-		priv->phyAddr = phy;
-		priv->phyEntry = entry;
-		priv->phyCheck = TLan_PhyNop;
-		priv->phyService = TLan_PhyNop;
-		priv->phyFlags = TLAN_PHY_BIT_RATE | 
-                                 TLAN_PHY_UNMANAGED |
-				 TLAN_PHY_ACTIVITY;
+	if ( priv->phy[1] != TLAN_PHY_NONE ) {
+		priv->phyNum = 1;
+	} else if ( priv->phy[0] != TLAN_PHY_NONE ) {
+		priv->phyNum = 0;
 	} else {
-		priv->phyAddr = phy;
-		priv->phyEntry = entry;
-		priv->phyCheck = TLanPhyIdTable[entry].check;
-		priv->phyService = TLanPhyIdTable[entry].service;
-		priv->phyFlags = TLanPhyIdTable[entry].flags;
+		printk( "TLAN:  Cannot initialize device, no PHY was found!\n" );
 	}
 
-} /* TLan_PhySelect */
+} /* TLan_PhyDetect */
 
 
 
 
-	/***************************************************************
-	 *	TLan_PhyNop
-	 *
-	 *	Returns:
-	 *		Nothing
-	 *	Parms:
-	 *		dev	A pointer to a device structure.
-	 *
-	 *	This function does nothing and is meant as a stand-in
-	 *	for when a Check or Service function would be
-	 *	meaningless.
-	 *
-	 **************************************************************/
+void TLan_PhyPowerDown( struct device *dev )
+{
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	u16		value;
+
+	TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Powering down PHY(s).\n", dev->name );
+	value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE;
+	TLan_MiiSync( dev->base_addr );
+	TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value );
+	if ( ( priv->phyNum == 0 ) && ( priv->phy[1] != TLAN_PHY_NONE ) && ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) {
+		TLan_MiiSync( dev->base_addr );
+		TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value );
+	}
 
-int TLan_PhyNop( struct device *dev )
+	/* Wait for 5 jiffies (50 ms) and powerup
+	 * This is abitrary.  It is intended to make sure the
+	 * tranceiver settles.
+	 */
+	TLan_SetTimer( dev, 5, TLAN_TIMER_PHY_PUP );
+
+} /* TLan_PhyPowerDown */
+
+
+
+
+void TLan_PhyPowerUp( struct device *dev )
 {
-	dev = NULL;
-	return 0;
+	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+	u16		value;
 
-} /* TLan_PhyNop */
+	TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Powering up PHY.\n", dev->name );
+	TLan_MiiSync( dev->base_addr );
+	value = MII_GC_LOOPBK;
+	TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value );
+
+	/* Wait for 50 jiffies (500 ms) and reset the
+	 * tranceiver.  The TLAN docs say both 50 ms and
+	 * 500 ms, so do the longer, just in case
+	 */
+	TLan_SetTimer( dev, 50, TLAN_TIMER_PHY_RESET );
 
+} /* TLan_PhyPowerUp */
 
 
 
-	/***************************************************************
-	 *  TLan_PhyInternalCheck
-	 *
-	 *	Returns:
-	 *		Nothing
-	 *	Parms:
-	 *		dev	A pointer to a device structure of the
-	 *			adapter	holding the PHY to be checked.
-	 *
-	 *	This function resets the internal PHY on a TLAN chip.
-	 *	See Chap. 7, "Physical Interface (PHY)" of "ThunderLAN
-	 *	Programmer's Guide"
-	 *
-	 **************************************************************/
 
-int TLan_PhyInternalCheck( struct device *dev )
+void TLan_PhyReset( struct device *dev )
 {
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
-	u16				gen_ctl;
-	u32				io;
-	u16				phy;
-	u16				value;
-	u8				sio;
-
-	io = dev->base_addr;
-	phy = priv->phyAddr;
-
-	TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl );
-	if ( gen_ctl & MII_GC_PDOWN ) {
-		TLan_MiiSync( io );
-		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE );
-		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK );
-		mdelay(50);
-		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK );
-		TLan_MiiSync( io );
-	}
-
-	TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
-	while ( value & MII_GC_RESET )
-		TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
-
-	/* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); */
-	/* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); */
-	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 );
-
-	mdelay(500);
-
-	TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
-	if ( aui ) 
-		value |= TLAN_TC_AUISEL;
-	else
-		value &= ~TLAN_TC_AUISEL;
-	TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
-
-	/* Read Possible Latched Link Status */
-	TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
-	/* Read Real Link Status */
-       	TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
-	if ( ( value & MII_GS_LINK ) || aui ) {
-		priv->phyOnline = 1;
-		TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
-	} else {
-		priv->phyOnline = 0;
-		TLan_DioWrite8( io, TLAN_LED_REG, 0 );
-	}
+	u16		phy;
+	u16		value;
 
-	/* Enable Interrupts */
-       	TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
-	value |= TLAN_TC_INTEN;
-	TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
-
-	sio = TLan_DioRead8( io, TLAN_NET_SIO );
-	sio |= TLAN_NET_SIO_MINTEN;
-	TLan_DioWrite8( io, TLAN_NET_SIO, sio );
-			
-	return 0;
+	phy = priv->phy[priv->phyNum];
 
-} /* TLanPhyInternalCheck */
+	TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Reseting PHY.\n", dev->name );
+	TLan_MiiSync( dev->base_addr );
+	value = MII_GC_LOOPBK | MII_GC_RESET;
+	TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, value );
+	TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value );
+	while ( value & MII_GC_RESET ) {
+		TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value );
+	}
+	TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0 );
 
+	/* Wait for 50 jiffies (500 ms) and initialize.
+	 * I don't remember why I wait this long.
+	 */
+	TLan_SetTimer( dev, 50, TLAN_TIMER_PHY_START_LINK );
+
+} /* TLan_PhyReset */
 
 
 
-	/***************************************************************
-	 *	TLan_PhyInternalService
-	 *
-	 *	Returns:
-	 *		Nothing
-	 *	Parms:
-	 *		dev	A pointer to a device structure of the
-	 *			adapter	holding the PHY to be serviced.
-	 *
-	 *	This function services an interrupt generated by the
-	 *	internal PHY.  It can turn on/off the link LED.  See
-	 *	Chap. 7, "Physical Interface (PHY)" of "ThunderLAN
-	 *	Programmer's Guide".
-	 *
-	 **************************************************************/
 
-int TLan_PhyInternalService( struct device *dev )
+void TLan_PhyStartLink( struct device *dev )
 {
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
-	u16			tlphy_sts;
-	u16			gen_sts;
-	u16			an_exp;
-	u32			io;
-	u16			phy;
-
-	io = dev->base_addr;
-	phy = priv->phyAddr;
-
-	TLan_MiiReadReg( io, phy, TLAN_TLPHY_STS, &tlphy_sts );
-	TLan_MiiReadReg( io, phy, MII_GEN_STS, &gen_sts ); 
-	TLan_MiiReadReg( io, phy, MII_AN_EXP, &an_exp ); 
-	if ( ( gen_sts & MII_GS_LINK ) || aui ) {
-		priv->phyOnline = 1;
-		TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
-	} else {
-		priv->phyOnline = 0;
-		TLan_DioWrite8( io, TLAN_LED_REG, 0 );
-	}
+	u16		ability;
+	u16		control;
+	u16		data;
+	u16		phy;
+	u16		status;
+	u16		tctl;
+
+	phy = priv->phy[priv->phyNum];
+
+	TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Trying to activate link.\n", dev->name );
+	TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+	if ( ( status & MII_GS_AUTONEG ) && 
+	     ( priv->duplex == TLAN_DUPLEX_DEFAULT ) && 
+	     ( priv->speed == TLAN_SPEED_DEFAULT ) &&
+	     ( ! priv->aui ) ) {
+		ability = status >> 11;
+
+		if ( priv->speed == TLAN_SPEED_10 ) {
+			ability &= 0x0003;
+		} else if ( priv->speed == TLAN_SPEED_100 ) {
+			ability &= 0x001C;
+		}
 
-        if ( ( tlphy_sts & TLAN_TS_POLOK ) == 0) {
-                u16     value;
-                TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value);
-                value |= TLAN_TC_SWAPOL;
-                TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value);
-        }
+		if ( priv->duplex == TLAN_DUPLEX_FULL ) {
+			ability &= 0x000A;
+		} else if ( priv->duplex == TLAN_DUPLEX_HALF ) {
+			ability &= 0x0005;
+		}
 
-	return 0;
+		TLan_MiiWriteReg( dev, phy, MII_AN_ADV, ( ability << 5 ) | 1 );
+       		TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 );
+		TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 );
+
+		/* Wait for 400 jiffies (4 sec) for autonegotiation
+		 * to complete.  The max spec time is less than this
+		 * but the card need additional time to start AN.
+		 * .5 sec should be plenty extra.
+		 */
+		printk( "TLAN:  %s: Starting autonegotiation.\n", dev->name );
+		TLan_SetTimer( dev, 400, TLAN_TIMER_PHY_FINISH_AN );
+		return;
+	}
 
-} /* TLan_PhyInternalService */
+	if ( ( priv->aui ) && ( priv->phyNum != 0 ) ) {
+		priv->phyNum = 0;
+		data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
+		TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data );
+		TLan_SetTimer( dev, 4, TLAN_TIMER_PHY_PDOWN );
+		return;
+	} else if ( priv->phyNum == 0 ) {
+        	TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl );
+		if ( priv->aui ) {
+                	tctl |= TLAN_TC_AUISEL;
+		} else {
+                	tctl &= ~TLAN_TC_AUISEL;
+			control = 0;
+			if ( priv->duplex == TLAN_DUPLEX_FULL ) {
+				control |= MII_GC_DUPLEX;
+				priv->tlanFullDuplex = TRUE;
+			}
+			if ( priv->speed == TLAN_SPEED_100 ) {
+				control |= MII_GC_SPEEDSEL;
+			}
+       			TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, control );
+		}
+        	TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tctl );
+	}
 
+	/* Wait for 100 jiffies (1 sec) to give the tranceiver time
+	 * to establish link.
+	 */
+	TLan_SetTimer( dev, 100, TLAN_TIMER_FINISH_RESET );
 
+} /* TLan_PhyStartLink */
 
 
-	/***************************************************************
-	 *	TLan_PhyDp83840aCheck
-	 *
-	 *	Returns:
-	 *		Nothing
-	 *	Parms:
-	 *		dev	A pointer to a device structure of the
-	 *			adapter holding the PHY to be reset.
-	 *
-	 *	This function resets a National Semiconductor DP83840A
-	 *	10/100 Mb/s PHY device.  See National Semiconductor's
-	 *	data sheet for more info.  This PHY is used on Compaq
-	 *	Netelligent 10/100 cards.
-	 *
-	 **************************************************************/
 
-static int TLan_PhyDp83840aCheck( struct device *dev )
+
+void TLan_PhyFinishAutoNeg( struct device *dev )
 {
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
-	u16			gen_ctl;
-	u32			io;
-	u16			phy;
-	u16			value;
-	u8			sio;
-
-	io = dev->base_addr;
-	phy = priv->phyAddr;
-
-	TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl );
-	if ( gen_ctl & MII_GC_PDOWN ) {
-		TLan_MiiSync( io );
-		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE );
-		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK );
-		mdelay(500);
-		TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK );
-		TLan_MiiSync( io );
-	}
-
-	TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
-	while ( value & MII_GC_RESET )
-		TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
-
-	/* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); */
-	/* TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); */
-	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 );
-	TLan_MiiReadReg( io, phy, MII_AN_ADV, &value );
-	value &= ~0x0140;
-	TLan_MiiWriteReg( io, phy, MII_AN_ADV, value );
-       	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1000 );
-	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1200 );
-
-	mdelay(50);
-#if 0
-	/* Read Possible Latched Link Status */
-	TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
-	/* Read Real Link Status */
-	TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
-	if ( value & MII_GS_LINK ) {
-		priv->phyOnline = 1;
-		TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
-	} else {
-		priv->phyOnline = 0;
-		TLan_DioWrite8( io, TLAN_LED_REG, 0 );
+	u16		an_adv;
+	u16		an_lpa;
+	u16		data;
+	u16		mode;
+	u16		phy;
+	u16		status;
+	
+	phy = priv->phy[priv->phyNum];
+
+	TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
+	if ( ! ( status & MII_GS_AUTOCMPLT ) ) {
+		/* Wait for 800 jiffies (8 sec) to give the process
+		 * more time.  Perhaps we should fail after a while.
+		 */
+		printk( "TLAN:  Giving autonegotiation more time.\n" );
+		TLan_SetTimer( dev, 800, TLAN_TIMER_PHY_FINISH_AN );
+		return;
 	}
 
-	/* Enable Interrupts */
-	TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
-	value |= TLAN_TC_INTEN;
-	TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
-#endif
-	sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO );
-	sio &= ~TLAN_NET_SIO_MINTEN;
-	TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio );
-/*	priv->phyOnline = 1; */
-			
-	return 0;
+	printk( "TLAN:  %s: Autonegotiation complete.\n", dev->name );
+	TLan_MiiReadReg( dev, phy, MII_AN_ADV, &an_adv );
+	TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa );
+	mode = an_adv & an_lpa & 0x03E0;
+	if ( mode & 0x0100 ) {
+		priv->tlanFullDuplex = TRUE;
+	} else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) {
+		priv->tlanFullDuplex = TRUE;
+	}
+
+	if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) {
+		priv->phyNum = 0;
+		data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
+		TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data );
+		TLan_SetTimer( dev, 40, TLAN_TIMER_PHY_PDOWN );
+		return;
+	}
+
+	if ( priv->phyNum == 0 ) {
+		if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || ( an_adv & an_lpa & 0x0040 ) ) {
+			TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB | MII_GC_DUPLEX );
+			printk( "TLAN:  Starting internal PHY with DUPLEX\n" );
+		} else {
+			TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB );
+			printk( "TLAN:  Starting internal PHY with HALF-DUPLEX\n" );
+		}
+	}
 
-} /* TLan_PhyDp83840aCheck */
+	/* Wait for 10 jiffies (100 ms).  No reason in partiticular.
+	 */
+	TLan_SetTimer( dev, 10, TLAN_TIMER_FINISH_RESET );
+		
+} /* TLan_PhyFinishAutoNeg */
 
 
 
@@ -2266,9 +2412,10 @@
 	 *		1	otherwise.
 	 *
 	 *	Parms:
-	 *		base_port	The base IO port of the adapter in
-	 *				question.
-	 *		dev		The address of the PHY to be queried.
+	 *		dev		The device structure containing
+	 *				The io address and interrupt count
+	 *				for this device.
+	 *		phy		The address of the PHY to be queried.
 	 *		reg		The register whose contents are to be
 	 *				retreived.
 	 *		val		A pointer to a variable to store the
@@ -2281,30 +2428,32 @@
 	 *
 	 **************************************************************/
 
-int TLan_MiiReadReg(u16 base_port, u16 dev, u16 reg, u16 *val)
+int TLan_MiiReadReg( struct device *dev, u16 phy, u16 reg, u16 *val )
 {
 	u8	nack;
-	u16 sio, tmp;
-	u32 i;
+	u16	sio, tmp;
+	u32	i;
 	int	err;
-	int minten;
+	int	minten;
 
 	err = FALSE;
-	outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
-	sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+	outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
+	sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
 
-	cli();
+	if ( dev->interrupt == 0 )
+		cli();
+	dev->interrupt++;
 
-	TLan_MiiSync(base_port);
+	TLan_MiiSync(dev->base_addr);
 
 	minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio );
 	if ( minten )
 		TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);
 
-	TLan_MiiSendData( base_port, 0x1, 2 );		/* Start ( 01b ) */
-	TLan_MiiSendData( base_port, 0x2, 2 );		/* Read  ( 10b ) */
-	TLan_MiiSendData( base_port, dev, 5 );		/* Device #      */
-	TLan_MiiSendData( base_port, reg, 5 );		/* Register #    */
+	TLan_MiiSendData( dev->base_addr, 0x1, 2 );	/* Start ( 01b ) */
+	TLan_MiiSendData( dev->base_addr, 0x2, 2 );	/* Read  ( 10b ) */
+	TLan_MiiSendData( dev->base_addr, phy, 5 );	/* Device #      */
+	TLan_MiiSendData( dev->base_addr, reg, 5 );	/* Register #    */
 
 
 	TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio);		/* Change direction */
@@ -2340,7 +2489,9 @@
 
 	*val = tmp;
 
-	sti();
+	dev->interrupt--;
+	if ( dev->interrupt == 0 )
+		sti();
 
 	return err;
 
@@ -2434,9 +2585,9 @@
 	 *	Returns:
 	 *		Nothing
 	 *	Parms:
-	 *		base_port	The base IO port of the adapter in
-	 *				question.
-	 *		dev		The address of the PHY to be written to.
+	 *		dev		The device structure for the device
+	 *				to write to.
+	 *		phy		The address of the PHY to be written to.
 	 *		reg		The register whose contents are to be
 	 *				written.
 	 *		val		The value to be written to the register.
@@ -2448,29 +2599,31 @@
 	 *
 	 **************************************************************/
 
-void TLan_MiiWriteReg(u16 base_port, u16 dev, u16 reg, u16 val)
+void TLan_MiiWriteReg( struct device *dev, u16 phy, u16 reg, u16 val )
 {
-	u16 sio;
+	u16	sio;
 	int	minten;
 
-	outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
-	sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+	outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
+	sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
 
-	cli();
+	if ( dev->interrupt == 0 )
+		cli();
+	dev->interrupt++;
 
-	TLan_MiiSync( base_port );
+	TLan_MiiSync( dev->base_addr );
 
 	minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio );
 	if ( minten )
 		TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio );
 
-	TLan_MiiSendData( base_port, 0x1, 2 );		/* Start ( 01b ) */
-	TLan_MiiSendData( base_port, 0x1, 2 );		/* Write ( 01b ) */
-	TLan_MiiSendData( base_port, dev, 5 );		/* Device #      */
-	TLan_MiiSendData( base_port, reg, 5 );		/* Register #    */
+	TLan_MiiSendData( dev->base_addr, 0x1, 2 );	/* Start ( 01b ) */
+	TLan_MiiSendData( dev->base_addr, 0x1, 2 );	/* Write ( 01b ) */
+	TLan_MiiSendData( dev->base_addr, phy, 5 );	/* Device #      */
+	TLan_MiiSendData( dev->base_addr, reg, 5 );	/* Register #    */
 
-	TLan_MiiSendData( base_port, 0x2, 2 );		/* Send ACK */
-	TLan_MiiSendData( base_port, val, 16 );		/* Send Data */
+	TLan_MiiSendData( dev->base_addr, 0x2, 2 );	/* Send ACK */
+	TLan_MiiSendData( dev->base_addr, val, 16 );	/* Send Data */
 
 	TLan_ClearBit( TLAN_NET_SIO_MCLK, sio );	/* Idle cycle */
 	TLan_SetBit( TLAN_NET_SIO_MCLK, sio );
@@ -2478,10 +2631,15 @@
 	if ( minten )
 		TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
 
-	sti();
+	dev->interrupt--;
+	if ( dev->interrupt == 0 )
+		sti();
 
 } /* TLan_MiiWriteReg */
 
+
+
+
 /*****************************************************************************
 ******************************************************************************
 
@@ -2654,7 +2812,7 @@
 	 *
 	 *	Returns:
 	 *		No error = 0, else, the stage at which the error
-	 *		occurred.
+	 *		occured.
 	 *	Parms:
 	 *		io_base		The IO port base address for the
 	 *				TLAN device with the EEPROM to
@@ -2670,26 +2828,30 @@
 	 *
 	 **************************************************************/
 
-int TLan_EeReadByte( u16 io_base, u8 ee_addr, u8 *data )
+int TLan_EeReadByte( struct device *dev, u8 ee_addr, u8 *data )
 {
 	int err;
 
-	cli();
+	if ( dev->interrupt == 0 )
+		cli();
+	dev->interrupt++;
 
-	TLan_EeSendStart( io_base );
-	err = TLan_EeSendByte( io_base, 0xA0, TLAN_EEPROM_ACK );
+	TLan_EeSendStart( dev->base_addr );
+	err = TLan_EeSendByte( dev->base_addr, 0xA0, TLAN_EEPROM_ACK );
 	if (err)
 		return 1;
-	err = TLan_EeSendByte( io_base, ee_addr, TLAN_EEPROM_ACK );
+	err = TLan_EeSendByte( dev->base_addr, ee_addr, TLAN_EEPROM_ACK );
 	if (err)
 		return 2;
-	TLan_EeSendStart( io_base );
-	err = TLan_EeSendByte( io_base, 0xA1, TLAN_EEPROM_ACK );
+	TLan_EeSendStart( dev->base_addr );
+	err = TLan_EeSendByte( dev->base_addr, 0xA1, TLAN_EEPROM_ACK );
 	if (err)
 		return 3;
-	TLan_EeReceiveByte( io_base, data, TLAN_EEPROM_STOP );
+	TLan_EeReceiveByte( dev->base_addr, data, TLAN_EEPROM_STOP );
 
-	sti();
+	dev->interrupt--;
+	if ( dev->interrupt == 0 )
+		sti();
 
 	return 0;
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov