Resent-Date: Mon, 21 Dec 1998 13:59:18 +0100 (MET)
Date: Mon, 21 Dec 1998 14:00:17 +0100 (CET)
From: "Christian T. Steigies" <cts@ap031.experimentalphysik.uni-kiel.de>
Reply-To: "Christian T. Steigies" <steigies@physik.uni-kiel.de>
To: linux-m68k <linux-m68k@lists.linux-m68k.org>
Subject: Re: Ariadne2
In-Reply-To: <d3pv9t11kl.fsf@valhall.cern.ch>
Resent-From: linux-m68k@phil.uni-sb.de

On 9 Dec 1998, Jes Sorensen wrote:

> One thing that rings a bell here, the $#$#@ IRQ_MACHSPEC bit, try to
> check whether the 8390 code gets the interrupt value passed or
> truncates it somewhere (ie. cast the int to a char) .... it may cause
> some 'interesting' problems if this is the case.
With a "little" help from Michael I think I got the MACSPEC thingy (I do not
want to say I understood it...).
Current status: kernel is booting, card is detected, I guess interrupts et
al are correct (maybe I have to change more in 8390.c?), no kernel oups, 
but the network is unreachable.
The complete diff is following.

Merry Xmas,
Christian.

--- linux-2.0.36-pre1/include/asm-m68k/zorro.h.orig	Thu Dec  3 00:23:19 1998
+++ linux-2.0.36-pre1/include/asm-m68k/zorro.h	Sun Dec 13 00:53:51 1998
@@ -316,6 +316,7 @@
 #define PROD_PICASSO_IV_3      (0x17)
 #define PROD_PICASSO_IV_4      (0x18)
 #define PROD_ARIADNE           (0xC9)	/* Ariadne Ethernet */
+#define PROD_ARIADNE2          (0xCA)	/* Ariadne II Ethernet */
 
 #define MANUF_UTILITIES_ULTD   (0x087B)	/* Utilities Unlimited */
 #define PROD_EMPLANT_DELUXE    (0x15)	/* Emplant Deluxe SCSI Controller */
@@ -373,7 +374,7 @@
 
 #define MANUF_INDIVIDUAL_COMP  (0x1212)	/* Individual Computers */
 #define PROD_BUDDHA            (0x00)	/* Buddha IDE Controller */
-#define PROD_CATWEASEL         (0x42)	/* Catweasel IDE + Floppy Controller */
+#define PROD_CATWEASEL         (0x2A)	/* Catweasel IDE + Floppy Controller */
 
 #define MANUF_KUPKE3           (0x1248)	/* Kupke */
 #define PROD_GOLEM_3000        (0x01)	/* Golem HD 3000 */
--- linux-2.0.36-pre1/arch/m68k/amiga/zorro.c.orig	Thu Mar 19 20:35:26 1998
+++ linux-2.0.36-pre1/arch/m68k/amiga/zorro.c	Fri Dec  4 23:55:31 1998
@@ -426,6 +426,7 @@
    PROD("Picassio IV Graphics Board", PICASSO_IV_3)
    PROD("Picassio IV Graphics Board", PICASSO_IV_4)
    PROD("Ariadne Ethernet Card", ARIADNE)
+   PROD("Ariadne II Ethernet Card", ARIADNE2)
 END
 
 BEGIN_PROD(UTILITIES_ULTD)
--- linux-2.0.36-pre1/Documentation/Configure.help.orig	Tue Dec  1 17:32:19 1998
+++ linux-2.0.36-pre1/Documentation/Configure.help	Thu Dec  3 00:20:46 1998
@@ -4918,6 +4918,15 @@
   want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
+Ariadne II support
+CONFIG_ARIADNE2
+  If you have a VillageTronics Ariadne II Ethernet adapter, say Y.
+  Otherwise, say N.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever 
+  you want). The module is called ariadne2.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 A2065 support
 CONFIG_A2065
   If you have a Commodore A2065 Ethernet adapter, say Y.  Otherwise, say N.
--- linux-2.0.36-pre1/drivers/net/Makefile.orig	Tue Dec  1 17:33:02 1998
+++ linux-2.0.36-pre1/drivers/net/Makefile	Wed Dec  2 23:42:46 1998
@@ -591,6 +591,15 @@
   endif
 endif
 
+ifeq ($(CONFIG_ARIADNE2),y)
+L_OBJS += ariadne2.o
+CONFIG_8390_BUILTIN = y
+else
+  ifeq ($(CONFIG_ARIADNE2),m)
+  CONFIG_8390_MODULE = y
+  M_OBJS += ariadne2.o
+  endif
+endif
 
 # If anything built-in uses the 8390, then build it into the kernel also.
 # If not, but a module uses it, build as a module.
--- linux-2.0.36-pre1/drivers/net/ariadne2.c.orig	Wed Dec  2 23:57:06 1998
+++ linux-2.0.36-pre1/drivers/net/ariadne2.c	Mon Dec 21 00:15:37 1998
@@ -0,0 +1,439 @@
+/*
+ *  Amiga Linux/m68k Ariadne II Ethernet Driver
+ *
+ *  (C) Copyright 1998 by some Elitist 680x0 Users(TM)
+ *
+ *  ---------------------------------------------------------------------------
+ *
+ *  This program is based on all the other NE2000 drivers for Linux
+ *
+ *  ---------------------------------------------------------------------------
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of the Linux
+ *  distribution for more details.
+ *
+ *  ---------------------------------------------------------------------------
+ *
+ *  The Ariadne II is a Zorro-II board made by Village Tronic. It contains a
+ *  Realtek RTL8019AS Ethernet Controller.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <asm/setup.h>		/* define MACH_TYPE? */
+#include <asm/zorro.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+
+#include "8390.h"
+
+
+#define ARIADNE2_BASE		0x0300
+#define ARIADNE2_BOOTROM	0xc000
+
+#define EI_DEBUG	5
+#define ARIADNE2_DEBUG
+
+#define NE_BASE		(dev->base_addr)
+#define NE_CMD		(0x00*2)
+#define NE_DATAPORT	(0x10*2)	/* NatSemi-defined port window offset. */
+#define NE_RESET	(0x1f*2)	/* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT	(0x20*2)
+
+#define NE_EN0_ISR	(0x07*2)
+#define NE_EN0_DCFG	(0x0e*2)
+
+#define NE_EN0_RSARLO	(0x08*2)
+#define NE_EN0_RSARHI	(0x09*2)
+#define NE_EN0_RCNTLO	(0x0a*2)
+#define NE_EN0_RXCR	(0x0c*2)
+#define NE_EN0_TXCR	(0x0d*2)
+#define NE_EN0_RCNTHI	(0x0b*2)
+#define NE_EN0_IMR	(0x0f*2)
+
+#define NESM_START_PG	0x40	/* First page of TX buffer */
+#define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
+
+
+#define WORDSWAP(a)	((((a)>>8)&0xff) | ((a)<<8))
+
+int ariadne2_probe(struct device *dev);
+static int ariadne2_init(struct device *dev, unsigned int key,
+			 unsigned long board);
+
+static int ariadne2_open(struct device *dev);
+static int ariadne2_close(struct device *dev);
+
+static void ariadne2_reset_8390(struct device *dev);
+static void ariadne2_get_8390_hdr(struct device *dev,
+				  struct e8390_pkt_hdr *hdr, int ring_page);
+static void ariadne2_block_input(struct device *dev, int count,
+				 struct sk_buff *skb, int ring_offset);
+static void ariadne2_block_output(struct device *dev, const int count,
+				  const unsigned char *buf,
+				  const int start_page);
+
+
+int ariadne2_probe(struct device *dev)
+{
+    int key;
+    struct ConfigDev *cd;
+    u_long board;
+    int err;
+
+    if ((key = zorro_find(MANUF_VILLAGE_TRONIC, PROD_ARIADNE2, 0, 0))) {
+	cd = zorro_get_board(key);
+	if ((board = (u_long)cd->cd_BoardAddr)) {
+	    if ((err = ariadne2_init(dev, key, ZTWO_VADDR(board))))
+		return err;
+	    zorro_config_board(key, 0);
+	    return 0;
+	}
+    }
+    return -ENODEV;
+}
+
+static int ariadne2_init(struct device *dev, unsigned int key,
+				    unsigned long board)
+{
+    int i;
+    unsigned char SA_prom[32];
+    const char *name = NULL;
+    int start_page, stop_page;
+    static u32 ariadne2_offsets[16] = {
+	0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
+	0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
+    };
+    int ioaddr = board+ARIADNE2_BASE*2;
+
+    /* We should have a "dev" from Space.c or the static module table. */
+    if (dev == NULL) {
+	printk(KERN_ERR "ariadne2.c: Passed a NULL device.\n");
+	dev = init_etherdev(0, 0);
+    }
+
+    /* Reset card. Who knows what dain-bramaged state it was left in. */
+    {
+	unsigned long reset_start_time = jiffies;
+
+	writeb(readb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+	while ((readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
+	    if (jiffies - reset_start_time > 2*HZ/100) {
+		printk(" not found (no reset ack).\n");
+		return -ENODEV;
+	    }
+
+	writeb(0xff, ioaddr + NE_EN0_ISR);		/* Ack all intr. */
+    }
+
+    /* Read the 16 bytes of station address PROM.
+       We must first initialize registers, similar to NS8390_init(eifdev, 0).
+       We can't reliably read the SAPROM address without this.
+       (I learned the hard way!). */
+    {
+	struct {
+	    u32 value;
+	    u32 offset;
+	} program_seq[] = {
+	    {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/
+	    {0x48,	NE_EN0_DCFG},	/* Set byte-wide (0x48) access. */
+	    {0x00,	NE_EN0_RCNTLO},	/* Clear the count regs. */
+	    {0x00,	NE_EN0_RCNTHI},
+	    {0x00,	NE_EN0_IMR},	/* Mask completion irq. */
+	    {0xFF,	NE_EN0_ISR},
+	    {E8390_RXOFF, NE_EN0_RXCR},	/* 0x20  Set to monitor */
+	    {E8390_TXOFF, NE_EN0_TXCR},	/* 0x02  and loopback mode. */
+	    {32,	NE_EN0_RCNTLO},
+	    {0x00,	NE_EN0_RCNTHI},
+	    {0x00,	NE_EN0_RSARLO},	/* DMA starting at 0x0000. */
+	    {0x00,	NE_EN0_RSARHI},
+	    {E8390_RREAD+E8390_START, NE_CMD},
+	};
+	for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
+	    writeb(program_seq[i].value, ioaddr + program_seq[i].offset);
+	}
+    }
+    for (i = 0; i < 16; i++) {
+	SA_prom[i] = readb(ioaddr + NE_DATAPORT);
+	(void)readb(ioaddr + NE_DATAPORT);
+    }
+
+    /* We must set the 8390 for word mode. */
+    writeb(0x49, ioaddr + NE_EN0_DCFG);
+    start_page = NESM_START_PG;
+    stop_page = NESM_STOP_PG;
+
+    name = "NE2000";
+
+    dev->base_addr = ioaddr;
+    dev->irq = (unsigned short) (IRQ_AMIGA_PORTS & 0xff); /* whatever IRQ, WITHOUT THE *?! IRQ_MACHSPEC BIT */
+    printk("irq2dev_map[%i] = %i\n", (dev->irq & 0xff), dev);
+    printk("dev->base_addr:%i  dev->irq:%i\n", dev->base_addr, dev->irq);
+
+    irq2dev_map[dev->irq] = dev; 
+    /* array contains only 16 elements, so here without the IRQ_MACHSPEC bit */
+
+    /* Install the Interrupt handler */
+    if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, 0, "AriadNE2 Ethernet", dev))
+    /* request_irq has to be called with IRQ_MACHSPEC bit, otherwise arch/m68k/kernel/ints.c barfs:
+       request_irq: Incorrect IRQ 12 from AriadNE2 Ethernet
+    */
+    {
+        dev->irq = 0; /* Michael's guess... */
+        irq2dev_map[dev->irq] = NULL; 
+	return -EAGAIN;
+    }
+
+    /* Allocate dev->priv and fill in 8390 specific dev fields. */
+    if (ethdev_init(dev)) {
+	printk("Unable to get memory for dev->priv.\n");
+	return -ENOMEM;
+    }
+
+    ((struct ei_device *)dev->priv)->priv = key; /* structure has no member named 'priv' */
+
+    for(i = 0; i < ETHER_ADDR_LEN; i++) {
+	printk(" %2.2x", SA_prom[i]);
+	dev->dev_addr[i] = SA_prom[i];
+    } /* do we have to print the address twice? */
+
+    printk("\n%s: AriadNE2 at 0x%08lx, Ethernet Address "
+	   "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board,
+	   dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+	   dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+    ei_status.name = name;
+    ei_status.tx_start_page = start_page;
+    ei_status.stop_page = stop_page;
+    ei_status.word16 = 1;
+
+    ei_status.rx_start_page = start_page + TX_PAGES;
+
+    ei_status.reset_8390 = &ariadne2_reset_8390;
+    ei_status.block_input = &ariadne2_block_input;
+    ei_status.block_output = &ariadne2_block_output;
+    ei_status.get_8390_hdr = &ariadne2_get_8390_hdr;
+    ei_status.reg_offset = ariadne2_offsets; /* structure has no member named 'reg_offset' */
+
+    dev->open = &ariadne2_open;
+    dev->stop = &ariadne2_close;
+    NS8390_init(dev, 0);
+
+    return 0;
+}
+
+static int ariadne2_open(struct device *dev)
+{
+    ei_open(dev);
+    MOD_INC_USE_COUNT;
+    return 0;
+}
+
+static int ariadne2_close(struct device *dev)
+{
+    if (ei_debug > 1)
+	printk("%s: Shutting down ethercard.\n", dev->name);
+    ei_close(dev);
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+/* Hard reset the card.  This used to pause for the same period that a
+   8390 reset command required, but that shouldn't be necessary. */
+static void ariadne2_reset_8390(struct device *dev)
+{
+    unsigned long reset_start_time = jiffies;
+
+    if (ei_debug > 1)
+	printk("resetting the 8390 t=%ld...", jiffies);
+
+    writeb(readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+    ei_status.txing = 0;
+    ei_status.dmaing = 0;
+
+    /* This check _should_not_ be necessary, omit eventually. */
+    while ((readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
+	if (jiffies - reset_start_time > 2*HZ/100) {
+	    printk("%s: ne_reset_8390() did not complete.\n", dev->name);
+	    break;
+	}
+    writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR);	/* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+   we don't need to be concerned with ring wrap as the header will be at
+   the start of a page, so we optimize accordingly. */
+
+static void ariadne2_get_8390_hdr(struct device *dev,
+				  struct e8390_pkt_hdr *hdr, int ring_page)
+{
+    int nic_base = dev->base_addr;
+    int cnt;
+    short *ptrs;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+	printk("%s: DMAing conflict in ne_get_8390_hdr "
+	   "[DMAstat:%d][irqlock:%d][intr:%ld].\n", dev->name, ei_status.dmaing,
+	   ei_status.irqlock, dev->interrupt);
+	return;
+    }
+
+    ei_status.dmaing |= 0x01;
+    writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+    writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
+    writeb(0, nic_base + NE_EN0_RCNTHI);
+    writeb(0, nic_base + NE_EN0_RSARLO);		/* On page boundary */
+    writeb(ring_page, nic_base + NE_EN0_RSARHI);
+    writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+    ptrs = (short*)hdr;
+    for (cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)
+	*ptrs++ = readw(NE_BASE + NE_DATAPORT);
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+
+    hdr->count = WORDSWAP(hdr->count);
+
+    ei_status.dmaing &= ~0x01;
+}
+
+/* Block input and output, similar to the Crynwr packet driver.  If you
+   are porting to a new ethercard, look at the packet driver source for hints.
+   The NEx000 doesn't share the on-board packet memory -- you have to put
+   the packet out through the "remote DMA" dataport using writeb. */
+
+static void ariadne2_block_input(struct device *dev, int count,
+				 struct sk_buff *skb, int ring_offset)
+{
+    int nic_base = dev->base_addr;
+    char *buf = skb->data;
+    short *ptrs;
+    int cnt;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+	printk("%s: DMAing conflict in ne_block_input "
+	   "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
+	   dev->name, ei_status.dmaing, ei_status.irqlock,
+	   dev->interrupt);
+	return;
+    }
+    ei_status.dmaing |= 0x01;
+    writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+    writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+    writeb(count >> 8, nic_base + NE_EN0_RCNTHI);
+    writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
+    writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
+    writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+    ptrs = (short*)buf;
+    for (cnt = 0; cnt < (count>>1); cnt++)
+	*ptrs++ = readw(NE_BASE + NE_DATAPORT);
+    if (count & 0x01)
+	buf[count-1] = readb(NE_BASE + NE_DATAPORT);
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+}
+
+static void ariadne2_block_output(struct device *dev, int count,
+				  const unsigned char *buf,
+				  const int start_page)
+{
+    int nic_base = NE_BASE;
+    unsigned long dma_start;
+    short *ptrs;
+    int cnt;
+
+    /* Round the count up for word writes.  Do we need to do this?
+       What effect will an odd byte count have on the 8390?
+       I should check someday. */
+    if (count & 0x01)
+	count++;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+	printk("%s: DMAing conflict in ne_block_output."
+	   "[DMAstat:%d][irqlock:%d][intr:%ld]\n", dev->name, ei_status.dmaing,
+	   ei_status.irqlock, dev->interrupt);
+	return;
+    }
+    ei_status.dmaing |= 0x01;
+    /* We should already be in page 0, but to be safe... */
+    writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+
+   /* Now the normal output. */
+    writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+    writeb(count >> 8,   nic_base + NE_EN0_RCNTHI);
+    writeb(0x00, nic_base + NE_EN0_RSARLO);
+    writeb(start_page, nic_base + NE_EN0_RSARHI);
+
+    writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+    ptrs = (short*)buf;
+    for (cnt = 0; cnt < count>>1; cnt++)
+	writew(*ptrs++, NE_BASE+NE_DATAPORT);
+
+    dma_start = jiffies;
+
+    while ((readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
+	if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
+		printk("%s: timeout waiting for Tx RDC.\n", dev->name);
+		ariadne2_reset_8390(dev);
+		NS8390_init(dev,1);
+		break;
+	}
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+    return;
+}
+
+#ifdef MODULE
+static char devicename[9] = { 0, };
+
+static struct device ariadne2_dev =
+{
+    devicename,
+    0, 0, 0, 0,
+    0, 0,
+    0, 0, 0, NULL, ariadne2_probe,
+};
+
+int init_module(void)
+{
+    int err;
+    if ((err = register_netdev(&ariadne2_dev))) {
+	if (err == -EIO)
+	    printk("No AriadNE2 ethernet card found.\n");
+	return err;
+    }
+    lock_8390_module();
+    return 0;
+}
+
+void cleanup_module(void)
+{
+    unsigned int key = ((struct ei_device *)ariadne2_dev.priv)->priv;
+    free_irq(IRQ_AMIGA_PORTS, &ariadne2_dev);
+    unregister_netdev(&ariadne2_dev);
+    zorro_config_board(key, 0);
+    unlock_8390_module();
+}
+
+#endif	/* MODULE */
--- linux-2.0.36-pre1/drivers/net/Space.c.orig	Tue Dec  1 17:33:03 1998
+++ linux-2.0.36-pre1/drivers/net/Space.c	Sat Dec  5 10:21:34 1998
@@ -81,6 +81,7 @@
 extern int a2065_probe(struct device *);
 extern int apne_probe(struct device *);
 extern int ariadne_probe(struct device *);
+extern int ariadne2_probe(struct device *);
 extern int hydra_probe(struct device *);
 extern int bionet_probe(struct device *);
 extern int pamsnet_probe(struct device *);
@@ -259,6 +260,9 @@
 #endif
 #ifdef CONFIG_ARIADNE		/* Village Tronic Ariadne Ethernet Board */
 	&& ariadne_probe(dev)
+#endif
+#ifdef CONFIG_ARIADNE2		/* Village Tronic Ariadne II Ethernet Board */
+	&& ariadne2_probe(dev)
 #endif
 #ifdef CONFIG_HYDRA		/* Hydra Systems Amiganet Ethernet board */
 	&& hydra_probe(dev)
--- linux-2.0.36-pre1/drivers/net/8390.h.orig	Thu Dec  3 00:30:15 1998
+++ linux-2.0.36-pre1/drivers/net/8390.h	Sun Dec 13 01:00:44 1998
@@ -25,6 +25,8 @@
 
 #define ETHER_ADDR_LEN 6
 
+#define net_device_stats	enet_statistics
+
 /* The 8390 specific per-packet-header format. */
 struct e8390_pkt_hdr {
   unsigned char status; /* status */
@@ -59,6 +61,7 @@
   void (*get_8390_hdr)(struct device *, struct e8390_pkt_hdr *, int);
   void (*block_output)(struct device *, int, const unsigned char *, int);
   void (*block_input)(struct device *, int, struct sk_buff *, int);
+  unsigned char mcfilter[8];
   unsigned open:1;
   unsigned word16:1;  /* We have the 16-bit (vs 8-bit) version of the card. */
   unsigned txing:1;		/* Transmit Active */
@@ -75,6 +78,8 @@
   unsigned char saved_irq;	/* Original dev->irq value. */
   /* The new statistics table. */
   struct enet_statistics stat;
+  u32 *reg_offset;		/* Register mapping table */
+  unsigned long priv;		/* Private field to store bus IDs etc. */
 };
 
 /* The maximum number of 8390 interrupt service routines called per IRQ. */
@@ -104,34 +109,41 @@
 #define E8390_PAGE1	0x40	/* using the two high-order bits */
 #define E8390_PAGE2	0x80	/* Page 3 is invalid. */
 
-#define E8390_CMD	0x00	/* The command register (for all pages) */
+#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \
+    defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE)
+#define EI_SHIFT(x)	(ei_local->reg_offset[x])
+#else
+#define EI_SHIFT(x)	(x)
+#endif
+
+#define E8390_CMD	EI_SHIFT(0x00)  /* The command register (for all pages) */
 /* Page 0 register offsets. */
-#define EN0_CLDALO	0x01	/* Low byte of current local dma addr  RD */
-#define EN0_STARTPG	0x01	/* Starting page of ring bfr WR */
-#define EN0_CLDAHI	0x02	/* High byte of current local dma addr  RD */
-#define EN0_STOPPG	0x02	/* Ending page +1 of ring bfr WR */
-#define EN0_BOUNDARY	0x03	/* Boundary page of ring bfr RD WR */
-#define EN0_TSR		0x04	/* Transmit status reg RD */
-#define EN0_TPSR	0x04	/* Transmit starting page WR */
-#define EN0_NCR		0x05	/* Number of collision reg RD */
-#define EN0_TCNTLO	0x05	/* Low  byte of tx byte count WR */
-#define EN0_FIFO	0x06	/* FIFO RD */
-#define EN0_TCNTHI	0x06	/* High byte of tx byte count WR */
-#define EN0_ISR		0x07	/* Interrupt status reg RD WR */
-#define EN0_CRDALO	0x08	/* low byte of current remote dma address RD */
-#define EN0_RSARLO	0x08	/* Remote start address reg 0 */
-#define EN0_CRDAHI	0x09	/* high byte, current remote dma address RD */
-#define EN0_RSARHI	0x09	/* Remote start address reg 1 */
-#define EN0_RCNTLO	0x0a	/* Remote byte count reg WR */
-#define EN0_RCNTHI	0x0b	/* Remote byte count reg WR */
-#define EN0_RSR		0x0c	/* rx status reg RD */
-#define EN0_RXCR	0x0c	/* RX configuration reg WR */
-#define EN0_TXCR	0x0d	/* TX configuration reg WR */
-#define EN0_COUNTER0	0x0d	/* Rcv alignment error counter RD */
-#define EN0_DCFG	0x0e	/* Data configuration reg WR */
-#define EN0_COUNTER1	0x0e	/* Rcv CRC error counter RD */
-#define EN0_IMR		0x0f	/* Interrupt mask reg WR */
-#define EN0_COUNTER2	0x0f	/* Rcv missed frame error counter RD */
+#define EN0_CLDALO	EI_SHIFT(0x01)	/* Low byte of current local dma addr  RD */
+#define EN0_STARTPG	EI_SHIFT(0x01)	/* Starting page of ring bfr WR */
+#define EN0_CLDAHI	EI_SHIFT(0x02)	/* High byte of current local dma addr  RD */
+#define EN0_STOPPG	EI_SHIFT(0x02)	/* Ending page +1 of ring bfr WR */
+#define EN0_BOUNDARY	EI_SHIFT(0x03)	/* Boundary page of ring bfr RD WR */
+#define EN0_TSR		EI_SHIFT(0x04)	/* Transmit status reg RD */
+#define EN0_TPSR	EI_SHIFT(0x04)	/* Transmit starting page WR */
+#define EN0_NCR		EI_SHIFT(0x05)	/* Number of collision reg RD */
+#define EN0_TCNTLO	EI_SHIFT(0x05)	/* Low  byte of tx byte count WR */
+#define EN0_FIFO	EI_SHIFT(0x06)	/* FIFO RD */
+#define EN0_TCNTHI	EI_SHIFT(0x06)	/* High byte of tx byte count WR */
+#define EN0_ISR		EI_SHIFT(0x07)	/* Interrupt status reg RD WR */
+#define EN0_CRDALO	EI_SHIFT(0x08)	/* low byte of current remote dma address RD */
+#define EN0_RSARLO	EI_SHIFT(0x08)	/* Remote start address reg 0 */
+#define EN0_CRDAHI	EI_SHIFT(0x09)	/* high byte, current remote dma address RD */
+#define EN0_RSARHI	EI_SHIFT(0x09)	/* Remote start address reg 1 */
+#define EN0_RCNTLO	EI_SHIFT(0x0a)	/* Remote byte count reg WR */
+#define EN0_RCNTHI	EI_SHIFT(0x0b)	/* Remote byte count reg WR */
+#define EN0_RSR		EI_SHIFT(0x0c)	/* rx status reg RD */
+#define EN0_RXCR	EI_SHIFT(0x0c)	/* RX configuration reg WR */
+#define EN0_TXCR	EI_SHIFT(0x0d)	/* TX configuration reg WR */
+#define EN0_COUNTER0	EI_SHIFT(0x0d)	/* Rcv alignment error counter RD */
+#define EN0_DCFG	EI_SHIFT(0x0e)	/* Data configuration reg WR */
+#define EN0_COUNTER1	EI_SHIFT(0x0e)	/* Rcv CRC error counter RD */
+#define EN0_IMR		EI_SHIFT(0x0f)	/* Interrupt mask reg WR */
+#define EN0_COUNTER2	EI_SHIFT(0x0f)	/* Rcv missed frame error counter RD */
 
 /* Bits in EN0_ISR - Interrupt status register */
 #define ENISR_RX	0x01	/* Receiver, no error */
@@ -148,9 +160,11 @@
 #define ENDCFG_WTS	0x01	/* word transfer mode selection */
 
 /* Page 1 register offsets. */
-#define EN1_PHYS   0x01	/* This board's physical enet addr RD WR */
-#define EN1_CURPAG 0x07	/* Current memory page RD WR */
-#define EN1_MULT   0x08	/* Multicast filter mask array (8 bytes) RD WR */
+#define EN1_PHYS   EI_SHIFT(0x01)	/* This board's physical enet addr RD WR */
+#define EN1_PHYS_SHIFT(i)  EI_SHIFT(i+1) /* Get and set mac address */
+#define EN1_CURPAG EI_SHIFT(0x07)	/* Current memory page RD WR */
+#define EN1_MULT   EI_SHIFT(0x08)	/* Multicast filter mask array (8 bytes) RD WR */
+#define EN1_MULT_SHIFT(i)  EI_SHIFT(8+i) /* Get and set multicast filter */
 
 /* Bits in received packet status byte and EN0_RSR*/
 #define ENRSR_RXOK	0x01	/* Received a good packet */
@@ -158,7 +172,7 @@
 #define ENRSR_FAE	0x04	/* frame alignment error */
 #define ENRSR_FO	0x08	/* FIFO overrun */
 #define ENRSR_MPA	0x10	/* missed pkt */
-#define ENRSR_PHY	0x20	/* physical/multicase address */
+#define ENRSR_PHY	0x20	/* physical/multicast address */
 #define ENRSR_DIS	0x40	/* receiver disable. set in monitor mode */
 #define ENRSR_DEF	0x80	/* deferring */
 
--- linux-2.0.36-pre1/drivers/net/8390.c.orig	Sat Oct  5 15:24:56 1996
+++ linux-2.0.36-pre1/drivers/net/8390.c	Mon Dec 21 00:39:00 1998
@@ -40,6 +40,7 @@
 static const char *version =
     "8390.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -284,13 +285,13 @@
    Handle the ether interface interrupts. */
 void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-    struct device *dev = (struct device *)(irq2dev_map[irq]);
+    struct device *dev = (struct device *)(irq2dev_map[(irq & 0xff)]);
     int e8390_base;
     int interrupts, nr_serviced = 0;
     struct ei_device *ei_local;
     
     if (dev == NULL) {
-		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+		printk ("net_interrupt(): irq %d for unknown device.\n", (irq & 0xff));
 		return;
     }
     e8390_base = dev->base_addr;
@@ -376,9 +377,9 @@
 static void ei_tx_err(struct device *dev)
 {
     int e8390_base = dev->base_addr;
+    struct ei_device *ei_local = (struct ei_device *) dev->priv;
     unsigned char txsr = inb_p(e8390_base+EN0_TSR);
     unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
-    struct ei_device *ei_local = (struct ei_device *) dev->priv;
 
 #ifdef VERBOSE_ERROR_DUMP
     printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
@@ -414,8 +415,8 @@
 static void ei_tx_intr(struct device *dev)
 {
     int e8390_base = dev->base_addr;
-    int status = inb(e8390_base + EN0_TSR);
     struct ei_device *ei_local = (struct ei_device *) dev->priv;
+    int status = inb(e8390_base + EN0_TSR);
     
     outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
 
@@ -520,6 +521,11 @@
 		current_offset = this_frame << 8;
 		ei_get_8390_hdr(dev, &rx_frame, this_frame);
 		
+#if 0
+		printk("RXF: status=%d, next=%d, count=%d\n",
+			rx_frame.status, rx_frame.next, rx_frame.count);
+#endif
+
 		pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
 		
 		next_frame = this_frame + 1 + ((pkt_len+4)>>8);
@@ -558,6 +564,18 @@
 				skb->dev = dev;
 				skb_put(skb, pkt_len);	/* Make room */
 				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
+#if 0
+				{
+					int z=0;
+					while(z<skb->len)
+					{
+						printk("%X."(unsigned int)skb->data[z]);
+						if(z%24==0)
+							printk("\n");
+						z++;
+					}
+				}
+#endif
 				skb->protocol=eth_type_trans(skb,dev);
 				netif_rx(skb);
 				ei_local->stat.rx_packets++;
@@ -663,7 +681,7 @@
 
 static struct enet_statistics *get_stats(struct device *dev)
 {
-    short ioaddr = dev->base_addr;
+    int ioaddr = dev->base_addr;
     struct ei_device *ei_local = (struct ei_device *) dev->priv;
     
     /* If the card is stopped, just return the present stats. */
@@ -683,7 +701,8 @@
  
 static void set_multicast_list(struct device *dev)
 {
-	short ioaddr = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	int ioaddr = dev->base_addr;
     
 	if(dev->flags&IFF_PROMISC)
 	{
@@ -735,8 +754,10 @@
     int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
     unsigned long flags;
     
+    if(sizeof(struct e8390_pkt_hdr)!=4)
+       panic("8390.c: header struct mispacked\n");
     /* Follow National Semi's recommendations for initing the DP83902. */
-    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base); /* 0x21 */
+    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
     outb_p(endcfg, e8390_base + EN0_DCFG);	/* 0x48 or 0x49 */
     /* Clear the remote byte count registers. */
     outb_p(0x00,  e8390_base + EN0_RCNTLO);
@@ -759,9 +780,11 @@
        and set the multicast hash bitmap to receive all multicasts. */
     save_flags(flags);
     cli();
-    outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base); /* 0x61 */
+    outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
     for(i = 0; i < 6; i++) {
-		outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS + i);
+		outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
+		if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
+			printk("Read/write mismap %d\n",i);
     }
     /* Initialize the multicast list to accept-all.  If we enable multicast
        the higher levels can do the filtering. */
@@ -769,7 +792,7 @@
 		outb_p(0xff, e8390_base + EN1_MULT + i);
     
     outb_p(ei_local->rx_start_page,	 e8390_base + EN1_CURPAG);
-    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
+    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
     restore_flags(flags);
     dev->tbusy = 0;
     dev->interrupt = 0;
@@ -778,7 +801,7 @@
     if (startp) {
 		outb_p(0xff,  e8390_base + EN0_ISR);
 		outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
-		outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base);
+		outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
 		outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
 		/* 3c503 TechMan says rxconfig only after the NIC is started. */
 		outb_p(E8390_RXCONFIG,	e8390_base + EN0_RXCR); /* rx on,  */
@@ -792,9 +815,10 @@
 static void NS8390_trigger_send(struct device *dev, unsigned int length,
 								int start_page)
 {
+    struct ei_device *ei_local = (struct ei_device *) dev->priv;
     int e8390_base = dev->base_addr;
     
-    outb_p(E8390_NODMA+E8390_PAGE0, e8390_base);
+    outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
     
     if (inb_p(e8390_base) & E8390_TRANS) {
 		printk("%s: trigger_send() called with the transmitter busy.\n",
@@ -804,7 +828,7 @@
     outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
     outb_p(length >> 8, e8390_base + EN0_TCNTHI);
     outb_p(start_page, e8390_base + EN0_TPSR);
-    outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base);
+    outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
     return;
 }
 

