patch-2.4.0-test2 linux/drivers/net/sk_mca.c

Next file: linux/drivers/net/sk_mca.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.4.0-test1/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c
@@ -62,14 +62,25 @@
 	implemented LANCE multicast filter
   Jun 6th, 1999
 	additions for Linux 2.2
-  Aug 2nd, 1999
-	small fixes (David Weinehall)
+  Dec 25th, 1999
+  	unfortunately there seem to be newer MC2+ boards that react
+  	on IRQ 3/5/9/10 instead of 3/5/10/11, so we have to autoprobe
+  	in questionable cases...
+  Dec 28th, 1999
+	integrated patches from David Weinehall & Bill Wendling for 2.3
+	kernels (isa_...functions).  Things are defined in a way that
+        it still works with 2.0.x 8-)
+  Dec 30th, 1999
+	added handling of the remaining interrupt conditions.  That
+        should cure the spurious hangs.
+  Jan 30th, 2000
+	newer kernels automatically probe more than one board, so the
+	'startslot' as a variable is also needed here
+  June 1st, 2000
+	added changes for recent 2.3 kernels
 
  *************************************************************************/
 
-#include <linux/module.h>
-#include <linux/version.h>
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -84,6 +95,11 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
@@ -96,11 +112,11 @@
  * have to pack all state info into the device struct!
  * ------------------------------------------------------------------------ */
 
-static char *MediaNames[Media_Count] = {
-	"10Base2", "10BaseT", "10Base5", "Unknown" };
+static char *MediaNames[Media_Count] =
+    { "10Base2", "10BaseT", "10Base5", "Unknown" };
 
-static unsigned char poly[] = { 
-	1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
+static unsigned char poly[] =
+    { 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
 	1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0
 };
 
@@ -111,14 +127,14 @@
 /* dump parts of shared memory - only needed during debugging */
 
 #ifdef DEBUG
-static void dumpmem(struct net_device *dev, u32 start, u32 len)
+static void dumpmem(struct SKMCA_NETDEV *dev, u32 start, u32 len)
 {
 	int z;
 
 	for (z = 0; z < len; z++) {
 		if ((z & 15) == 0)
 			printk("%04x:", z);
-		printk(" %02x", readb(dev->mem_start + start + z));
+		printk(" %02x", SKMCA_READB(dev->mem_start + start + z));
 		if ((z & 15) == 15)
 			printk("\n");
 	}
@@ -133,7 +149,6 @@
 	do_gettimeofday(&tv);
 	printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
 }
-
 #endif
 
 /* deduce resources out of POS registers */
@@ -169,10 +184,10 @@
 			*irq = 5;
 			break;
 		case 8:
-			*irq = 10;
+			*irq = -10;
 			break;
 		case 12:
-			*irq = 11;
+			*irq = -11;
 			break;
 		}
 		*medium = (pos2 >> 6) & 3;
@@ -205,18 +220,37 @@
 
 /* reset the whole board */
 
-static void ResetBoard(struct net_device *dev)
+static void ResetBoard(struct SKMCA_NETDEV *dev)
 {
 	skmca_priv *priv = (skmca_priv *) dev->priv;
 
-	writeb(CTRL_RESET_ON, priv->ctrladdr);
+	SKMCA_WRITEB(CTRL_RESET_ON, priv->ctrladdr);
 	udelay(10);
-	writeb(CTRL_RESET_OFF, priv->ctrladdr);
+	SKMCA_WRITEB(CTRL_RESET_OFF, priv->ctrladdr);
+}
+
+/* wait for LANCE interface to become not busy */
+
+static int WaitLANCE(struct SKMCA_NETDEV *dev)
+{
+	skmca_priv *priv = (skmca_priv *) dev->priv;
+	int t = 0;
+
+	while ((SKMCA_READB(priv->ctrladdr) & STAT_IO_BUSY) ==
+	       STAT_IO_BUSY) {
+		udelay(1);
+		if (++t > 1000) {
+			printk("%s: LANCE access timeout", dev->name);
+			return 0;
+		}
+	}
+
+	return 1;
 }
 
 /* set LANCE register - must be atomic */
 
-static void SetLANCE(struct net_device *dev, u16 addr, u16 value)
+static void SetLANCE(struct SKMCA_NETDEV *dev, u16 addr, u16 value)
 {
 	skmca_priv *priv = (skmca_priv *) dev->priv;
 	unsigned long flags;
@@ -228,25 +262,25 @@
 
 	/* wait until no transfer is pending */
 
-	while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+	WaitLANCE(dev);
 
 	/* transfer register address to RAP */
 
-	writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP,
-	       priv->ctrladdr);
-	writew(addr, priv->ioregaddr);
-	writeb(IOCMD_GO, priv->cmdaddr);
+	SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP,
+		     priv->ctrladdr);
+	SKMCA_WRITEW(addr, priv->ioregaddr);
+	SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr);
 	udelay(1);
-	while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+	WaitLANCE(dev);
 
 	/* transfer data to register */
 
-	writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA,
-	       priv->ctrladdr);
-	writew(value, priv->ioregaddr);
-	writeb(IOCMD_GO, priv->cmdaddr);
+	SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA,
+		     priv->ctrladdr);
+	SKMCA_WRITEW(value, priv->ioregaddr);
+	SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr);
 	udelay(1);
-	while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+	WaitLANCE(dev);
 
 	/* reenable interrupts */
 
@@ -255,7 +289,7 @@
 
 /* get LANCE register */
 
-static u16 GetLANCE(struct net_device *dev, u16 addr)
+static u16 GetLANCE(struct SKMCA_NETDEV *dev, u16 addr)
 {
 	skmca_priv *priv = (skmca_priv *) dev->priv;
 	unsigned long flags;
@@ -268,25 +302,25 @@
 
 	/* wait until no transfer is pending */
 
-	while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+	WaitLANCE(dev);
 
 	/* transfer register address to RAP */
 
-	writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP,
-	       priv->ctrladdr);
-	writew(addr, priv->ioregaddr);
-	writeb(IOCMD_GO, priv->cmdaddr);
+	SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP,
+		     priv->ctrladdr);
+	SKMCA_WRITEW(addr, priv->ioregaddr);
+	SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr);
 	udelay(1);
-	while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+	WaitLANCE(dev);
 
 	/* transfer data from register */
 
-	writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA,
-	       priv->ctrladdr);
-	writeb(IOCMD_GO, priv->cmdaddr);
+	SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA,
+		     priv->ctrladdr);
+	SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr);
 	udelay(1);
-	while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
-	res = readw(priv->ioregaddr);
+	WaitLANCE(dev);
+	res = SKMCA_READW(priv->ioregaddr);
 
 	/* reenable interrupts */
 
@@ -297,7 +331,7 @@
 
 /* build up descriptors in shared RAM */
 
-static void InitDscrs(struct net_device *dev)
+static void InitDscrs(struct SKMCA_NETDEV *dev)
 {
 	u32 bufaddr;
 
@@ -314,11 +348,11 @@
 			descr.Flags = 0;
 			descr.Len = 0xf000;
 			descr.Status = 0;
-			isa_memcpy_toio(dev->mem_start + RAM_TXBASE +
-					(z * sizeof(LANCE_TxDescr)),
-					&descr, sizeof(LANCE_TxDescr));
-			memset_io(dev->mem_start + bufaddr, 0,
-				  RAM_BUFSIZE);
+			SKMCA_TOIO(dev->mem_start + RAM_TXBASE +
+				   (z * sizeof(LANCE_TxDescr)), &descr,
+				   sizeof(LANCE_TxDescr));
+			SKMCA_SETIO(dev->mem_start + bufaddr, 0,
+				    RAM_BUFSIZE);
 			bufaddr += RAM_BUFSIZE;
 		}
 	}
@@ -334,11 +368,11 @@
 			descr.Flags = RXDSCR_FLAGS_OWN;
 			descr.MaxLen = -RAM_BUFSIZE;
 			descr.Len = 0;
-			isa_memcpy_toio(dev->mem_start + RAM_RXBASE +
-					(z * sizeof(LANCE_RxDescr)),
-					&descr, sizeof(LANCE_RxDescr));
-			isa_memset_io(dev->mem_start + bufaddr, 0,
-				      RAM_BUFSIZE);
+			SKMCA_TOIO(dev->mem_start + RAM_RXBASE +
+				   (z * sizeof(LANCE_RxDescr)), &descr,
+				   sizeof(LANCE_RxDescr));
+			SKMCA_SETIO(dev->mem_start + bufaddr, 0,
+				    RAM_BUFSIZE);
 			bufaddr += RAM_BUFSIZE;
 		}
 	}
@@ -393,7 +427,7 @@
 
 /* feed ready-built initialization block into LANCE */
 
-static void InitLANCE(struct net_device *dev)
+static void InitLANCE(struct SKMCA_NETDEV *dev)
 {
 	skmca_priv *priv = (skmca_priv *) dev->priv;
 
@@ -423,8 +457,12 @@
 
 	/* we don't get ready until the LANCE has read the init block */
 
+#if (LINUX_VERSION_CODE >= 0x02032a)
 	netif_stop_queue(dev);
-	
+#else
+	dev->tbusy = 1;
+#endif
+
 	/* let LANCE read the initialization block.  LANCE is ready
 	   when we receive the corresponding interrupt. */
 
@@ -433,12 +471,16 @@
 
 /* stop the LANCE so we can reinitialize it */
 
-static void StopLANCE(struct net_device *dev)
+static void StopLANCE(struct SKMCA_NETDEV *dev)
 {
 	/* can't take frames any more */
 
+#if (LINUX_VERSION_CODE >= 0x02032a)
 	netif_stop_queue(dev);
-	
+#else
+	dev->tbusy = 1;
+#endif
+
 	/* disable interrupts, stop it */
 
 	SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
@@ -446,7 +488,7 @@
 
 /* initialize card and LANCE for proper operation */
 
-static void InitBoard(struct net_device *dev)
+static void InitBoard(struct SKMCA_NETDEV *dev)
 {
 	LANCE_InitBlock block;
 
@@ -462,8 +504,7 @@
 	block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
 	block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
 
-	isa_memcpy_toio(dev->mem_start + RAM_INITBASE, &block,
-			sizeof(block));
+	SKMCA_TOIO(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
 
 	/* initialize LANCE. Implicitly sets up other structures in RAM. */
 
@@ -472,7 +513,7 @@
 
 /* deinitialize card and LANCE */
 
-static void DeinitBoard(struct net_device *dev)
+static void DeinitBoard(struct SKMCA_NETDEV *dev)
 {
 	/* stop LANCE */
 
@@ -483,44 +524,97 @@
 	ResetBoard(dev);
 }
 
+/* probe for device's irq */
+
+static int ProbeIRQ(struct SKMCA_NETDEV *dev)
+{
+	unsigned long imaskval, njiffies, irq;
+	u16 csr0val;
+
+	/* enable all interrupts */
+
+	imaskval = probe_irq_on();
+
+	/* initialize the board. Wait for interrupt 'Initialization done'. */
+
+	ResetBoard(dev);
+	InitBoard(dev);
+
+	njiffies = jiffies + 100;
+	do {
+		csr0val = GetLANCE(dev, LANCE_CSR0);
+	}
+	while (((csr0val & CSR0_IDON) == 0) && (jiffies != njiffies));
+
+	/* turn of interrupts again */
+
+	irq = probe_irq_off(imaskval);
+
+	/* if we found something, ack the interrupt */
+
+	if (irq)
+		SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_IDON);
+
+	/* back to idle state */
+
+	DeinitBoard(dev);
+
+	return irq;
+}
+
 /* ------------------------------------------------------------------------
  * interrupt handler(s)
  * ------------------------------------------------------------------------ */
 
-/* LANCE has read initializazion block -> start it */
+/* LANCE has read initialization block -> start it */
 
-static u16 irqstart_handler(struct net_device *dev, u16 oldcsr0)
+static u16 irqstart_handler(struct SKMCA_NETDEV *dev, u16 oldcsr0)
 {
 	/* now we're ready to transmit */
 
+#if (LINUX_VERSION_CODE >= 0x02032a)
 	netif_wake_queue(dev);
-	
+#else
+	dev->tbusy = 0;
+#endif
+
 	/* reset IDON bit, start LANCE */
 
 	SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
 	return GetLANCE(dev, LANCE_CSR0);
 }
 
+/* did we loose blocks due to a FIFO overrun ? */
+
+static u16 irqmiss_handler(struct SKMCA_NETDEV *dev, u16 oldcsr0)
+{
+	skmca_priv *priv = (skmca_priv *) dev->priv;
+
+	/* update statistics */
+
+	priv->stat.rx_fifo_errors++;
+
+	/* reset MISS bit */
+
+	SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_MISS);
+	return GetLANCE(dev, LANCE_CSR0);
+}
+
 /* receive interrupt */
 
-static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
+static u16 irqrx_handler(struct SKMCA_NETDEV *dev, u16 oldcsr0)
 {
 	skmca_priv *priv = (skmca_priv *) dev->priv;
 	LANCE_RxDescr descr;
 	unsigned int descraddr;
 
-	/* did we loose blocks due to a FIFO overrun ? */
-
-	if (oldcsr0 & CSR0_MISS)
-		priv->stat.rx_fifo_errors++;
-
 	/* run through queue until we reach a descriptor we do not own */
 
 	descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
 	while (1) {
 		/* read descriptor */
-		isa_memcpy_fromio(&descr, dev->mem_start + descraddr,
-				  sizeof(LANCE_RxDescr));
+		SKMCA_FROMIO(&descr, dev->mem_start + descraddr,
+			     sizeof(LANCE_RxDescr));
 
 		/* if we reach a descriptor we do not own, we're done */
 		if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
@@ -551,10 +645,9 @@
 			if (skb == NULL)
 				priv->stat.rx_dropped++;
 			else {
-				isa_memcpy_fromio(skb_put(skb, descr.Len),
-						  dev->mem_start +
-						  descr.LowAddr,
-						  descr.Len);
+				SKMCA_FROMIO(skb_put(skb, descr.Len),
+					     dev->mem_start +
+					     descr.LowAddr, descr.Len);
 				skb->dev = dev;
 				skb->protocol = eth_type_trans(skb, dev);
 				skb->ip_summed = CHECKSUM_NONE;
@@ -571,8 +664,8 @@
 		descr.Flags |= RXDSCR_FLAGS_OWN;
 
 		/* update descriptor in shared RAM */
-		isa_memcpy_toio(dev->mem_start + descraddr, &descr,
-				sizeof(LANCE_RxDescr));
+		SKMCA_TOIO(dev->mem_start + descraddr, &descr,
+			   sizeof(LANCE_RxDescr));
 
 		/* go to next descriptor */
 		priv->nextrx++;
@@ -591,7 +684,7 @@
 
 /* transmit interrupt */
 
-static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
+static u16 irqtx_handler(struct SKMCA_NETDEV *dev, u16 oldcsr0)
 {
 	skmca_priv *priv = (skmca_priv *) dev->priv;
 	LANCE_TxDescr descr;
@@ -603,8 +696,8 @@
 	    RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
 	while (priv->txbusy > 0) {
 		/* read descriptor */
-		isa_memcpy_fromio(&descr, dev->mem_start + descraddr,
-				  sizeof(LANCE_TxDescr));
+		SKMCA_FROMIO(&descr, dev->mem_start + descraddr,
+			     sizeof(LANCE_TxDescr));
 
 		/* if the LANCE still owns this one, we've worked out all sent packets */
 		if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
@@ -653,9 +746,15 @@
 
 	/* at least one descriptor is freed.  Therefore we can accept
 	   a new one */
+	/* inform upper layers we're in business again */
 
+#if (LINUX_VERSION_CODE >= 0x02032a)
 	netif_wake_queue(dev);
-	
+#else
+	dev->tbusy = 0;
+	mark_bh(NET_BH);
+#endif
+
 	return oldcsr0;
 }
 
@@ -663,7 +762,7 @@
 
 static void irq_handler(int irq, void *device, struct pt_regs *regs)
 {
-	struct net_device *dev = (struct net_device *) device;
+	struct SKMCA_NETDEV *dev = (struct SKMCA_NETDEV *) device;
 	u16 csr0val;
 
 	/* read CSR0 to get interrupt cause */
@@ -675,6 +774,14 @@
 	if ((csr0val & CSR0_INTR) == 0)
 		return;
 
+#if (LINUX_VERSION_CODE >= 0x02032a)
+#if 0
+	set_bit(LINK_STATE_RXSEM, &dev->state);
+#endif
+#else
+	dev->interrupt = 1;
+#endif
+
 	/* loop through the interrupt bits until everything is clear */
 
 	do {
@@ -682,10 +789,28 @@
 			csr0val = irqstart_handler(dev, csr0val);
 		if ((csr0val & CSR0_RINT) != 0)
 			csr0val = irqrx_handler(dev, csr0val);
+		if ((csr0val & CSR0_MISS) != 0)
+			csr0val = irqmiss_handler(dev, csr0val);
 		if ((csr0val & CSR0_TINT) != 0)
 			csr0val = irqtx_handler(dev, csr0val);
+		if ((csr0val & CSR0_MERR) != 0) {
+			SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_MERR);
+			csr0val = GetLANCE(dev, LANCE_CSR0);
+		}
+		if ((csr0val & CSR0_BABL) != 0) {
+			SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_BABL);
+			csr0val = GetLANCE(dev, LANCE_CSR0);
+		}
 	}
 	while ((csr0val & CSR0_INTR) != 0);
+
+#if (LINUX_VERSION_CODE >= 0x02032a)
+#if 0
+	clear_bit(LINK_STATE_RXSEM, &dev->state);
+#endif
+#else
+	dev->interrupt = 0;
+#endif
 }
 
 /* ------------------------------------------------------------------------
@@ -697,7 +822,7 @@
 static int skmca_getinfo(char *buf, int slot, void *d)
 {
 	int len = 0, i;
-	struct net_device *dev = (struct net_device *) d;
+	struct SKMCA_NETDEV *dev = (struct SKMCA_NETDEV *) d;
 	skmca_priv *priv;
 
 	/* can't say anything about an uninitialized device... */
@@ -728,7 +853,7 @@
 
 /* open driver.  Means also initialization and start of LANCE */
 
-static int skmca_open(struct net_device *dev)
+static int skmca_open(struct SKMCA_NETDEV *dev)
 {
 	int result;
 	skmca_priv *priv = (skmca_priv *) dev->priv;
@@ -745,8 +870,19 @@
 	dev->irq = priv->realirq;
 
 	/* set up the card and LANCE */
+
 	InitBoard(dev);
 
+	/* set up flags */
+
+#if (LINUX_VERSION_CODE >= 0x02032a)
+	netif_start_queue(dev);
+#else
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 0;
+#endif
+
 #ifdef MODULE
 	MOD_INC_USE_COUNT;
 #endif
@@ -756,7 +892,7 @@
 
 /* close driver.  Shut down board and free allocated resources */
 
-static int skmca_close(struct net_device *dev)
+static int skmca_close(struct SKMCA_NETDEV *dev)
 {
 	/* turn off board */
 	DeinitBoard(dev);
@@ -775,7 +911,7 @@
 
 /* transmit a block. */
 
-static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
+static int skmca_tx(struct sk_buff *skb, struct SKMCA_NETDEV *dev)
 {
 	skmca_priv *priv = (skmca_priv *) dev->priv;
 	LANCE_TxDescr descr;
@@ -783,8 +919,15 @@
 	int tmplen, retval = 0;
 	unsigned long flags;
 
-	netif_stop_queue(dev);
-	
+	/* if we get called with a NULL descriptor, the Ethernet layer thinks 
+	   our card is stuck an we should reset it.  We'll do this completely: */
+
+	if (skb == NULL) {
+		DeinitBoard(dev);
+		InitBoard(dev);
+		return 0;	/* don't try to free the block here ;-) */
+	}
+
 	/* is there space in the Tx queue ? If no, the upper layer gave us a
 	   packet in spite of us not being ready and is really in trouble.
 	   We'll do the dropping for him: */
@@ -796,8 +939,8 @@
 
 	/* get TX descriptor */
 	address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
-	isa_memcpy_fromio(&descr, dev->mem_start + address,
-			  sizeof(LANCE_TxDescr));
+	SKMCA_FROMIO(&descr, dev->mem_start + address,
+		     sizeof(LANCE_TxDescr));
 
 	/* enter packet length as 2s complement - assure minimum length */
 	tmplen = skb->len;
@@ -813,15 +956,14 @@
 		unsigned int destoffs = 0, l = strlen(fill);
 
 		while (destoffs < tmplen) {
-			isa_memcpy_toio(dev->mem_start + descr.LowAddr +
-					destoffs, fill, l);
+			SKMCA_TOIO(dev->mem_start + descr.LowAddr +
+				   destoffs, fill, l);
 			destoffs += l;
 		}
 	}
 
 	/* do the real data copying */
-	isa_memcpy_toio(dev->mem_start + descr.LowAddr, skb->data,
-			skb->len);
+	SKMCA_TOIO(dev->mem_start + descr.LowAddr, skb->data, skb->len);
 
 	/* hand descriptor over to LANCE - this is the first and last chunk */
 	descr.Flags =
@@ -840,12 +982,19 @@
 	if (priv->nexttxput >= TXCOUNT)
 		priv->nexttxput = 0;
 	priv->txbusy++;
-	if (priv->txbusy < TXCOUNT)
-		netif_wake_queue(dev);
+
+	/* are we saturated ? */
+
+	if (priv->txbusy >= TXCOUNT)
+#if (LINUX_VERSION_CODE >= 0x02032a)
+		netif_stop_queue(dev);
+#else
+		dev->tbusy = 1;
+#endif
 
 	/* write descriptor back to RAM */
-	isa_memcpy_toio(dev->mem_start + address, &descr,
-			sizeof(LANCE_TxDescr));
+	SKMCA_TOIO(dev->mem_start + address, &descr,
+		   sizeof(LANCE_TxDescr));
 
 	/* if no descriptors were active, give the LANCE a hint to read it
 	   immediately */
@@ -855,24 +1004,31 @@
 
 	restore_flags(flags);
 
-tx_done:
+      tx_done:
+
 	/* When did that change exactly ? */
+
+#if LINUX_VERSION_CODE >= 0x020200
 	dev_kfree_skb(skb);
+#else
+	dev_kfree_skb(skb, FREE_WRITE);
+#endif
 	return retval;
 }
 
 /* return pointer to Ethernet statistics */
 
-static struct enet_statistics *skmca_stats(struct net_device *dev)
+static struct enet_statistics *skmca_stats(struct SKMCA_NETDEV *dev)
 {
 	skmca_priv *priv = (skmca_priv *) dev->priv;
+
 	return &(priv->stat);
 }
 
 /* we don't support runtime reconfiguration, since an MCA card can
    be unambigously identified by its POS registers. */
 
-static int skmca_config(struct net_device *dev, struct ifmap *map)
+static int skmca_config(struct SKMCA_NETDEV *dev, struct ifmap *map)
 {
 	return 0;
 }
@@ -880,7 +1036,7 @@
 /* switch receiver mode.  We use the LANCE's multicast filter to prefilter
    multicast addresses. */
 
-static void skmca_set_multicast_list(struct net_device *dev)
+static void skmca_set_multicast_list(struct SKMCA_NETDEV *dev)
 {
 	LANCE_InitBlock block;
 
@@ -888,8 +1044,7 @@
 	StopLANCE(dev);
 
 	/* ...then modify the initialization block... */
-	isa_memcpy_fromio(&block, dev->mem_start + RAM_INITBASE,
-			  sizeof(block));
+	SKMCA_FROMIO(&block, dev->mem_start + RAM_INITBASE, sizeof(block));
 	if (dev->flags & IFF_PROMISC)
 		block.Mode |= LANCE_INIT_PROM;
 	else
@@ -909,8 +1064,7 @@
 		}
 	}
 
-	isa_memcpy_toio(dev->mem_start + RAM_INITBASE, &block,
-			sizeof(block));
+	SKMCA_TOIO(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
 
 	/* ...then reinit LANCE with the correct flags */
 	InitLANCE(dev);
@@ -920,13 +1074,9 @@
  * hardware check
  * ------------------------------------------------------------------------ */
 
-#ifdef MODULE
 static int startslot;		/* counts through slots when probing multiple devices */
-#else
-#define startslot 0		/* otherwise a dummy, since there is only eth0 in-kern */
-#endif
 
-int skmca_probe(struct net_device *dev)
+int skmca_probe(struct SKMCA_NETDEV *dev)
 {
 	int force_detect = 0;
 	int junior, slot, i;
@@ -937,7 +1087,7 @@
 	/* can't work without an MCA bus ;-) */
 
 	if (MCA_bus == 0)
-		return ENODEV;
+		return -ENODEV;
 
 	/* start address of 1 --> forced detection */
 
@@ -957,7 +1107,7 @@
 
 		getaddrs(slot, junior, &base, &irq, &medium);
 
-#if LINUX_VERSION_CODE >= 0x020200
+#if LINUX_VERSION_CODE >= 0x020300
 		/* slot already in use ? */
 
 		if (mca_is_adapter_used(slot)) {
@@ -1015,7 +1165,6 @@
 	priv->ioregaddr = base + 0x3ff0;
 	priv->ctrladdr = base + 0x3ff2;
 	priv->cmdaddr = base + 0x3ff3;
-	priv->realirq = irq;
 	priv->medium = medium;
 	memset(&(priv->stat), 0, sizeof(struct enet_statistics));
 
@@ -1024,6 +1173,22 @@
 	dev->mem_start = base;
 	dev->mem_end = base + 0x4000;
 
+	/* autoprobe ? */
+	if (irq < 0) {
+		int nirq;
+
+		printk
+		    ("%s: ambigous POS bit combination, must probe for IRQ...\n",
+		     dev->name);
+		nirq = ProbeIRQ(dev);
+		if (nirq <= 0)
+			printk("%s: IRQ probe failed, assuming IRQ %d",
+			       dev->name, priv->realirq = -irq);
+		else
+			priv->realirq = nirq;
+	} else
+		priv->realirq = irq;
+
 	/* set methods */
 	dev->open = skmca_open;
 	dev->stop = skmca_close;
@@ -1039,7 +1204,7 @@
 
 	/* copy out MAC address */
 	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = readb(priv->macbase + (i << 1));
+		dev->dev_addr[i] = SKMCA_READB(priv->macbase + (i << 1));
 
 	/* print config */
 	printk("%s: IRQ %d, memory %#lx-%#lx, "
@@ -1053,9 +1218,7 @@
 
 	ResetBoard(dev);
 
-#ifdef MODULE
 	startslot = slot + 1;
-#endif
 
 	return 0;
 }
@@ -1068,13 +1231,24 @@
 
 #define DEVMAX 5
 
-static struct net_device moddevs[DEVMAX] =
-    { {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
-{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
-{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
-{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
-{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}
+#if (LINUX_VERSION_CODE >= 0x020369)
+static struct SKMCA_NETDEV moddevs[DEVMAX] =
+    { {"    ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{"    ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{"    ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{"    ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{"    ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}
 };
+#else
+static char NameSpace[8 * DEVMAX];
+static struct SKMCA_NETDEV moddevs[DEVMAX] =
+    { {NameSpace + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{NameSpace + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{NameSpace + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{NameSpace + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{NameSpace + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}
+};
+#endif
 
 int irq = 0;
 int io = 0;
@@ -1096,7 +1270,7 @@
 
 void cleanup_module(void)
 {
-	struct net_device *dev;
+	struct SKMCA_NETDEV *dev;
 	skmca_priv *priv;
 	int z;
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)