patch-2.4.19 linux-2.4.19/drivers/net/declance.c

Next file: linux-2.4.19/drivers/net/depca.c
Previous file: linux-2.4.19/drivers/net/de620.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/drivers/net/declance.c linux-2.4.19/drivers/net/declance.c
@@ -5,6 +5,8 @@
  *
  *      adopted from sunlance.c by Richard van den Berg
  *
+ *      Copyright (C) 2002  Maciej W. Rozycki
+ *
  *      additional sources:
  *      - PMAD-AA TURBOchannel Ethernet Module Functional Specification,
  *        Revision 1.2
@@ -16,77 +18,68 @@
  *      v0.002: Removed most sparc stuff, left only some module and dma stuff.
  *
  *      v0.003: Enhanced base address calculation from proposals by
- *      Harald Koerfgen and Thomas Riemer.
+ *              Harald Koerfgen and Thomas Riemer.
  *
  *      v0.004: lance-regs is pointing at the right addresses, added prom
- *      check. First start of address mapping and DMA.
+ *              check. First start of address mapping and DMA.
  *
- *      v0.005: started to play around with LANCE-DMA. This driver will not work
- *      for non IOASIC lances. HK
+ *      v0.005: started to play around with LANCE-DMA. This driver will not
+ *              work for non IOASIC lances. HK
  *
- *      v0.006: added pointer arrays to lance_private and setup routine for them
- *      in dec_lance_init. HK
+ *      v0.006: added pointer arrays to lance_private and setup routine for
+ *              them in dec_lance_init. HK
  *
- *      v0.007: Big shit. The LANCE seems to use a different DMA mechanism to access
- *      the init block. This looks like one (short) word at a time, but the smallest
- *      amount the IOASIC can transfer is a (long) word. So we have a 2-2 padding here.
- *      Changed lance_init_block accordingly. The 16-16 padding for the buffers
- *      seems to be correct. HK
+ *      v0.007: Big shit. The LANCE seems to use a different DMA mechanism to
+ *              access the init block. This looks like one (short) word at a
+ *              time, but the smallest amount the IOASIC can transfer is a
+ *              (long) word. So we have a 2-2 padding here. Changed
+ *              lance_init_block accordingly. The 16-16 padding for the buffers
+ *              seems to be correct. HK
  *
- *     v0.008 - mods to make PMAX_LANCE work. 01/09/1999 triemer
- */
-
-#undef DEBUG_DRIVER
-
-static char *version =
-"declance.c: v0.008 by Linux Mips DECstation task force\n";
-
-static char *lancestr = "LANCE";
-
-/*
- * card types
+ *      v0.008: mods to make PMAX_LANCE work. 01/09/1999 triemer
+ *
+ *      v0.009: Module support fixes, multiple interfaces support, various
+ *              bits. macro
  */
-#define ASIC_LANCE 1
-#define PMAD_LANCE 2
-#define PMAX_LANCE 3
 
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
 
+#include <asm/addrspace.h>
 #include <asm/dec/interrupts.h>
-#include <asm/dec/ioasic_ints.h>
+#include <asm/dec/ioasic.h>
 #include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/kn01.h>
 #include <asm/dec/machtype.h>
 #include <asm/dec/tc.h>
-#include <asm/dec/kn01.h>
 #include <asm/wbflush.h>
-#include <asm/addrspace.h>
 
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/utsname.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-#include <linux/etherdevice.h>
+static char version[] __devinitdata =
+"declance.c: v0.009 by Linux MIPS DECstation task force\n";
+
+MODULE_AUTHOR("Linux MIPS DECstation task force");
+MODULE_DESCRIPTION("DEC LANCE (DECstation onboard, PMAD-xx) driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * card types
+ */
+#define ASIC_LANCE 1
+#define PMAD_LANCE 2
+#define PMAX_LANCE 3
 
 #ifndef CONFIG_TC
 unsigned long system_base;
 unsigned long dmaptr;
 #endif
-static int type;
 
 #define CRC_POLYNOMIAL_BE 0x04c11db7UL	/* Ethernet CRC, big endian */
 #define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
@@ -164,8 +157,6 @@
 #define TX_BUFF_SIZE            PKT_BUF_SZ
 
 #undef TEST_HITS
-#define DEBUG_DRIVER 1
-
 #define ZERO 0
 
 /* The DS2000/3000 have a linear 64 KB buffer.
@@ -183,26 +174,26 @@
  */
 
 struct lance_rx_desc {
-	unsigned short rmd0;	/* low address of packet */
+	unsigned short rmd0;		/* low address of packet */
 	short gap0;
 	unsigned char rmd1_hadr;	/* high address of packet */
 	unsigned char rmd1_bits;	/* descriptor bits */
 	short gap1;
-	short length;		/* This length is 2s complement (negative)!
-				   * Buffer length
-				 */
+	short length;			/* 2s complement (negative!)
+					   of buffer length */
 	short gap2;
-	unsigned short mblength;	/* This is the actual number of bytes received */
+	unsigned short mblength;	/* actual number of bytes received */
 	short gap3;
 };
 
 struct lance_tx_desc {
-	unsigned short tmd0;	/* low address of packet */
+	unsigned short tmd0;		/* low address of packet */
 	short gap0;
 	unsigned char tmd1_hadr;	/* high address of packet */
 	unsigned char tmd1_bits;	/* descriptor bits */
 	short gap1;
-	short length;		/* Length is 2s complement (negative)! */
+	short length;			/* 2s complement (negative!)
+					   of buffer length */
 	short gap2;
 	unsigned short misc;
 	short gap3;
@@ -211,28 +202,26 @@
 
 /* First part of the LANCE initialization block, described in databook. */
 struct lance_init_block {
-	unsigned short mode;	/* Pre-set mode (reg. 15) */
+	unsigned short mode;		/* pre-set mode (reg. 15) */
 	short gap0;
 
-	unsigned char phys_addr[12];	/* Physical ethernet address
-					   * only 0, 1, 4, 5, 8, 9 are valid
-					   * 2, 3, 6, 7, 10, 11 are gaps
-					 */
-	unsigned short filter[8];	/* Multicast filter.
-					   * only 0, 2, 4, 6 are valid
-					   * 1, 3, 5, 7 are gaps
-					 */
+	unsigned char phys_addr[12];	/* physical ethernet address
+					   only 0, 1, 4, 5, 8, 9 are valid
+					   2, 3, 6, 7, 10, 11 are gaps */
+	unsigned short filter[8];	/* multicast filter
+					   only 0, 2, 4, 6 are valid
+					   1, 3, 5, 7 are gaps */
 
 	/* Receive and transmit ring base, along with extra bits. */
-	unsigned short rx_ptr;	/* receive descriptor addr */
+	unsigned short rx_ptr;		/* receive descriptor addr */
 	short gap1;
-	unsigned short rx_len;	/* receive len and high addr */
+	unsigned short rx_len;		/* receive len and high addr */
 	short gap2;
-	unsigned short tx_ptr;	/* transmit descriptor addr */
+	unsigned short tx_ptr;		/* transmit descriptor addr */
 	short gap3;
-	unsigned short tx_len;	/* transmit len and high addr */
+	unsigned short tx_len;		/* transmit len and high addr */
 	short gap4;
-	char gap5[16];
+	short gap5[8];
 
 	/* The buffer descriptors */
 	struct lance_rx_desc brx_ring[RX_RING_SIZE];
@@ -251,10 +240,12 @@
 #define LANCE_ADDR(x) (PHYSADDR(x) >> 1)
 
 struct lance_private {
-	char *name;
+	struct net_device *next;
+	int type;
+	int slot;
+	int dma_irq;
 	volatile struct lance_regs *ll;
 	volatile struct lance_init_block *init_block;
-	volatile unsigned long *dma_ptr_reg;
 
 	spinlock_t	lock;
 
@@ -265,8 +256,6 @@
 
 	unsigned short busmaster_regval;
 
-	struct net_device *dev;	/* Backpointer        */
-	struct lance_private *next_module;
 	struct timer_list       multicast_timer;
 
 	/* Pointers to the ring buffers as seen from the CPU */
@@ -296,11 +285,7 @@
 
 int dec_lance_debug = 2;
 
-/*
-   #ifdef MODULE
-   static struct lance_private *root_lance_dev = NULL;
-   #endif
- */
+static struct net_device *root_lance_dev;
 
 static inline void writereg(volatile unsigned short *regptr, short value)
 {
@@ -334,7 +319,7 @@
  * Our specialized copy routines
  *
  */
-void cp_to_buf(void *to, const void *from, __kernel_size_t len)
+void cp_to_buf(const int type, void *to, const void *from, int len)
 {
 	unsigned short *tp, *fp, clen;
 	unsigned char *rtp, *rfp;
@@ -388,7 +373,7 @@
 	wbflush();
 }
 
-void cp_from_buf(void *to, unsigned char *from, int len)
+void cp_from_buf(const int type, void *to, const void *from, int len)
 {
 	unsigned short *tp, *fp, clen;
 	unsigned char *rtp, *rfp;
@@ -555,22 +540,21 @@
 
 #ifdef TEST_HITS
 	{
-	int i;
+		int i;
 
-	printk("[");
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		if (i == lp->rx_new)
-			printk("%s",
-			       ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "_" : "X");
-		else
-			printk("%s",
-			       ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "." : "1");
-	}
-	printk("]");
+		printk("[");
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			if (i == lp->rx_new)
+				printk("%s", ib->brx_ring[i].rmd1_bits &
+					     LE_R1_OWN ? "_" : "X");
+			else
+				printk("%s", ib->brx_ring[i].rmd1_bits &
+					     LE_R1_OWN ? "." : "1");
+		}
+		printk("]");
 	}
 #endif
 
-
 	for (rd = &ib->brx_ring[lp->rx_new];
 	     !((bits = rd->rmd1_bits) & LE_R1_OWN);
 	     rd = &ib->brx_ring[lp->rx_new]) {
@@ -612,8 +596,8 @@
 			skb_reserve(skb, 2);	/* 16 byte align */
 			skb_put(skb, len);	/* make room */
 
-			cp_from_buf(skb->data,
-				 (char *) lp->rx_buf_ptr_cpu[lp->rx_new],
+			cp_from_buf(lp->type, skb->data,
+				    (char *)lp->rx_buf_ptr_cpu[lp->rx_new],
 				    len);
 
 			skb->protocol = eth_type_trans(skb, dev);
@@ -713,6 +697,14 @@
 	spin_unlock(&lp->lock);
 }
 
+static void lance_dma_merr_int(const int irq, void *dev_id,
+				struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+
+	printk("%s: DMA error\n", dev->name);
+}
+
 static void lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
@@ -744,19 +736,8 @@
 		lp->stats.rx_errors++;
 
 	if (csr0 & LE_C0_MERR) {
-		volatile unsigned long int_stat = *(unsigned long *) (system_base + IOCTL + SIR);
-
 		printk("%s: Memory error, status %04x\n", dev->name, csr0);
 
-		if (int_stat & LANCE_DMA_MEMRDERR) {
-			printk("%s: DMA error\n", dev->name);
-			int_stat |= LANCE_DMA_MEMRDERR;
-			/*
-			 * re-enable LANCE DMA
-			 */
-			*(unsigned long *) (system_base + IOCTL + SSR) |= (1 << 16);
-			wbflush();
-		}
 		writereg(&ll->rdp, LE_C0_STOP);
 
 		lance_init_ring(dev);
@@ -793,6 +774,8 @@
 	ib->mode = 0;
 	ib->filter [0] = 0;
 	ib->filter [2] = 0;
+	ib->filter [4] = 0;
+	ib->filter [6] = 0;
 
 	lance_init_ring(dev);
 	load_csrs(lp);
@@ -800,10 +783,21 @@
 	netif_start_queue(dev);
 
 	/* Associate IRQ with lance_interrupt */
-	if (request_irq(dev->irq, &lance_interrupt, 0, lp->name, dev)) {
-		printk("Lance: Can't get irq %d\n", dev->irq);
+	if (request_irq(dev->irq, &lance_interrupt, 0, "lance", dev)) {
+		printk("lance: Can't get IRQ %d\n", dev->irq);
 		return -EAGAIN;
 	}
+	if (lp->dma_irq >= 0) {
+		if (request_irq(lp->dma_irq, &lance_dma_merr_int, 0,
+				"lance error", dev)) {
+			free_irq(dev->irq, dev);
+			printk("lance: Can't get DMA IRQ %d\n", lp->dma_irq);
+			return -EAGAIN;
+		}
+		/* Enable I/O ASIC LANCE DMA.  */
+		wbflush();
+		ioasic_write(SSR, ioasic_read(SSR) | LANCE_DMA_EN);
+	}
 
 	status = init_restart_lance(lp);
 
@@ -827,7 +821,13 @@
 	writereg(&ll->rap, LE_CSR0);
 	writereg(&ll->rdp, LE_C0_STOP);
 
-	free_irq(dev->irq, (void *) dev);
+	if (lp->dma_irq >= 0) {
+		/* Disable I/O ASIC LANCE DMA.  */
+		ioasic_write(SSR, ioasic_read(SSR) & ~LANCE_DMA_EN);
+		wbflush();
+		free_irq(lp->dma_irq, dev);
+	}
+	free_irq(dev->irq, dev);
 	/*
 	   MOD_DEC_USE_COUNT;
 	 */
@@ -879,7 +879,8 @@
 	ib->btx_ring[entry].length = (-len);
 	ib->btx_ring[entry].misc = 0;
 
-	cp_to_buf((char *) lp->tx_buf_ptr_cpu[entry], skb->data, skblen);
+	cp_to_buf(lp->type, (char *)lp->tx_buf_ptr_cpu[entry], skb->data,
+		  skblen);
 
 	/* Clear the slack of the packet, do I need this? */
 	/* For a firewall its a good idea - AC */
@@ -920,7 +921,7 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_BE;
+	u32 crc, poly = CRC_POLYNOMIAL_LE;
 
 	/* set all multicast bits */
 	if (dev->flags & IFF_ALLMULTI) {
@@ -959,7 +960,7 @@
 			}
 
 		crc = crc >> 26;
-		mcast_table[crc >> 3] |= 1 << (crc & 0xf);
+		mcast_table[2 * (crc >> 4)] |= 1 << (crc & 0xf);
 	}
 	return;
 }
@@ -1006,7 +1007,7 @@
 	lance_set_multicast(dev);
 }
 
-static int __init dec_lance_init(struct net_device *dev, const int type)
+static int __init dec_lance_init(const int type, const int slot)
 {
 	static unsigned version_printed;
 	struct net_device *dev;
@@ -1018,21 +1019,25 @@
 
 #ifndef CONFIG_TC
 	system_base = KN01_LANCE_BASE;
-#else
-	int slot;
 #endif
 
 	if (dec_lance_debug && version_printed++ == 0)
 		printk(version);
 
-	dev = init_etherdev(0, sizeof(struct lance_private));
+	dev = init_etherdev(NULL, sizeof(struct lance_private));
 	if (!dev)
 		return -ENOMEM;
+	SET_MODULE_OWNER(dev);
 
-	/* init_etherdev ensures the data structures used by the LANCE are aligned. */
+	/*
+	 * init_etherdev ensures the data structures used by the LANCE
+	 * are aligned.
+	 */
 	lp = (struct lance_private *) dev->priv;
 	spin_lock_init(&lp->lock);
 
+	lp->type = type;
+	lp->slot = slot;
 	switch (type) {
 #ifdef CONFIG_TC
 	case ASIC_LANCE:
@@ -1044,78 +1049,100 @@
 		 */
 		dev->mem_start = KSEG1ADDR(0x00020000);
 		dev->mem_end = dev->mem_start + 0x00020000;
-		dev->irq = ETHER;
+		dev->irq = dec_interrupt[DEC_IRQ_LANCE];
 		esar_base = system_base + ESAR;
-	
+
 		/* Workaround crash with booting KN04 2.1k from Disk */
-		memset(dev->mem_start, 0, dev->mem_end - dev->mem_start);
+		memset((void *)dev->mem_start, 0,
+		       dev->mem_end - dev->mem_start);
 
 		/*
 		 * setup the pointer arrays, this sucks [tm] :-(
 		 */
 		for (i = 0; i < RX_RING_SIZE; i++) {
-			lp->rx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU
-						 + 2 * i * RX_BUFF_SIZE);
-			lp->rx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC
-						     + i * RX_BUFF_SIZE);
+			lp->rx_buf_ptr_cpu[i] =
+				(char *)(dev->mem_start + BUF_OFFSET_CPU +
+					 2 * i * RX_BUFF_SIZE);
+			lp->rx_buf_ptr_lnc[i] =
+				(char *)(BUF_OFFSET_LNC + i * RX_BUFF_SIZE);
 		}
 		for (i = 0; i < TX_RING_SIZE; i++) {
-			lp->tx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU
-					+ 2 * RX_RING_SIZE * RX_BUFF_SIZE
-						 + 2 * i * TX_BUFF_SIZE);
-			lp->tx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC
-					    + RX_RING_SIZE * RX_BUFF_SIZE
-						     + i * TX_BUFF_SIZE);
+			lp->tx_buf_ptr_cpu[i] =
+				(char *)(dev->mem_start + BUF_OFFSET_CPU +
+					 2 * RX_RING_SIZE * RX_BUFF_SIZE +
+					 2 * i * TX_BUFF_SIZE);
+			lp->tx_buf_ptr_lnc[i] =
+				(char *)(BUF_OFFSET_LNC +
+					 RX_RING_SIZE * RX_BUFF_SIZE +
+					 i * TX_BUFF_SIZE);
 		}
 
-		/*
-		 * setup and enable IOASIC LANCE DMA
-		 */
-		lp->dma_ptr_reg = (unsigned long *) (system_base + IOCTL + LANCE_DMA_P);
-		*(lp->dma_ptr_reg) = PHYSADDR(dev->mem_start) << 3;
-		*(unsigned long *) (system_base + IOCTL + SSR) |= (1 << 16);
-		wbflush();
+		/* Setup I/O ASIC LANCE DMA.  */
+		lp->dma_irq = dec_interrupt[DEC_IRQ_LANCE_MERR];
+		ioasic_write(LANCE_DMA_P, PHYSADDR(dev->mem_start) << 3);
 
 		break;
+
 	case PMAD_LANCE:
-		slot = search_tc_card("PMAD-AA");
 		claim_tc_card(slot);
 
 		dev->mem_start = get_tc_base_addr(slot);
 		dev->base_addr = dev->mem_start + 0x100000;
 		dev->irq = get_tc_irq_nr(slot);
 		esar_base = dev->mem_start + 0x1c0002;
+		lp->dma_irq = -1;
+
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			lp->rx_buf_ptr_cpu[i] =
+				(char *)(dev->mem_start + BUF_OFFSET_CPU +
+					 i * RX_BUFF_SIZE);
+			lp->rx_buf_ptr_lnc[i] =
+				(char *)(BUF_OFFSET_LNC + i * RX_BUFF_SIZE);
+		}
+		for (i = 0; i < TX_RING_SIZE; i++) {
+			lp->tx_buf_ptr_cpu[i] =
+				(char *)(dev->mem_start + BUF_OFFSET_CPU +
+					 RX_RING_SIZE * RX_BUFF_SIZE +
+					 i * TX_BUFF_SIZE);
+			lp->tx_buf_ptr_lnc[i] =
+				(char *)(BUF_OFFSET_LNC +
+					 RX_RING_SIZE * RX_BUFF_SIZE +
+					 i * TX_BUFF_SIZE);
+		}
+
 		break;
 #endif
+
 	case PMAX_LANCE:
-		dev->irq = ETHER;
+		dev->irq = dec_interrupt[DEC_IRQ_LANCE];
 		dev->base_addr = KN01_LANCE_BASE;
 		dev->mem_start = KN01_LANCE_BASE + 0x01000000;
 		esar_base = KN01_RTC_BASE + 1;
+		lp->dma_irq = -1;
+
 		/*
 		 * setup the pointer arrays, this sucks [tm] :-(
 		 */
 		for (i = 0; i < RX_RING_SIZE; i++) {
 			lp->rx_buf_ptr_cpu[i] =
-			    (char *) (dev->mem_start + BUF_OFFSET_CPU
-				      + 2 * i * RX_BUFF_SIZE);
-
+				(char *)(dev->mem_start + BUF_OFFSET_CPU +
+					 2 * i * RX_BUFF_SIZE);
 			lp->rx_buf_ptr_lnc[i] =
-			    (char *) (BUF_OFFSET_LNC
-				      + i * RX_BUFF_SIZE);
-
+				(char *)(BUF_OFFSET_LNC + i * RX_BUFF_SIZE);
 		}
 		for (i = 0; i < TX_RING_SIZE; i++) {
 			lp->tx_buf_ptr_cpu[i] =
-			    (char *) (dev->mem_start + BUF_OFFSET_CPU
-				      + 2 * RX_RING_SIZE * RX_BUFF_SIZE
-				      + 2 * i * TX_BUFF_SIZE);
-			lp->tx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC
-					    + RX_RING_SIZE * RX_BUFF_SIZE
-						     + i * TX_BUFF_SIZE);
-
+				(char *)(dev->mem_start + BUF_OFFSET_CPU +
+					 2 * RX_RING_SIZE * RX_BUFF_SIZE +
+					 2 * i * TX_BUFF_SIZE);
+			lp->tx_buf_ptr_lnc[i] =
+				(char *)(BUF_OFFSET_LNC +
+					 RX_RING_SIZE * RX_BUFF_SIZE +
+					 i * TX_BUFF_SIZE);
 		}
+
 		break;
+
 	default:
 		printk("declance_init called with unknown type\n");
 		ret = -ENODEV;
@@ -1145,6 +1172,9 @@
 		}
 	}
 
+	lp->next = root_lance_dev;
+	root_lance_dev = dev;
+
 	/* Copy the ethernet address to the device structure, later to the
 	 * lance initialization block so the lance gets it every time it's
 	 * (re)initialized.
@@ -1167,7 +1197,6 @@
 
 	printk(" irq = %d\n", dev->irq);
 
-	lp->dev = dev;
 	dev->open = &lance_open;
 	dev->stop = &lance_close;
 	dev->hard_start_xmit = &lance_start_xmit;
@@ -1179,8 +1208,6 @@
 	/* lp->ll is the location of the registers for lance card */
 	lp->ll = ll;
 
-	lp->name = lancestr;
-
 	/* busmaster_regval (CSR3) should be zero according to the PMAD-AA
 	 * specification.
 	 */
@@ -1188,8 +1215,6 @@
 
 	dev->dma = 0;
 
-	ether_setup(dev);
-
 	/* We cannot sleep if the chip is busy during a
 	 * multicast list update event, because such events
 	 * can occur from interrupts (ex. IPv6).  So we
@@ -1199,11 +1224,6 @@
 	lp->multicast_timer.data = (unsigned long) dev;
 	lp->multicast_timer.function = &lance_set_multicast_retry;
 
-#ifdef MODULE
-	dev->ifindex = dev_new_index();
-	lp->next_module = root_lance_dev;
-	root_lance_dev = lp;
-#endif
 	return 0;
 
 err_out:
@@ -1216,61 +1236,51 @@
 /* Find all the lance cards on the system and initialize them */
 static int __init dec_lance_probe(void)
 {
-	struct net_device *dev = NULL;
-	static int called;
-
-#ifdef MODULE
-	root_lance_dev = NULL;
-#endif
-
+	int count = 0;
 
+	/* Scan slots for PMAD-AA cards first. */
 #ifdef CONFIG_TC
-	int slot = -1;
-
 	if (TURBOCHANNEL) {
-		if (IOASIC && !called) {
-			called = 1;
-			type = ASIC_LANCE;
-		} else {
-			if ((slot = search_tc_card("PMAD-AA")) >= 0) {
-				type = PMAD_LANCE;
-			} else {
-				return -ENODEV;
-			}
-		}
-	} else {
-		if (!called) {
-			called = 1;
-			type = PMAX_LANCE;
-		} else {
-			return -ENODEV;
+		int slot;
+
+		while ((slot = search_tc_card("PMAD-AA")) >= 0) {
+			if (dec_lance_init(PMAD_LANCE, slot) < 0)
+				break;
+			count++;
 		}
 	}
-#else
-	if (!called && !TURBOCHANNEL) {
-		called = 1;
-		type = PMAX_LANCE;
-	} else {
-		return -ENODEV;
-	}
 #endif
 
-	return dec_lance_init(dev, type);
+	/* Then handle onboard devices. */
+	if (dec_interrupt[DEC_IRQ_LANCE] >= 0) {
+		if (dec_interrupt[DEC_IRQ_LANCE_MERR] >= 0) {
+#ifdef CONFIG_TC
+			if (dec_lance_init(ASIC_LANCE, -1) >= 0)
+				count++;
+#endif
+		} else if (!TURBOCHANNEL) {
+			if (dec_lance_init(PMAX_LANCE, -1) >= 0)
+				count++;
+		}
+	}
+
+	return (count > 0) ? 0 : -ENODEV;
 }
 
 static void __exit dec_lance_cleanup(void)
 {
-#ifdef MODULE
-   struct lance_private *lp;
-
-   while (root_lance_dev) {
-   lp = root_lance_dev->next_module;
+	while (root_lance_dev) {
+		struct net_device *dev = root_lance_dev;
+		struct lance_private *lp = (struct lance_private *)dev->priv;
 
-   unregister_netdev(root_lance_dev->dev);
-   kfree(root_lance_dev->dev);
-   root_lance_dev = lp;
-   }
-#endif /* MODULE */
+#ifdef CONFIG_TC
+		if (lp->slot >= 0)
+			release_tc_card(lp->slot);
+#endif
+		root_lance_dev = lp->next;
+		unregister_netdev(dev);
+		kfree(dev);
+	}
 }
 
 module_init(dec_lance_probe);

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