Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
new file mode 100644
index 0000000..ccae6ba
--- /dev/null
+++ b/drivers/net/eth16i.c
@@ -0,0 +1,1509 @@
+/* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux
+   
+   Written 1994-1999 by Mika Kuoppala
+   
+   Copyright (C) 1994-1999 by Mika Kuoppala
+   Based on skeleton.c and heavily on at1700.c by Donald Becker
+
+   This software may be used and distributed according to the terms
+   of the GNU General Public License, incorporated herein by reference.
+
+   The author may be reached as miku@iki.fi
+
+   This driver supports following cards :
+	- ICL EtherTeam 16i
+	- ICL EtherTeam 32 EISA 
+	  (Uses true 32 bit transfers rather than 16i compability mode)
+
+   Example Module usage:
+        insmod eth16i.o io=0x2a0 mediatype=bnc
+
+	mediatype can be one of the following: bnc,tp,dix,auto,eprom
+
+	'auto' will try to autoprobe mediatype.
+	'eprom' will use whatever type defined in eprom.
+
+   I have benchmarked driver with PII/300Mhz as a ftp client
+   and 486/33Mhz as a ftp server. Top speed was 1128.37 kilobytes/sec.
+   
+   Sources:
+     - skeleton.c  a sample network driver core for linux,
+       written by Donald Becker <becker@scyld.com>
+     - at1700.c a driver for Allied Telesis AT1700, written 
+       by Donald Becker.
+     - e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i
+       written by Markku Viima
+     - The Fujitsu MB86965 databook.
+   
+   Author thanks following persons due to their valueble assistance:    
+        Markku Viima (ICL)
+	Ari Valve (ICL)      
+	Donald Becker
+	Kurt Huwig <kurt@huwig.de>
+
+   Revision history:
+
+   Version	Date		Description
+   
+   0.01         15.12-94        Initial version (card detection)
+   0.02         23.01-95        Interrupt is now hooked correctly
+   0.03         01.02-95        Rewrote initialization part
+   0.04         07.02-95        Base skeleton done...
+                                Made a few changes to signature checking
+                                to make it a bit reliable.
+                                - fixed bug in tx_buf mapping
+                                - fixed bug in initialization (DLC_EN
+                                  wasn't enabled when initialization
+                                  was done.)
+   0.05         08.02-95        If there were more than one packet to send,
+                                transmit was jammed due to invalid
+                                register write...now fixed
+   0.06         19.02-95        Rewrote interrupt handling        
+   0.07         13.04-95        Wrote EEPROM read routines
+                                Card configuration now set according to
+                                data read from EEPROM
+   0.08         23.06-95        Wrote part that tries to probe used interface
+                                port if AUTO is selected
+
+   0.09         01.09-95        Added module support
+   
+   0.10         04.09-95        Fixed receive packet allocation to work
+                                with kernels > 1.3.x
+      
+   0.20		20.09-95	Added support for EtherTeam32 EISA	
+
+   0.21         17.10-95        Removed the unnecessary extern 
+				init_etherdev() declaration. Some
+				other cleanups.
+   				
+   0.22		22.02-96	Receive buffer was not flushed
+				correctly when faulty packet was
+				received. Now fixed.
+
+   0.23		26.02-96	Made resetting the adapter	
+			 	more reliable.
+   
+   0.24		27.02-96	Rewrote faulty packet handling in eth16i_rx
+
+   0.25		22.05-96	kfree() was missing from cleanup_module.
+
+   0.26		11.06-96	Sometimes card was not found by 
+				check_signature(). Now made more reliable.
+   
+   0.27		23.06-96	Oops. 16 consecutive collisions halted 
+				adapter. Now will try to retransmit 
+				MAX_COL_16 times before finally giving up.
+   
+   0.28	        28.10-97	Added dev_id parameter (NULL) for free_irq
+
+   0.29         29.10-97        Multiple card support for module users
+
+   0.30         30.10-97        Fixed irq allocation bug.
+                                (request_irq moved from probe to open)
+
+   0.30a        21.08-98        Card detection made more relaxed. Driver
+                                had problems with some TCP/IP-PROM boots
+				to find the card. Suggested by 
+				Kurt Huwig <kurt@huwig.de>
+
+   0.31         28.08-98        Media interface port can now be selected
+                                with module parameters or kernel
+				boot parameters. 
+
+   0.32         31.08-98        IRQ was never freed if open/close 
+                                pair wasn't called. Now fixed.
+   
+   0.33         10.09-98        When eth16i_open() was called after
+                                eth16i_close() chip never recovered.
+				Now more shallow reset is made on
+				close.
+
+   0.34         29.06-99	Fixed one bad #ifdef.
+				Changed ioaddr -> io for consistency
+
+   0.35         01.07-99        transmit,-receive bytes were never
+                                updated in stats. 
+
+   Bugs:
+	In some cases the media interface autoprobing code doesn't find 
+	the correct interface type. In this case you can 
+	manually choose the interface type in DOS with E16IC.EXE which is 
+	configuration software for EtherTeam16i and EtherTeam32 cards.
+	This is also true for IRQ setting. You cannot use module
+	parameter to configure IRQ of the card (yet). 
+
+   To do:
+	- Real multicast support
+	- Rewrite the media interface autoprobing code. Its _horrible_ !
+	- Possibly merge all the MB86965 specific code to external
+	  module for use by eth16.c and Donald's at1700.c
+	- IRQ configuration with module parameter. I will do
+	  this when i will get enough info about setting
+	  irq without configuration utility.
+*/
+
+static char *version = 
+    "eth16i.c: v0.35 01-Jul-1999 Mika Kuoppala (miku@iki.fi)\n";
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>		  
+#include <linux/fcntl.h>		  
+#include <linux/interrupt.h>		  
+#include <linux/ioport.h>		  
+#include <linux/in.h>		  
+#include <linux/slab.h>		  
+#include <linux/string.h>		  
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>		  
+#include <asm/io.h>		  
+#include <asm/dma.h>
+
+
+
+/* Few macros */
+#define BIT(a)		       ( (1 << (a)) )  
+#define BITSET(ioaddr, bnum)   ((outb(((inb(ioaddr)) | (bnum)), ioaddr))) 
+#define BITCLR(ioaddr, bnum)   ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr)))
+
+/* This is the I/O address space for Etherteam 16i adapter. */
+#define ETH16I_IO_EXTENT       32
+
+/* Ticks before deciding that transmit has timed out */
+#define TX_TIMEOUT             (400*HZ/1000)
+
+/* Maximum loop count when receiving packets */
+#define MAX_RX_LOOP            20
+
+/* Some interrupt masks */
+#define ETH16I_INTR_ON	       0xef8a       /* Higher is receive mask */
+#define ETH16I_INTR_OFF	       0x0000
+	 
+/* Buffers header status byte meanings */
+#define PKT_GOOD               BIT(5)
+#define PKT_GOOD_RMT           BIT(4)
+#define PKT_SHORT              BIT(3)
+#define PKT_ALIGN_ERR          BIT(2)
+#define PKT_CRC_ERR            BIT(1)
+#define PKT_RX_BUF_OVERFLOW    BIT(0)
+
+/* Transmit status register (DLCR0) */
+#define TX_STATUS_REG          0
+#define TX_DONE                BIT(7)
+#define NET_BUSY               BIT(6)
+#define TX_PKT_RCD             BIT(5)
+#define CR_LOST                BIT(4)
+#define TX_JABBER_ERR	       BIT(3)
+#define COLLISION              BIT(2)
+#define COLLISIONS_16          BIT(1)
+
+/* Receive status register (DLCR1) */
+#define RX_STATUS_REG          1
+#define RX_PKT                 BIT(7)  /* Packet received */
+#define BUS_RD_ERR             BIT(6)
+#define SHORT_PKT_ERR          BIT(3)
+#define ALIGN_ERR              BIT(2)
+#define CRC_ERR                BIT(1)
+#define RX_BUF_OVERFLOW        BIT(0)
+              
+/* Transmit Interrupt Enable Register (DLCR2) */
+#define TX_INTR_REG            2
+#define TX_INTR_DONE           BIT(7)
+#define TX_INTR_COL            BIT(2)
+#define TX_INTR_16_COL         BIT(1)
+
+/* Receive Interrupt Enable Register (DLCR3) */
+#define RX_INTR_REG            3
+#define RX_INTR_RECEIVE        BIT(7)
+#define RX_INTR_SHORT_PKT      BIT(3)
+#define RX_INTR_CRC_ERR        BIT(1)
+#define RX_INTR_BUF_OVERFLOW   BIT(0)
+
+/* Transmit Mode Register (DLCR4) */
+#define TRANSMIT_MODE_REG      4
+#define LOOPBACK_CONTROL       BIT(1)
+#define CONTROL_OUTPUT         BIT(2)
+
+/* Receive Mode Register (DLCR5) */
+#define RECEIVE_MODE_REG       5
+#define RX_BUFFER_EMPTY        BIT(6)
+#define ACCEPT_BAD_PACKETS     BIT(5)
+#define RECEIVE_SHORT_ADDR     BIT(4)
+#define ACCEPT_SHORT_PACKETS   BIT(3)
+#define REMOTE_RESET           BIT(2)
+
+#define ADDRESS_FILTER_MODE    BIT(1) | BIT(0)
+#define REJECT_ALL             0
+#define ACCEPT_ALL             3
+#define MODE_1                 1            /* NODE ID, BC, MC, 2-24th bit */
+#define MODE_2                 2            /* NODE ID, BC, MC, Hash Table */
+
+/* Configuration Register 0 (DLCR6) */
+#define CONFIG_REG_0           6
+#define DLC_EN                 BIT(7)
+#define SRAM_CYCLE_TIME_100NS  BIT(6)
+#define SYSTEM_BUS_WIDTH_8     BIT(5)       /* 1 = 8bit, 0 = 16bit */
+#define BUFFER_WIDTH_8         BIT(4)       /* 1 = 8bit, 0 = 16bit */
+#define TBS1                   BIT(3)       
+#define TBS0                   BIT(2)
+#define SRAM_BS1               BIT(1)       /* 00=8kb,  01=16kb  */
+#define SRAM_BS0               BIT(0)       /* 10=32kb, 11=64kb  */
+
+#ifndef ETH16I_TX_BUF_SIZE                   /* 0 = 2kb, 1 = 4kb  */ 
+#define ETH16I_TX_BUF_SIZE     3             /* 2 = 8kb, 3 = 16kb */
+#endif                                      
+#define TX_BUF_1x2048          0
+#define TX_BUF_2x2048          1
+#define TX_BUF_2x4098          2
+#define TX_BUF_2x8192          3
+
+/* Configuration Register 1 (DLCR7) */
+#define CONFIG_REG_1           7
+#define POWERUP                BIT(5)
+
+/* Transmit start register */
+#define TRANSMIT_START_REG     10
+#define TRANSMIT_START_RB      2
+#define TX_START               BIT(7)       /* Rest of register bit indicate*/
+                                            /* number of packets in tx buffer*/
+/* Node ID registers (DLCR8-13) */
+#define NODE_ID_0              8
+#define NODE_ID_RB             0
+
+/* Hash Table registers (HT8-15) */
+#define HASH_TABLE_0           8
+#define HASH_TABLE_RB          1
+
+/* Buffer memory ports */
+#define BUFFER_MEM_PORT_LB     8
+#define DATAPORT               BUFFER_MEM_PORT_LB
+#define BUFFER_MEM_PORT_HB     9
+
+/* 16 Collision control register (BMPR11) */
+#define COL_16_REG             11
+#define HALT_ON_16             0x00
+#define RETRANS_AND_HALT_ON_16 0x02
+
+/* Maximum number of attempts to send after 16 concecutive collisions */
+#define MAX_COL_16	       10
+
+/* DMA Burst and Transceiver Mode Register (BMPR13) */
+#define TRANSCEIVER_MODE_REG   13
+#define TRANSCEIVER_MODE_RB    2         
+#define IO_BASE_UNLOCK	       BIT(7)
+#define LOWER_SQUELCH_TRESH    BIT(6)
+#define LINK_TEST_DISABLE      BIT(5)
+#define AUI_SELECT             BIT(4)
+#define DIS_AUTO_PORT_SEL      BIT(3)
+
+/* Filter Self Receive Register (BMPR14)  */
+#define FILTER_SELF_RX_REG     14
+#define SKIP_RX_PACKET         BIT(2)
+#define FILTER_SELF_RECEIVE    BIT(0)
+
+/* EEPROM Control Register (BMPR 16) */
+#define EEPROM_CTRL_REG        16
+
+/* EEPROM Data Register (BMPR 17) */
+#define EEPROM_DATA_REG        17
+
+/* NMC93CSx6 EEPROM Control Bits */
+#define CS_0                   0x00
+#define CS_1                   0x20
+#define SK_0                   0x00
+#define SK_1                   0x40
+#define DI_0                   0x00
+#define DI_1                   0x80
+
+/* NMC93CSx6 EEPROM Instructions */
+#define EEPROM_READ            0x80
+
+/* NMC93CSx6 EEPROM Addresses */
+#define E_NODEID_0             0x02
+#define E_NODEID_1             0x03
+#define E_NODEID_2             0x04
+#define E_PORT_SELECT          0x14
+  #define E_PORT_BNC           0x00
+  #define E_PORT_DIX           0x01
+  #define E_PORT_TP            0x02
+  #define E_PORT_AUTO          0x03
+  #define E_PORT_FROM_EPROM    0x04
+#define E_PRODUCT_CFG          0x30
+ 
+
+/* Macro to slow down io between EEPROM clock transitions */
+#define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { inb(0x80); }}while(0)
+
+/* Jumperless Configuration Register (BMPR19) */
+#define JUMPERLESS_CONFIG      19
+
+/* ID ROM registers, writing to them also resets some parts of chip */
+#define ID_ROM_0               24
+#define ID_ROM_7               31
+#define RESET                  ID_ROM_0
+
+/* This is the I/O address list to be probed when seeking the card */
+static unsigned int eth16i_portlist[] __initdata = {
+	0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 
+};
+
+static unsigned int eth32i_portlist[] __initdata = { 
+	0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
+	0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 
+};
+
+/* This is the Interrupt lookup table for Eth16i card */
+static unsigned int eth16i_irqmap[] __initdata = { 9, 10, 5, 15, 0 };
+#define NUM_OF_ISA_IRQS    4
+
+/* This is the Interrupt lookup table for Eth32i card */
+static unsigned int eth32i_irqmap[] __initdata = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };  
+#define EISA_IRQ_REG	0xc89
+#define NUM_OF_EISA_IRQS   8
+
+static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 };
+
+/* Use 0 for production, 1 for verification, >2 for debug */
+#ifndef ETH16I_DEBUG
+#define ETH16I_DEBUG 0
+#endif
+static unsigned int eth16i_debug = ETH16I_DEBUG;
+
+/* Information for each board */
+
+struct eth16i_local {
+	struct net_device_stats stats;
+	unsigned char     tx_started;
+	unsigned char     tx_buf_busy;
+	unsigned short    tx_queue;  /* Number of packets in transmit buffer */
+	unsigned short    tx_queue_len;         
+	unsigned int      tx_buf_size;
+	unsigned long     open_time;
+	unsigned long     tx_buffered_packets;
+	unsigned long     tx_buffered_bytes;
+	unsigned long     col_16;
+	spinlock_t	  lock;
+};
+
+/* Function prototypes */
+
+static int     eth16i_probe1(struct net_device *dev, int ioaddr);
+static int     eth16i_check_signature(int ioaddr);
+static int     eth16i_probe_port(int ioaddr);
+static void    eth16i_set_port(int ioaddr, int porttype);
+static int     eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l);
+static int     eth16i_receive_probe_packet(int ioaddr);
+static int     eth16i_get_irq(int ioaddr);
+static int     eth16i_read_eeprom(int ioaddr, int offset);
+static int     eth16i_read_eeprom_word(int ioaddr);
+static void    eth16i_eeprom_cmd(int ioaddr, unsigned char command);
+static int     eth16i_open(struct net_device *dev);
+static int     eth16i_close(struct net_device *dev);
+static int     eth16i_tx(struct sk_buff *skb, struct net_device *dev);
+static void    eth16i_rx(struct net_device *dev);
+static void    eth16i_timeout(struct net_device *dev);
+static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void    eth16i_reset(struct net_device *dev);
+static void    eth16i_timeout(struct net_device *dev);
+static void    eth16i_skip_packet(struct net_device *dev);
+static void    eth16i_multicast(struct net_device *dev); 
+static void    eth16i_select_regbank(unsigned char regbank, int ioaddr);
+static void    eth16i_initialize(struct net_device *dev, int boot);
+
+#if 0
+static int     eth16i_set_irq(struct net_device *dev);
+#endif
+
+#ifdef MODULE
+static ushort  eth16i_parse_mediatype(const char* s);
+#endif
+
+static struct net_device_stats *eth16i_get_stats(struct net_device *dev);
+
+static char cardname[] __initdata = "ICL EtherTeam 16i/32";
+
+static int __init do_eth16i_probe(struct net_device *dev)
+{
+	int i;
+	int ioaddr;
+	int base_addr = dev->base_addr;
+    
+	SET_MODULE_OWNER(dev);
+
+	if(eth16i_debug > 4) 
+		printk(KERN_DEBUG "Probing started for %s\n", cardname);
+
+	if(base_addr > 0x1ff)           /* Check only single location */
+		return eth16i_probe1(dev, base_addr);
+	else if(base_addr != 0)         /* Don't probe at all */
+		return -ENXIO;
+
+	/* Seek card from the ISA io address space */
+	for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++)
+		if(eth16i_probe1(dev, ioaddr) == 0)
+			return 0;
+
+	/* Seek card from the EISA io address space */
+	for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++)
+		if(eth16i_probe1(dev, ioaddr) == 0)
+			return 0;
+
+	return -ENODEV;
+}
+
+#ifndef MODULE
+struct net_device * __init eth16i_probe(int unit)
+{
+	struct net_device *dev = alloc_etherdev(sizeof(struct eth16i_local));
+	int err;
+
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
+
+	sprintf(dev->name, "eth%d", unit);
+	netdev_boot_setup_check(dev);
+
+	err = do_eth16i_probe(dev);
+	if (err)
+		goto out;
+	err = register_netdev(dev);
+	if (err)
+		goto out1;
+	return dev;
+out1:
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, ETH16I_IO_EXTENT);
+out:
+	free_netdev(dev);
+	return ERR_PTR(err);
+}
+#endif
+
+static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
+{
+	struct eth16i_local *lp = netdev_priv(dev);
+	static unsigned version_printed;
+	int retval;
+
+	/* Let's grab the region */
+	if (!request_region(ioaddr, ETH16I_IO_EXTENT, cardname))
+		return -EBUSY;
+
+	/*
+	  The MB86985 chip has on register which holds information in which 
+	  io address the chip lies. First read this register and compare
+	  it to our current io address and if match then this could
+	  be our chip.
+	  */
+
+	if(ioaddr < 0x1000) {
+		if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)] 
+		   != ioaddr) {
+			retval = -ENODEV;
+			goto out;
+		}
+	}
+
+	/* Now we will go a bit deeper and try to find the chip's signature */
+
+	if(eth16i_check_signature(ioaddr) != 0) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	/* 
+	   Now it seems that we have found a ethernet chip in this particular
+	   ioaddr. The MB86985 chip has this feature, that when you read a 
+	   certain register it will increase it's io base address to next
+	   configurable slot. Now when we have found the chip, first thing is
+	   to make sure that the chip's ioaddr will hold still here.
+	   */
+
+	eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
+	outb(0x00, ioaddr + TRANSCEIVER_MODE_REG);
+
+	outb(0x00, ioaddr + RESET);             /* Reset some parts of chip */
+	BITSET(ioaddr + CONFIG_REG_0, BIT(7));  /* Disable the data link */
+
+	if( (eth16i_debug & version_printed++) == 0)
+		printk(KERN_INFO "%s", version);
+
+	dev->base_addr = ioaddr;
+	dev->irq = eth16i_get_irq(ioaddr);
+
+	/* Try to obtain interrupt vector */
+
+	if ((retval = request_irq(dev->irq, (void *)&eth16i_interrupt, 0, cardname, dev))) {
+		printk(KERN_WARNING "%s at %#3x, but is unusable due to conflicting IRQ %d.\n", 
+		       cardname, ioaddr, dev->irq);
+		goto out;
+	}
+
+	printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ",
+	       dev->name, cardname, ioaddr, dev->irq);
+
+
+	/* Now we will have to lock the chip's io address */
+	eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
+	outb(0x38, ioaddr + TRANSCEIVER_MODE_REG); 
+
+	eth16i_initialize(dev, 1); /* Initialize rest of the chip's registers */
+
+	/* Now let's same some energy by shutting down the chip ;) */
+	BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
+
+	/* Initialize the device structure */
+	memset(lp, 0, sizeof(struct eth16i_local));
+	dev->open               = eth16i_open;
+	dev->stop               = eth16i_close;
+	dev->hard_start_xmit    = eth16i_tx;
+	dev->get_stats          = eth16i_get_stats;
+	dev->set_multicast_list = eth16i_multicast;
+	dev->tx_timeout 	= eth16i_timeout;
+	dev->watchdog_timeo	= TX_TIMEOUT;
+	spin_lock_init(&lp->lock);
+	return 0;
+out:
+	release_region(ioaddr, ETH16I_IO_EXTENT);
+	return retval;
+}
+
+
+static void eth16i_initialize(struct net_device *dev, int boot)
+{
+	int ioaddr = dev->base_addr;
+	int i, node_w = 0;
+	unsigned char node_byte = 0;
+
+	/* Setup station address */
+	eth16i_select_regbank(NODE_ID_RB, ioaddr);
+	for(i = 0 ; i < 3 ; i++) {
+		unsigned short node_val = eth16i_read_eeprom(ioaddr, E_NODEID_0 + i);
+		((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
+	}
+
+	for(i = 0; i < 6; i++) { 
+		outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
+		if(boot) {
+			printk("%02x", inb(ioaddr + NODE_ID_0 + i));
+			if(i != 5)
+				printk(":");
+		}
+	}
+
+	/* Now we will set multicast addresses to accept none */
+	eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
+	for(i = 0; i < 8; i++) 
+		outb(0x00, ioaddr + HASH_TABLE_0 + i);
+
+	/*
+	  Now let's disable the transmitter and receiver, set the buffer ram 
+	  cycle time, bus width and buffer data path width. Also we shall
+	  set transmit buffer size and total buffer size.
+	  */
+
+	eth16i_select_regbank(2, ioaddr);
+
+	node_byte = 0;
+	node_w = eth16i_read_eeprom(ioaddr, E_PRODUCT_CFG);
+
+	if( (node_w & 0xFF00) == 0x0800)
+		node_byte |= BUFFER_WIDTH_8;
+
+	node_byte |= SRAM_BS1;
+
+	if( (node_w & 0x00FF) == 64)
+		node_byte |= SRAM_BS0;
+
+	node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2);
+
+	outb(node_byte, ioaddr + CONFIG_REG_0);
+
+	/* We shall halt the transmitting, if 16 collisions are detected */
+	outb(HALT_ON_16, ioaddr + COL_16_REG);
+
+#ifdef MODULE
+	/* if_port already set by init_module() */
+#else
+	dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ? 
+		dev->mem_start : E_PORT_FROM_EPROM;
+#endif
+
+	/* Set interface port type */
+	if(boot) {
+		char *porttype[] = {"BNC", "DIX", "TP", "AUTO", "FROM_EPROM" };
+
+		switch(dev->if_port)
+		{
+
+		case E_PORT_FROM_EPROM:
+			dev->if_port = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
+			break;
+
+		case E_PORT_AUTO:
+			dev->if_port = eth16i_probe_port(ioaddr);
+			break;
+			
+		case E_PORT_BNC:
+		case E_PORT_TP:
+		case E_PORT_DIX:
+			break;
+		}
+
+		printk(" %s interface.\n", porttype[dev->if_port]);
+
+		eth16i_set_port(ioaddr, dev->if_port);
+	}
+
+	/* Set Receive Mode to normal operation */
+	outb(MODE_2, ioaddr + RECEIVE_MODE_REG);
+}
+
+static int eth16i_probe_port(int ioaddr)
+{
+	int i;
+	int retcode;
+	unsigned char dummy_packet[64];
+
+	/* Powerup the chip */
+	outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
+
+	BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+
+	eth16i_select_regbank(NODE_ID_RB, ioaddr);
+
+	for(i = 0; i < 6; i++) {
+		dummy_packet[i] = inb(ioaddr + NODE_ID_0 + i);
+		dummy_packet[i+6] = inb(ioaddr + NODE_ID_0 + i);
+	}
+
+	dummy_packet[12] = 0x00;
+	dummy_packet[13] = 0x04;
+	memset(dummy_packet + 14, 0, sizeof(dummy_packet) - 14);
+
+	eth16i_select_regbank(2, ioaddr);
+
+	for(i = 0; i < 3; i++) {
+		BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+		BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+		eth16i_set_port(ioaddr, i);
+
+		if(eth16i_debug > 1)
+			printk(KERN_DEBUG "Set port number %d\n", i);
+
+		retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64);
+		if(retcode == 0) {
+			retcode = eth16i_receive_probe_packet(ioaddr);
+			if(retcode != -1) {
+				if(eth16i_debug > 1)
+					printk(KERN_DEBUG "Eth16i interface port found at %d\n", i);
+				return i;
+			}
+		}
+		else {
+			if(eth16i_debug > 1)
+				printk(KERN_DEBUG "TRANSMIT_DONE timeout when probing interface port\n");
+		}
+	}
+
+	if( eth16i_debug > 1)
+		printk(KERN_DEBUG "Using default port\n");
+
+	return E_PORT_BNC;
+}
+
+static void eth16i_set_port(int ioaddr, int porttype)
+{ 
+	unsigned short temp = 0;
+
+	eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
+	outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG);
+
+	temp |= DIS_AUTO_PORT_SEL;
+
+	switch(porttype) {
+
+	case E_PORT_BNC :
+		temp |= AUI_SELECT;
+		break;
+
+	case E_PORT_TP :
+		break;
+
+	case E_PORT_DIX :
+		temp |= AUI_SELECT;
+		BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
+		break;
+	}  
+
+	outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
+
+	if(eth16i_debug > 1) {
+		printk(KERN_DEBUG "TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
+		printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n", 
+		       inb(ioaddr+TRANSCEIVER_MODE_REG));
+	}
+}
+
+static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l)
+{
+	int starttime;
+
+	outb(0xff, ioaddr + TX_STATUS_REG);
+
+	outw(l, ioaddr + DATAPORT);
+	outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);  
+
+	starttime = jiffies;
+	outb(TX_START | 1, ioaddr + TRANSMIT_START_REG); 
+
+	while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) {
+		if( (jiffies - starttime) > TX_TIMEOUT) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int eth16i_receive_probe_packet(int ioaddr)
+{
+	int starttime;
+
+	starttime = jiffies;
+
+	while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) {
+		if( (jiffies - starttime) > TX_TIMEOUT) {
+
+			if(eth16i_debug > 1)
+				printk(KERN_DEBUG "Timeout occurred waiting transmit packet received\n");
+			starttime = jiffies;
+			while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) {
+				if( (jiffies - starttime) > TX_TIMEOUT) {
+					if(eth16i_debug > 1)
+						printk(KERN_DEBUG "Timeout occurred waiting receive packet\n");
+					return -1;
+				}
+			}
+
+			if(eth16i_debug > 1)
+				printk(KERN_DEBUG "RECEIVE_PACKET\n");
+			return(0); /* Found receive packet */
+		}
+	}
+
+	if(eth16i_debug > 1) {
+		printk(KERN_DEBUG "TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
+		printk(KERN_DEBUG "RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
+	}
+
+	return(0); /* Return success */
+}
+
+#if 0
+static int eth16i_set_irq(struct net_device* dev)
+{
+	const int ioaddr = dev->base_addr;
+	const int irq = dev->irq;
+	int i = 0;
+
+	if(ioaddr < 0x1000) {		
+		while(eth16i_irqmap[i] && eth16i_irqmap[i] != irq)
+			i++;
+	
+		if(i < NUM_OF_ISA_IRQS) {
+			u8 cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
+			cbyte = (cbyte & 0x3F) | (i << 6);
+			outb(cbyte, ioaddr + JUMPERLESS_CONFIG);
+			return 0;
+		}
+	}
+	else {
+		printk(KERN_NOTICE "%s: EISA Interrupt cannot be set. Use EISA Configuration utility.\n", dev->name);
+	}
+	
+	return -1;
+
+}
+#endif
+
+static int __init eth16i_get_irq(int ioaddr)
+{
+	unsigned char cbyte;
+
+	if( ioaddr < 0x1000) {
+		cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
+		return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] );
+	} else {  /* Oh..the card is EISA so method getting IRQ different */
+		unsigned short index = 0;
+		cbyte = inb(ioaddr + EISA_IRQ_REG);
+		while( (cbyte & 0x01) == 0) {
+			cbyte = cbyte >> 1;
+			index++;
+		}
+		return( eth32i_irqmap[ index ] );
+	}
+}
+
+static int __init eth16i_check_signature(int ioaddr)
+{
+	int i;
+	unsigned char creg[4] = { 0 };
+
+	for(i = 0; i < 4 ; i++) {
+
+		creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
+
+		if(eth16i_debug > 1)
+			printk("eth16i: read signature byte %x at %x\n", 
+			       creg[i],
+			       ioaddr + TRANSMIT_MODE_REG + i);
+	}
+
+	creg[0] &= 0x0F;      /* Mask collision cnr */
+	creg[2] &= 0x7F;      /* Mask DCLEN bit */
+
+#if 0
+	/* 
+	   This was removed because the card was sometimes left to state
+	   from which it couldn't be find anymore. If there is need
+	   to more strict check still this have to be fixed.
+	   */
+	if( ! ((creg[0] == 0x06) && (creg[1] == 0x41)) ) {
+		if(creg[1] != 0x42)
+			return -1;
+	}
+#endif
+
+	if( !((creg[2] == 0x36) && (creg[3] == 0xE0)) ) {
+		creg[2] &= 0x40;
+		creg[3] &= 0x03;
+		
+		if( !((creg[2] == 0x40) && (creg[3] == 0x00)) )
+			return -1;
+	}
+	
+	if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
+		return -1;
+	
+	if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
+		return -1;
+
+	return 0;
+}
+
+static int eth16i_read_eeprom(int ioaddr, int offset)
+{
+	int data = 0;
+
+	eth16i_eeprom_cmd(ioaddr, EEPROM_READ | offset);
+	outb(CS_1, ioaddr + EEPROM_CTRL_REG);
+	data = eth16i_read_eeprom_word(ioaddr);
+	outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
+
+	return(data);  
+}
+
+static int eth16i_read_eeprom_word(int ioaddr)
+{
+	int i;
+	int data = 0;
+     
+	for(i = 16; i > 0; i--) {
+		outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
+		eeprom_slow_io();
+		outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
+		eeprom_slow_io();
+		data = (data << 1) | 
+			((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
+		
+		eeprom_slow_io();
+	}
+
+	return(data);
+}
+
+static void eth16i_eeprom_cmd(int ioaddr, unsigned char command)
+{
+	int i;
+
+	outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
+	outb(DI_0, ioaddr + EEPROM_DATA_REG);
+	outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
+	outb(DI_1, ioaddr + EEPROM_DATA_REG);
+	outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
+
+	for(i = 7; i >= 0; i--) {
+		short cmd = ( (command & (1 << i)) ? DI_1 : DI_0 );
+		outb(cmd, ioaddr + EEPROM_DATA_REG);
+		outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
+		eeprom_slow_io();
+		outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
+		eeprom_slow_io();
+	} 
+}
+
+static int eth16i_open(struct net_device *dev)
+{
+	struct eth16i_local *lp = netdev_priv(dev);
+	int ioaddr = dev->base_addr;
+	
+	/* Powerup the chip */
+	outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
+
+	/* Initialize the chip */
+	eth16i_initialize(dev, 0);  
+
+	/* Set the transmit buffer size */
+	lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
+
+	if(eth16i_debug > 0)
+		printk(KERN_DEBUG "%s: transmit buffer size %d\n", 
+		       dev->name, lp->tx_buf_size);
+
+	/* Now enable Transmitter and Receiver sections */
+	BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+
+	/* Now switch to register bank 2, for run time operation */
+	eth16i_select_regbank(2, ioaddr);
+
+	lp->open_time = jiffies;
+	lp->tx_started = 0;
+	lp->tx_queue = 0;
+	lp->tx_queue_len = 0;
+
+	/* Turn on interrupts*/
+	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);  
+
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int eth16i_close(struct net_device *dev)
+{
+	struct eth16i_local *lp = netdev_priv(dev);
+	int ioaddr = dev->base_addr;
+
+	eth16i_reset(dev);
+
+	/* Turn off interrupts*/
+	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);  
+
+	netif_stop_queue(dev);
+	
+	lp->open_time = 0;
+
+	/* Disable transmit and receive */
+	BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+
+	/* Reset the chip */
+	/* outb(0xff, ioaddr + RESET); */
+	/* outw(0xffff, ioaddr + TX_STATUS_REG);    */
+	
+	outb(0x00, ioaddr + CONFIG_REG_1);
+
+	return 0;
+}
+
+static void eth16i_timeout(struct net_device *dev)
+{
+	struct eth16i_local *lp = netdev_priv(dev);
+	int ioaddr = dev->base_addr;
+	/* 
+	   If we get here, some higher level has decided that 
+	   we are broken. There should really be a "kick me" 
+	   function call instead. 
+	   */
+
+	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+	printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n", 
+	       dev->name,
+	inw(ioaddr + TX_STATUS_REG),  (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ? 
+		       "IRQ conflict" : "network cable problem");
+
+	dev->trans_start = jiffies;
+
+	/* Let's dump all registers */
+	if(eth16i_debug > 0) { 
+		printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+		       dev->name, inb(ioaddr + 0), 
+		       inb(ioaddr + 1), inb(ioaddr + 2), 
+		       inb(ioaddr + 3), inb(ioaddr + 4), 
+		       inb(ioaddr + 5),
+		       inb(ioaddr + 6), inb(ioaddr + 7));
+
+		printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
+		       dev->name, inb(ioaddr + TRANSMIT_START_REG),
+		       inb(ioaddr + COL_16_REG));
+			printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue);
+		printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
+		printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
+	}
+	lp->stats.tx_errors++;
+	eth16i_reset(dev);
+	dev->trans_start = jiffies;
+	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+	netif_wake_queue(dev);
+}
+
+static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct eth16i_local *lp = netdev_priv(dev);
+	int ioaddr = dev->base_addr;
+	int status = 0;
+	ushort length = skb->len;
+	unsigned char *buf;
+	unsigned long flags;
+
+	if (length < ETH_ZLEN) {
+		skb = skb_padto(skb, ETH_ZLEN);
+		if (skb == NULL)
+			return 0;
+		length = ETH_ZLEN;
+	}
+	buf = skb->data;
+
+	netif_stop_queue(dev);
+		
+	/* Turn off TX interrupts */
+	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+	
+	/* We would be better doing the disable_irq tricks the 3c509 does,
+	   that would make this suck a lot less */
+	   
+	spin_lock_irqsave(&lp->lock, flags);
+
+	if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
+		if(eth16i_debug > 0) 
+			printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);  
+	} 
+	else {
+		outw(length, ioaddr + DATAPORT);
+
+		if( ioaddr < 0x1000 ) 
+			outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+		else {
+			unsigned char frag = length % 4;
+			outsl(ioaddr + DATAPORT, buf, length >> 2);
+			if( frag != 0 ) {
+				outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
+				if( frag == 3 ) 
+					outsw(ioaddr + DATAPORT, 
+					      (buf + (length & 0xFFFC) + 2), 1);
+			}
+		}
+		lp->tx_buffered_packets++;
+		lp->tx_buffered_bytes = length;
+		lp->tx_queue++;
+		lp->tx_queue_len += length + 2;
+	}
+	lp->tx_buf_busy = 0;
+
+	if(lp->tx_started == 0) {
+		/* If the transmitter is idle..always trigger a transmit */
+		outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
+		lp->tx_queue = 0;
+		lp->tx_queue_len = 0;
+		dev->trans_start = jiffies;
+		lp->tx_started = 1;
+		netif_wake_queue(dev);
+	}
+	else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
+		/* There is still more room for one more packet in tx buffer */
+		netif_wake_queue(dev);
+	}
+		
+	spin_unlock_irqrestore(&lp->lock, flags);
+	
+	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+	/* Turn TX interrupts back on */
+	/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
+	status = 0;
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+static void eth16i_rx(struct net_device *dev)
+{
+	struct eth16i_local *lp = netdev_priv(dev);
+	int ioaddr = dev->base_addr;
+	int boguscount = MAX_RX_LOOP;
+
+	/* Loop until all packets have been read */
+	while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) {
+
+		/* Read status byte from receive buffer */ 
+		ushort status = inw(ioaddr + DATAPORT);
+
+		/* Get the size of the packet from receive buffer */
+		ushort pkt_len = inw(ioaddr + DATAPORT);
+
+		if(eth16i_debug > 4)
+			printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n", 
+			       dev->name, 
+			       inb(ioaddr + RECEIVE_MODE_REG), status);
+		
+		if( !(status & PKT_GOOD) ) {
+			lp->stats.rx_errors++;
+
+			if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {
+				lp->stats.rx_length_errors++;
+				eth16i_reset(dev);
+				return;		
+			}
+			else { 
+				eth16i_skip_packet(dev);
+				lp->stats.rx_dropped++;
+			}	
+		}
+		else {   /* Ok so now we should have a good packet */
+			struct sk_buff *skb;
+
+			skb = dev_alloc_skb(pkt_len + 3);
+			if( skb == NULL ) {
+				printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n", 
+				       dev->name, pkt_len);
+				eth16i_skip_packet(dev);
+				lp->stats.rx_dropped++;
+				break;
+			}
+
+			skb->dev = dev;
+			skb_reserve(skb,2);
+			
+			/* 
+			   Now let's get the packet out of buffer.
+			   size is (pkt_len + 1) >> 1, cause we are now reading words
+			   and it have to be even aligned.
+			   */ 
+			
+			if(ioaddr < 0x1000) 
+				insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), 
+				     (pkt_len + 1) >> 1);
+			else {	
+				unsigned char *buf = skb_put(skb, pkt_len);
+				unsigned char frag = pkt_len % 4;
+
+				insl(ioaddr + DATAPORT, buf, pkt_len >> 2);
+
+				if(frag != 0) {
+					unsigned short rest[2];
+					rest[0] = inw( ioaddr + DATAPORT );
+					if(frag == 3)
+						rest[1] = inw( ioaddr + DATAPORT );
+
+					memcpy(buf + (pkt_len & 0xfffc), (char *)rest, frag);
+				}
+			}
+
+			skb->protocol=eth_type_trans(skb, dev);
+
+			if( eth16i_debug > 5 ) {
+				int i;
+				printk(KERN_DEBUG "%s: Received packet of length %d.\n", 
+				       dev->name, pkt_len);
+				for(i = 0; i < 14; i++) 
+					printk(KERN_DEBUG " %02x", skb->data[i]);
+				printk(KERN_DEBUG ".\n");
+			}
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			lp->stats.rx_packets++;
+			lp->stats.rx_bytes += pkt_len;
+
+		} /* else */
+
+		if(--boguscount <= 0)
+			break;
+
+	} /* while */
+}
+
+static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct eth16i_local *lp;
+	int ioaddr = 0, status;
+	int handled = 0;
+
+	ioaddr = dev->base_addr;
+	lp = netdev_priv(dev);
+
+	/* Turn off all interrupts from adapter */
+	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+
+	/* eth16i_tx won't be called */
+	spin_lock(&lp->lock);
+
+	status = inw(ioaddr + TX_STATUS_REG);      /* Get the status */
+	outw(status, ioaddr + TX_STATUS_REG);      /* Clear status bits */
+
+	if (status)
+		handled = 1;
+
+	if(eth16i_debug > 3)
+		printk(KERN_DEBUG "%s: Interrupt with status %04x.\n", dev->name, status);
+
+	if( status & 0x7f00 ) {
+
+		lp->stats.rx_errors++;
+
+		if(status & (BUS_RD_ERR << 8) ) 
+			printk(KERN_WARNING "%s: Bus read error.\n",dev->name);
+		if(status & (SHORT_PKT_ERR << 8) )   lp->stats.rx_length_errors++;
+		if(status & (ALIGN_ERR << 8) )       lp->stats.rx_frame_errors++;
+		if(status & (CRC_ERR << 8) )	    lp->stats.rx_crc_errors++;
+		if(status & (RX_BUF_OVERFLOW << 8) ) lp->stats.rx_over_errors++;
+	}
+	if( status & 0x001a) {
+
+		lp->stats.tx_errors++;
+
+		if(status & CR_LOST) lp->stats.tx_carrier_errors++;
+		if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++;
+
+#if 0	       
+		if(status & COLLISION) {
+			lp->stats.collisions += 
+				((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);
+		}
+#endif
+		if(status & COLLISIONS_16) {
+			if(lp->col_16 < MAX_COL_16) { 
+				lp->col_16++;
+				lp->stats.collisions++;
+				/* Resume transmitting, skip failed packet */
+				outb(0x02, ioaddr + COL_16_REG);
+			}
+			else {
+				printk(KERN_WARNING "%s: bailing out due to many consecutive 16-in-a-row collisions. Network cable problem?\n", dev->name);
+			}
+		}
+	}
+
+	if( status & 0x00ff ) {          /* Let's check the transmit status reg */
+
+		if(status & TX_DONE) {         /* The transmit has been done */
+			lp->stats.tx_packets = lp->tx_buffered_packets;
+			lp->stats.tx_bytes += lp->tx_buffered_bytes;
+			lp->col_16 = 0;		   
+
+			if(lp->tx_queue) {           /* Is there still packets ? */
+				/* There was packet(s) so start transmitting and write also
+				   how many packets there is to be sended */
+				outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
+				lp->tx_queue = 0;
+				lp->tx_queue_len = 0;
+				lp->tx_started = 1;
+			}
+			else {
+				lp->tx_started = 0;
+			}
+			netif_wake_queue(dev);
+		}
+	}
+
+	if( ( status & 0x8000 ) || 
+	    ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
+		eth16i_rx(dev);  /* We have packet in receive buffer */
+	}  
+	
+	/* Turn interrupts back on */
+	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+	
+	if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
+		/* There is still more room for one more packet in tx buffer */
+		netif_wake_queue(dev);
+	}
+	
+	spin_unlock(&lp->lock);
+	
+	return IRQ_RETVAL(handled);
+}
+
+static void eth16i_skip_packet(struct net_device *dev)
+{	 
+	int ioaddr = dev->base_addr;
+
+	inw(ioaddr + DATAPORT);
+	inw(ioaddr + DATAPORT);
+	inw(ioaddr + DATAPORT);
+
+	outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
+	while( inb( ioaddr + FILTER_SELF_RX_REG ) != 0);
+}
+
+static void eth16i_reset(struct net_device *dev)
+{
+	struct eth16i_local *lp = netdev_priv(dev);
+	int ioaddr = dev->base_addr;
+
+	if(eth16i_debug > 1) 
+		printk(KERN_DEBUG "%s: Resetting device.\n", dev->name);
+
+	BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+	outw(0xffff, ioaddr + TX_STATUS_REG);    
+	eth16i_select_regbank(2, ioaddr);
+
+	lp->tx_started = 0;
+	lp->tx_buf_busy = 0;
+	lp->tx_queue = 0;
+	lp->tx_queue_len = 0;    
+	BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+}
+
+static void eth16i_multicast(struct net_device *dev)
+{
+	int ioaddr = dev->base_addr;
+  
+	if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) 
+	{
+		dev->flags|=IFF_PROMISC;	/* Must do this */
+		outb(3, ioaddr + RECEIVE_MODE_REG);    
+	} else {
+		outb(2, ioaddr + RECEIVE_MODE_REG);
+	}
+}
+
+static struct net_device_stats *eth16i_get_stats(struct net_device *dev)
+{
+	struct eth16i_local *lp = netdev_priv(dev);
+	return &lp->stats;
+}
+
+static void eth16i_select_regbank(unsigned char banknbr, int ioaddr)
+{
+	unsigned char data;
+
+	data = inb(ioaddr + CONFIG_REG_1);
+	outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1); 
+}
+
+#ifdef MODULE
+
+static ushort eth16i_parse_mediatype(const char* s)
+{
+	if(!s)
+		return E_PORT_FROM_EPROM;
+	
+        if (!strncmp(s, "bnc", 3))
+		return E_PORT_BNC;
+        else if (!strncmp(s, "tp", 2))
+                return E_PORT_TP;
+        else if (!strncmp(s, "dix", 3))
+                return E_PORT_DIX;
+        else if (!strncmp(s, "auto", 4))
+		return E_PORT_AUTO;
+	else
+		return E_PORT_FROM_EPROM;
+}
+
+#define MAX_ETH16I_CARDS 4  /* Max number of Eth16i cards per module */
+
+static struct net_device *dev_eth16i[MAX_ETH16I_CARDS];
+static int io[MAX_ETH16I_CARDS];
+#if 0
+static int irq[MAX_ETH16I_CARDS];
+#endif
+static char* mediatype[MAX_ETH16I_CARDS];
+static int debug = -1;
+
+MODULE_AUTHOR("Mika Kuoppala <miku@iki.fi>");
+MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver");
+MODULE_LICENSE("GPL");
+
+
+module_param_array(io, int, NULL, 0);
+MODULE_PARM_DESC(io, "eth16i I/O base address(es)");
+
+#if 0
+module_param_array(irq, int, NULL, 0);
+MODULE_PARM_DESC(irq, "eth16i interrupt request number");
+#endif
+
+module_param_array(mediatype, charp, NULL, 0);
+MODULE_PARM_DESC(mediatype, "eth16i media type of interface(s) (bnc,tp,dix,auto,eprom)");
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "eth16i debug level (0-6)");
+
+int init_module(void)
+{
+	int this_dev, found = 0;
+	struct net_device *dev;
+
+	for (this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) {
+		dev = alloc_etherdev(sizeof(struct eth16i_local));
+		if (!dev)
+			break;
+
+		dev->base_addr = io[this_dev];
+
+	        if(debug != -1)
+			eth16i_debug = debug;
+
+		if(eth16i_debug > 1)
+			printk(KERN_NOTICE "eth16i(%d): interface type %s\n", this_dev, mediatype[this_dev] ? mediatype[this_dev] : "none" );
+
+		dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]);
+
+		if(io[this_dev] == 0) {
+			if(this_dev != 0) /* Only autoprobe 1st one */
+				break;
+
+			printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n");
+		}
+
+		if (do_eth16i_probe(dev) == 0) {
+			if (register_netdev(dev) == 0) {
+				dev_eth16i[found++] = dev;
+				continue;
+			}
+			free_irq(dev->irq, dev);
+			release_region(dev->base_addr, ETH16I_IO_EXTENT);
+		}
+		printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n",
+		       io[this_dev]);
+		free_netdev(dev);
+		break;
+	}
+	if (found)
+		return 0;
+	return -ENXIO;
+}
+	
+void cleanup_module(void)
+{
+	int this_dev;
+
+	for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) {
+		struct net_device *dev = dev_eth16i[this_dev];
+		
+		if(dev->priv) {
+			unregister_netdev(dev);
+			free_irq(dev->irq, dev);
+			release_region(dev->base_addr, ETH16I_IO_EXTENT);
+			free_netdev(dev);
+		}
+	}
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eth16i.c"
+ *  alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict -prototypes -O6 -c eth16i.c"
+ *  tab-width: 8
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ * End:
+ */
+
+/* End of file eth16i.c */