patch-2.3.42 linux/drivers/net/daynaport.c

Next file: linux/drivers/net/irda/Config.in
Previous file: linux/drivers/net/cs89x0.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.41/linux/drivers/net/daynaport.c linux/drivers/net/daynaport.c
@@ -1,4 +1,4 @@
-/* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */
+/* daynaport.c: A Macintosh 8390 based ethernet driver for linux. */
 /*
 	Derived from code:
 	
@@ -15,14 +15,20 @@
 	    The block output routines may be wrong for non Dayna
 	    cards
 
-	    Reading MAC addresses
-*/
+		Fix this driver so that it will attempt to use the info
+		(i.e. iobase, iosize) given to it by the new and improved
+		NuBus code.
+
+		Despite its misleading filename, this driver is not Dayna-specific
+		anymore. */
+/* Cabletron E6100 card support added by Tony Mantler (eek@escape.ca) April 1999 */
 
 static const char *version =
-	"mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n";
+	"daynaport.c: v0.02 1999-05-17 Alan Cox (Alan.Cox@linux.org) and others\n";
+static int version_printed = 0;
 
 #include <linux/module.h>
-
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -31,20 +37,26 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/hwtest.h>
+#include <asm/macints.h>
 #include <linux/delay.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include "8390.h"
 
-int ns8390_probe1(struct net_device *dev, int word16, char *name, int id, int prom);
+extern int console_loglevel;
+
+int ns8390_probe1(struct net_device *dev, int word16, char *name, int id,
+				  int prom, struct nubus_dev *ndev);
 
 static int ns8390_open(struct net_device *dev);
 static void ns8390_no_reset(struct net_device *dev);
 static int ns8390_close_card(struct net_device *dev);
 
+/* Interlan */
 static void interlan_reset(struct net_device *dev);
 
+/* Dayna */
 static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 						int ring_page);
 static void dayna_block_input(struct net_device *dev, int count,
@@ -52,6 +64,7 @@
 static void dayna_block_output(struct net_device *dev, int count,
 						   const unsigned char *buf, const int start_page);
 
+/* Sane (32-bit chunk memory read/write) */
 static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 						int ring_page);
 static void sane_block_input(struct net_device *dev, int count,
@@ -59,6 +72,7 @@
 static void sane_block_output(struct net_device *dev, int count,
 						   const unsigned char *buf, const int start_page);
 
+/* Slow Sane (16-bit chunk memory read/write) */
 static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 						int ring_page);
 static void slow_sane_block_input(struct net_device *dev, int count,
@@ -71,6 +85,10 @@
 #define WD03_STOP_PG	0x20	/* Last page +1 of RX ring */
 #define WD13_STOP_PG	0x40	/* Last page +1 of RX ring */
 
+#define CABLETRON_RX_START_PG          0x00    /* First page of RX buffer */
+#define CABLETRON_RX_STOP_PG           0x30    /* Last page +1 of RX ring */
+#define CABLETRON_TX_START_PG          CABLETRON_RX_STOP_PG  /* First page of TX buffer */
+
 
 #define DAYNA_MAC_BASE		0xf0007
 #define DAYNA_8390_BASE		0x80000 /* 3 */
@@ -81,9 +99,14 @@
 #define APPLE_8390_MEM		0xD0000
 #define APPLE_MEMSIZE		8192    /* FIXME: need to dynamically check */
 
-#define KINETICS_8390_BASE	0x80003
-#define KINETICS_8390_MEM	0x00000
+#define KINETICS_MAC_BASE	0xf0004 /* first byte of each long */
+#define KINETICS_8390_BASE	0x80000
+#define KINETICS_8390_MEM	0x00000 /* first word of each long */
 #define KINETICS_MEMSIZE	8192    /* FIXME: need to dynamically check */
+/*#define KINETICS_MEMSIZE	(0x10000/2) * CSA: on the board I have, at least */
+
+#define CABLETRON_8390_BASE		0x90000	
+#define CABLETRON_8390_MEM		0x00000
 
 static int test_8390(volatile char *ptr, int scale)
 {
@@ -113,34 +136,59 @@
  *    Identify the species of NS8390 card/driver we need
  */
 
-#define NS8390_DAYNA		1
-#define NS8390_INTERLAN		2
-#define NS8390_KINETICS		3
-#define NS8390_APPLE		4
-#define NS8390_FARALLON		5
-#define NS8390_ASANTE		6
-
-int ns8390_ident(struct nubus_type *nb)
-{
-	/* It appears anything with a software type of 0 is an apple
-	   compatible - even if the hardware matches others */
-	   
-	if(nb->DrSW==0x0001 || nb->DrSW==0x0109 || nb->DrSW==0x0000 || nb->DrSW==0x0100)
-		return NS8390_APPLE;
-	
+enum mac8390_type {
+	NS8390_DAYNA,
+	NS8390_INTERLAN,
+	NS8390_KINETICS,
+	NS8390_APPLE,
+	NS8390_FARALLON,
+	NS8390_ASANTE,
+	NS8390_CABLETRON
+};
+
+int __init ns8390_ident(struct nubus_dev* ndev)
+{
+	/* This really needs to be tested and tested hard.  */
+		
+	/* Summary of what we know so far --
+	 * SW: 0x0104 -- asante,    16 bit, back4_offsets
+	 * SW: 0x010b -- daynaport, 16 bit, fwrd4_offsets
+	 * SW: 0x010c -- farallon,  16 bit, back4_offsets, no long word access
+	 * SW: 0x011a -- focus,     [no details yet]
+	 * SW: ?????? -- interlan,  16 bit, back4_offsets, funny reset
+	 * SW: ?????? -- kinetics,   8 bit, back4_offsets
+	 * -- so i've this hypothesis going that says DrSW&1 says whether the
+	 *    map is forward or backwards -- and maybe DrSW&256 says what the
+	 *    register spacing is -- for all cards that report a DrSW in some
+	 *    range.
+	 *    This would allow the "apple compatible" driver to drive many
+	 *    seemingly different types of cards.  More DrSW info is needed
+	 *    to investigate this properly. [CSA, 21-May-1999]
+	 */
 	/* Dayna ex Kinetics board */
-	if(nb->DrHW==0x0103)
+	if(ndev->dr_sw == NUBUS_DRSW_DAYNA)
 		return NS8390_DAYNA;
-
-	/* Asante board */
-	if(nb->DrHW==0x0104)
+	if(ndev->dr_sw == NUBUS_DRSW_ASANTE)
 		return NS8390_ASANTE;
-	if(nb->DrHW==0x0100)
-		return NS8390_INTERLAN;
-	if(nb->DrHW==0x0106)
-		return NS8390_KINETICS;
-	if(nb->DrSW==0x010C)
+	if(ndev->dr_sw == NUBUS_DRSW_FARALLON) /* farallon or sonic systems */
 		return NS8390_FARALLON;
+	if(ndev->dr_sw == NUBUS_DRSW_KINETICS)
+		return NS8390_KINETICS;
+	/* My ATI Engineering card with this combination crashes the */
+	/* driver trying to xmit packets. Best not touch it for now. */
+	/*     - 1999-05-20 (funaho@jurai.org)                       */
+	if(ndev->dr_sw == NUBUS_DRSW_FOCUS)
+		return -1;
+
+	/* Check the HW on this one, because it shares the same DrSW as
+	   the on-board SONIC chips */
+	if(ndev->dr_hw == NUBUS_DRHW_CABLETRON)
+		return NS8390_CABLETRON;
+	/* does anyone have one of these? */
+	if(ndev->dr_hw == NUBUS_DRHW_INTERLAN)
+		return NS8390_INTERLAN;
+
+	/* FIXME: what do genuine Apple boards look like? */
 	return -1;
 }
 
@@ -148,7 +196,7 @@
  *	Memory probe for 8390 cards
  */
  
-int apple_8390_mem_probe(volatile unsigned short *p)
+int __init apple_8390_mem_probe(volatile unsigned short *p)
 {
 	int i, j;
 	/*
@@ -192,61 +240,79 @@
 /*
  *    Probe for 8390 cards.  
  *    The ns8390_probe1() routine initializes the card and fills the
- *    station address field. On entry base_addr is set, irq is set
- *    (These come from the nubus probe code). dev->mem_start points
+ *    station address field.
+ *
+ *    The NuBus interface has changed!  We now scan for these somewhat
+ *    like how the PCI and Zorro drivers do.  It's not clear whether
+ *    this is actually better, but it makes things more consistent.
+ *
+ *    dev->mem_start points
  *    at the memory ring, dev->mem_end gives the end of it.
  */
 
-int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *match)
+int __init mac8390_probe(struct net_device *dev)
 {
-	struct net_device *dev;
+	static int slots = 0;
 	volatile unsigned short *i;
 	volatile unsigned char *p;
 	int plen;
 	int id;
+	static struct nubus_dev* ndev = NULL;
 
-	if(match->category!=NUBUS_CAT_NETWORK || match->type!=1)
-		return -ENODEV;		
-	/* Ok so it is an ethernet network device */
-	if((id=ns8390_ident(match))==-1)
-	{
-		printk("Ethernet but type unknown %d\n",match->DrHW);
+	/* Find the first card that hasn't already been seen */
+	while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
+								   NUBUS_TYPE_ETHERNET, ndev)) != NULL) {
+		/* Have we seen it already? */
+		if (slots & (1<<ndev->board->slot))
+			continue;
+		slots |= 1<<ndev->board->slot;
+
+		/* Is it one of ours? */
+		if ((id = ns8390_ident(ndev)) != -1)
+			break;
+	}
+
+	/* Hm.  No more cards, then */
+	if (ndev == NULL)
 		return -ENODEV;
+
+	dev = init_etherdev(dev, 0);
+
+	if (!version_printed) {
+		printk(KERN_INFO "%s", version);
+		version_printed = 1;
 	}
-	dev = init_etherdev(0, 0);
-	if(dev==NULL)
-		return -ENOMEM;
 
 	/*
 	 *	Dayna specific init
 	 */
 	if(id==NS8390_DAYNA)
 	{
-		dev->base_addr=(int)(nubus_slot_addr(slot)+DAYNA_8390_BASE);
-		dev->mem_start=(int)(nubus_slot_addr(slot)+DAYNA_8390_MEM);
-		dev->mem_end=dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
+		dev->base_addr = (int)(ndev->board->slot_addr+DAYNA_8390_BASE);
+		dev->mem_start = (int)(ndev->board->slot_addr+DAYNA_8390_MEM);
+		dev->mem_end = dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
 	
-		printk("daynaport: testing board: ");
-
+		printk(KERN_INFO "%s: daynaport. testing board: ", dev->name);
+			
 		printk("memory - ");	
-	
-		i=(void *)dev->mem_start;
+			
+		i = (void *)dev->mem_start;
 		memset((void *)i,0xAA, DAYNA_MEMSIZE);
 		while(i<(volatile unsigned short *)dev->mem_end)
 		{
 			if(*i!=0xAAAA)
 				goto membad;
-			*i=0x5555;
-			if(*i!=0x5555)
+			*i=0x5678; /* make sure we catch byte smearing */
+			if(*i!=0x5678)
 				goto membad;
 			i+=2;	/* Skip a word */
 		}
-
+			
 		printk("controller - ");
-	
+			
 		p=(void *)dev->base_addr;
 		plen=0;
-	
+			
 		while(plen<0x3FF00)
 		{
 			if(test_8390(p,0)==0)
@@ -263,26 +329,71 @@
 		if(plen==0x3FF00)
 			goto membad;
 		printk("OK\n");
-		dev->irq=slot;
-		if(ns8390_probe1(dev, 0, "dayna", id, -1)==0)
-		return 0;
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+		if(ns8390_probe1(dev, 0, "dayna", id, -1, ndev)==0)
+			return 0;
+	}
+	/* Cabletron */
+	if (id==NS8390_CABLETRON) {
+		int memsize = 16<<10; /* fix this */
+		  
+		dev->base_addr=(int)(ndev->board->slot_addr+CABLETRON_8390_BASE);
+		dev->mem_start=(int)(ndev->board->slot_addr+CABLETRON_8390_MEM);
+		dev->mem_end=dev->mem_start+memsize;
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+		  
+		/* The base address is unreadable if 0x00 has been written to the command register */
+		/* Reset the chip by writing E8390_NODMA+E8390_PAGE0+E8390_STOP just to be sure */
+		i = (void *)dev->base_addr;
+		*i = 0x21;
+		  
+		printk(KERN_INFO "%s: cabletron: testing board: ", dev->name);
+		printk("%dK memory - ", memsize>>10);		
+		i=(void *)dev->mem_start;
+		while(i<(volatile unsigned short *)(dev->mem_start+memsize))
+		{
+			*i=0xAAAA;
+			if(*i!=0xAAAA)
+				goto membad;
+			*i=0x5555;
+			if(*i!=0x5555)
+				goto membad;
+			i+=2;	/* Skip a word */
+		}
+		printk("OK\n");
+		  
+		if(ns8390_probe1(dev, 1, "cabletron", id, -1, ndev)==0)
+			return 0;
 	}
 	/* Apple, Farallon, Asante */
-	if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE)
+	if(id==NS8390_APPLE || id==NS8390_FARALLON || id==NS8390_ASANTE)
 	{
 		int memsize;
-		
-		dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
-		dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
-		
+			
+		dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
+		dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
+			
 		memsize = apple_8390_mem_probe((void *)dev->mem_start);
-		
+			
 		dev->mem_end=dev->mem_start+memsize;
-		dev->irq=slot;
-		printk("apple/clone: testing board: ");
-
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+			
+		switch(id)
+		{
+		case NS8390_FARALLON:
+			printk(KERN_INFO "%s: farallon: testing board: ", dev->name);
+			break;
+		case NS8390_ASANTE:
+			printk(KERN_INFO "%s: asante: testing board: ", dev->name);
+			break;
+		case NS8390_APPLE:
+		default:
+			printk(KERN_INFO "%s: apple/clone: testing board: ", dev->name);
+			break;
+		}
+			
 		printk("%dK memory - ", memsize>>10);		
-
+			
 		i=(void *)dev->mem_start;
 		memset((void *)i,0xAA, memsize);
 		while(i<(volatile unsigned short *)dev->mem_end)
@@ -295,51 +406,75 @@
 			i+=2;	/* Skip a word */
 		}
 		printk("OK\n");
-
-		if(id==NS8390_FARALLON)
+			
+		switch (id)
 		{
-			if(ns8390_probe1(dev, 1, "farallon", id, -1)==0)
+		case NS8390_FARALLON:
+			if(ns8390_probe1(dev, 1, "farallon", id, -1, ndev)==0)
 				return 0;
-		}
-		else
-		{
-			if(ns8390_probe1(dev, 1, "apple/clone", id, -1)==0)
-			    return 0;
+			break;
+		case NS8390_ASANTE:
+			if(ns8390_probe1(dev, 1, "asante", id, -1, ndev)==0)
+				return 0;
+			break;
+		case NS8390_APPLE:
+		default:
+			if(ns8390_probe1(dev, 1, "apple/clone", id, -1, ndev)==0)
+				return 0;
+			break;
 		}
 	}
 	/* Interlan */
 	if(id==NS8390_INTERLAN)
 	{
 		/* As apple and asante */
-		dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
-		dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
+		dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
+		dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
 		dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
-		dev->irq=slot;
-		if(ns8390_probe1(dev, 1, "interlan", id, -1)==0)
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+		if(ns8390_probe1(dev, 1, "interlan", id, -1, ndev)==0)
 			return 0;
 	}
-	/* Kinetics */
+	/* Kinetics (Shiva Etherport) */
 	if(id==NS8390_KINETICS)
 	{
-		dev->base_addr=(int)(nubus_slot_addr(slot)+KINETICS_8390_BASE);
-		dev->mem_start=(int)(nubus_slot_addr(slot)+KINETICS_8390_MEM);
+		dev->base_addr=(int)(ndev->board->slot_addr+KINETICS_8390_BASE);
+		dev->mem_start=(int)(ndev->board->slot_addr+KINETICS_8390_MEM);
 		dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */
-		dev->irq=slot;
-		if(ns8390_probe1(dev, 0, "kinetics", id, -1)==0)
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+		if(ns8390_probe1(dev, 0, "kinetics", id, -1, ndev)==0)
 			return 0;
 	}
-	kfree(dev);
+
+	/* We should hopefully not get here */
+	printk(KERN_ERR "Probe unsucessful.\n");
 	return -ENODEV;
-membad:
-	printk("failed.\n");
-	kfree(dev);
+
+ membad:
+	printk(KERN_ERR "failed at %p in %p - %p.\n", i,
+		   (void *)dev->mem_start, (void *)dev->mem_end);
 	return -ENODEV;
 }
 
-int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type, int promoff)
+int __init mac8390_ethernet_addr(struct nubus_dev* ndev, 
+				 unsigned char addr[6])
 {
-	static unsigned version_printed = 0;
+	struct nubus_dir dir;
+	struct nubus_dirent ent;
+
+	/* Get the functional resource for this device */
+	if (nubus_get_func_dir(ndev, &dir) == -1)
+		return -1;
+	if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1)
+		return -1;
+	
+	nubus_get_rsrc_mem(addr, &ent, 6);
+	return 0;
+}
 
+int __init ns8390_probe1(struct net_device *dev, int word16, char *model_name,
+			 int type, int promoff, struct nubus_dev *ndev)
+{
 	static u32 fwrd4_offsets[16]={
 		0,      4,      8,      12,
 		16,     20,     24,     28,
@@ -352,25 +487,19 @@
 		28,     24,     20,     16,
 		12,     8,      4,      0
 	};
+	static u32 fwrd2_offsets[16]={
+		0,      2,      4,      6,
+		8,     10,     12,     14,
+		16,    18,     20,     22,
+		24,    26,     28,     30
+	};
 
-	unsigned char *prom=((unsigned char *)nubus_slot_addr(dev->irq))+promoff;
+	unsigned char *prom = (unsigned char*) ndev->board->slot_addr + promoff;
 
-	if (ei_debug  &&  version_printed++ == 0)
-		printk(version);
-	
-	/* Snarf the interrupt now.  There's no point in waiting since we cannot
-	   share a slot! and the board will usually be enabled. */
-	if (nubus_request_irq(dev->irq, dev, ei_interrupt)) 
-	{
-		printk (" unable to get nubus IRQ %d.\n", dev->irq);
-		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");
-		nubus_free_irq(dev->irq);
+		printk ("%s: unable to get memory for dev->priv.\n", dev->name);
 		return -ENOMEM;
 	}
 
@@ -378,16 +507,25 @@
 
 	ei_status.name = model_name;
 	ei_status.word16 = word16;
-	ei_status.tx_start_page = WD_START_PG;
-	ei_status.rx_start_page = WD_START_PG + TX_PAGES;
 
-	dev->rmem_start = dev->mem_start + TX_PAGES*256;
-	ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
-	dev->rmem_end = dev->mem_end;
+       if (type==NS8390_CABLETRON) {
+               /* Cabletron card puts the RX buffer before the TX buffer */
+               ei_status.tx_start_page = CABLETRON_TX_START_PG;
+               ei_status.rx_start_page = CABLETRON_RX_START_PG;
+               ei_status.stop_page = CABLETRON_RX_STOP_PG;
+               dev->rmem_start = dev->mem_start;
+               dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
+       } else {
+               ei_status.tx_start_page = WD_START_PG;
+               ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+               ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+               dev->rmem_start = dev->mem_start + TX_PAGES*256;
+               dev->rmem_end = dev->mem_end;
+       }
 	
 	if(promoff==-1)		/* Use nubus resources ? */
 	{
-		if(nubus_ethernet_addr(dev->irq /* slot */, dev->dev_addr))
+		if(mac8390_ethernet_addr(ndev, dev->dev_addr))
 		{
 		  printk("mac_ns8390: MAC address not in resources!\n");
 		  return -ENODEV;
@@ -400,7 +538,7 @@
 		/* These should go in the end I hope */
 		if(type==NS8390_DAYNA)
 			x=2;
-		if(type==NS8390_INTERLAN)
+		if(type==NS8390_INTERLAN || type==NS8390_KINETICS)
 			x=4;
 		while(i<6)
 		{
@@ -412,12 +550,24 @@
 		}
 	}
 
-	printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
-		   model_name, dev->irq, dev->mem_start, dev->mem_end-1);
+	printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
+		   dev->name, ndev->board->name, ndev->board->slot, model_name);
+	printk(KERN_INFO "MAC ");
+	{
+		int i;
+		for (i = 0; i < 6; i++) {
+			printk("%2.2x", dev->dev_addr[i]);
+			if (i < 5)
+				printk(":");
+		}
+	}
+	printk(" IRQ %d, shared memory at %#lx-%#lx.\n",
+		   dev->irq, dev->mem_start, dev->mem_end-1);
 
 	switch(type)
 	{
 		case NS8390_DAYNA:      /* Dayna card */
+		case NS8390_KINETICS:   /* Kinetics --  8 bit config, but 16 bit mem */
 			/* 16 bit, 4 word offsets */
 			ei_status.reset_8390 = &ns8390_no_reset;
 			ei_status.block_input = &dayna_block_input;
@@ -425,6 +575,15 @@
 			ei_status.get_8390_hdr = &dayna_get_8390_hdr;
 			ei_status.reg_offset = fwrd4_offsets;
 			break;
+		case NS8390_CABLETRON: /* Cabletron */
+			/*		16 bit card, register map is short forward */
+			ei_status.reset_8390 = &ns8390_no_reset;
+			/* Ctron card won't accept 32bit values read or written to it */
+			ei_status.block_input = &slow_sane_block_input;
+			ei_status.block_output = &slow_sane_block_output;
+			ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+			ei_status.reg_offset = fwrd2_offsets;
+			break;
 		case NS8390_FARALLON:
 		case NS8390_APPLE:	/* Apple/Asante/Farallon */
 			/*      16 bit card, register map is reversed */
@@ -450,6 +609,8 @@
 			ei_status.get_8390_hdr = &sane_get_8390_hdr;
 			ei_status.reg_offset = back4_offsets;
 			break;
+#if 0 /* i think this suffered code rot.  my kinetics card has much
+	   * different settings.  -- CSA [22-May-1999] */
 		case NS8390_KINETICS:   /* Kinetics */
 			/*      8bit card, map is forward */
 			ei_status.reset_8390 = &ns8390_no_reset;
@@ -458,6 +619,7 @@
 			ei_status.get_8390_hdr = &sane_get_8390_hdr;
 			ei_status.reg_offset = back4_offsets;
 			break;
+#endif
 		default:
 			panic("Detected a card I can't drive - whoops\n");
 	}
@@ -472,6 +634,19 @@
 static int ns8390_open(struct net_device *dev)
 {
 	ei_open(dev);
+
+	/* At least on my card (a Focus Enhancements PDS card) I start */
+	/* getting interrupts right away, so the driver needs to be    */
+	/* completely initialized before enabling the interrupt.        */
+	/*                             - funaho@jurai.org (1999-05-17) */
+
+	/* Non-slow interrupt, works around issues with the SONIC driver */
+	if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) 
+	{
+		printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+		return EAGAIN;
+	}
+	
 	MOD_INC_USE_COUNT;
 	return 0;
 }
@@ -489,24 +664,19 @@
 {
 	if (ei_debug > 1)
 		printk("%s: Shutting down ethercard.\n", dev->name);
+	free_irq(dev->irq, dev);
 	ei_close(dev);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
-struct nubus_device_specifier nubus_8390={
-	ns8390_probe,
-	NULL
-};
-
-
 /*
  *    Interlan Specific Code Starts Here
  */
 
 static void interlan_reset(struct net_device *dev)
 {
-	unsigned char *target=nubus_slot_addr(dev->irq);
+	unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
 	if (ei_debug > 1) 
 		printk("Need to reset the NS8390 t=%lu...", jiffies);
 	ei_status.txing = 0;
@@ -531,16 +701,23 @@
    The only complications are that the ring buffer wraps.
 */
 
-static void dayna_cpu_memcpy(struct net_device *dev, void *to, int from, int count)
+static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
 {
 	volatile unsigned short *ptr;
 	unsigned short *target=to;
 	from<<=1;	/* word, skip overhead */
 	ptr=(unsigned short *)(dev->mem_start+from);
+	/*
+	 * Leading byte?
+	 */
+	if (from&2) {
+		*((char *)target)++ = *(((char *)ptr++)-1);
+		count--;
+	}
 	while(count>=2)
 	{
 		*target++=*ptr++;	/* Copy and */
-		ptr++;			/* Cruft and */
+		ptr++;			/* skip cruft */
 		count-=2;
 	}
 	/*
@@ -554,16 +731,24 @@
 	}
 }
 
-static void cpu_dayna_memcpy(struct net_device *dev, int to, const void *from, int count)
+static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count)
 {
 	volatile unsigned short *ptr;
 	const unsigned short *src=from;
 	to<<=1;	/* word, skip overhead */
 	ptr=(unsigned short *)(dev->mem_start+to);
+	/*
+	 * Leading byte?
+	 */
+	if (to&2) { /* avoid a byte write (stomps on other data) */
+		ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++;
+		ptr++;
+		count--;
+	}
 	while(count>=2)
 	{
 		*ptr++=*src++;		/* Copy and */
-		ptr++;			/* Cruft and */
+		ptr++;			/* skip cruft */
 		count-=2;
 	}
 	/*
@@ -573,14 +758,15 @@
 	{
 		/* Big endian */
 		unsigned short v=*src;
-		*((char *)ptr)=v>>8;
+		/* card doesn't like byte writes */
+		*ptr=(*ptr&0x00FF)|(v&0xFF00);
 	}
 }
 
 static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 {
 	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
-	dayna_cpu_memcpy(dev, (void *)hdr, hdr_start, 4);
+	dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4);
 	/* Register endianism - fix here rather than 8390.c */
 	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
 }
@@ -599,14 +785,14 @@
 	{
 		/* We must wrap the input move. */
 		int semi_count = dev->rmem_end - xfer_start;
-		dayna_cpu_memcpy(dev, skb->data, xfer_base, semi_count);
+		dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
 		count -= semi_count;
-		dayna_cpu_memcpy(dev, skb->data + semi_count, 
+		dayna_memcpy_fromcard(dev, skb->data + semi_count, 
 			dev->rmem_start - dev->mem_start, count);
 	}
 	else
 	{
-		dayna_cpu_memcpy(dev, skb->data, xfer_base, count);
+		dayna_memcpy_fromcard(dev, skb->data, xfer_base, count);
 	}
 }
 
@@ -615,7 +801,7 @@
 {
 	long shmem = (start_page - WD_START_PG)<<8;
 	
-	cpu_dayna_memcpy(dev, shmem, buf, count);
+	dayna_memcpy_tocard(dev, shmem, buf, count);
 }
 
 /*
@@ -739,6 +925,7 @@
  * Local variables:
  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c"
  *  version-control: t
+ *  c-basic-offset: 4
  *  tab-width: 4
  *  kept-new-versions: 5
  * End:

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