patch-1.3.64 linux/drivers/net/arcnet.c

Next file: linux/drivers/scsi/aic7xxx.c
Previous file: linux/drivers/char/stallion.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.63/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
@@ -1,4 +1,4 @@
-/* arcnet.c
+/* arcnet.c:
 	Written 1994-1996 by Avery Pennarun,
 	derived from skeleton.c by Donald Becker.
 
@@ -19,6 +19,45 @@
 	
 	This is ONLY A SUMMARY.  The complete ChangeLog is available in
 	the full Linux-ARCnet package.
+	
+	v2.41 ALPHA (96/02/10)
+	  - Incorporated changes someone made to arcnet_setup in 1.3.60.
+	  - Increased reset timeout to 3/10 of a second because some cards
+	    are too slow.
+	  - Removed a useless delay from autoprobe stage 4; I wonder
+	    how that got there!  (oops)
+	  - If FAST_IFCONFIG is defined, don't reset the card during
+	    arcnet_open; rather, do it in arcnet_close but don't delay. 
+	    This speeds up calls to ifconfig up/down.  (Thanks to Vojtech
+	    for the idea to speed this up.)
+	  - If FAST_PROBE is defined, don't bother to reset the card in
+	    autoprobe Stage 5 when there is only one io port and one shmem
+	    left in the list.  They "obviously" correspond to each other. 
+	    Another good idea from Vojtech.
+
+	v2.40 ALPHA (96/02/03)
+	  - Checked the RECON flag last in the interrupt handler (when
+	    enabled) so the flag will show up in "status" when reporting
+	    other errors.  (I had a cabling problem that was hard to notice
+	    until I saw the huge RECON count in /proc/net/dev.)
+	  - Moved "IRQ for unknown device" message to D_DURING.
+	  - "transmit timed out" and "not acknowledged" messages are
+	    now D_EXTRA, because they very commonly happen when things
+	    are working fine.  "transmit timed out" due to missed IRQ's
+	    is still D_NORMAL, because it's probably a bug.
+	  - "Transmit timed out" messages now include destination station id.
+	  - The virtual arc0e and arc0s devices can now be disabled. 
+	    Massive (but simple) code rearrangement to support this with
+	    fewer ifdef's.
+	  - SLOW_XMIT_COPY option so fast computers don't hog the bus.  It's
+	    weird, but it works.
+	  - Finally redesigned autoprobe after some discussion with Vojtech
+	    Pavlik <Vojtech.Pavlik@st.mff.cuni.cz>.  It should be much safer
+	    and more reliable now, I think.  We now probe several more io
+	    ports and many more shmem addresses.
+	  - Rearranged D_* debugging flags slightly.  Watch out!  There is
+	    now a new flag, disabled by default, that will tell you the
+	    reason a particular port or shmem is discarded from the list.
 
 	v2.30 ALPHA (96/01/10)
 	  - Abandoned support for Linux 1.2 to simplify coding and allow me
@@ -82,27 +121,27 @@
          
 	TO DO: (it it just me, or does this list only get longer?)
 	
-         - Test in systems with NON-ARCnet network cards, just to see if
-           autoprobe kills anything.  Currently, we do cause some NE2000's
-           to die.  Autoprobe is also way too slow and verbose, particularly
-           if there aren't any ARCnet cards in the system.
-         - Rewrite autoprobe.  Try the Linux-generic-autoirq function instead
-           of the net-specific one.
-         - Make sure RESET flag is cleared during an IRQ even if dev->start==0;
-           mainly a portability fix.  This will confuse autoprobe a bit, so
-           test that too.
+	 - Make sure autoprobe puts TESTvalue back into shmem locations
+	   that it determines aren't ARCnet cards.
+	 - Probe for multiple devices in one shot (there's supposed to
+	   be a way to do that now, but I can't remember what it is!)
+         - Support printk's priority levels.
+         - Have people test the new autoprobe a bit more - then remove
+           D_INIT from the default debug level.
+         - Move the SKB and memory dump code into separate functions.
+	 - Debug level should be changed with a system call, not a hack to
+	   the "metric" flag.
          - What about cards with shared memory that can be "turned off?"
            (or that have none at all, like the SMC PC500longboard)
          - Autoconfigure PDI5xxPlus cards. (I now have a PDI508Plus to play
-           with temporarily)
+           with temporarily.)  Update: yes, the Pure Data config program
+           for DOS works fine, but the PDI508Plus I have doesn't! :)
          - Try to implement promiscuous (receive-all-packets) mode available
            on some newer cards with COM20020 and similar chips.  I don't have
            one, but SMC sent me the specs.
          - Add support for the new 1.3.x IP header cache features.
-         - Support printk's priority levels.
          - Make arcnetE_send_packet use arcnet_prepare_tx for loading the
            packet into ARCnet memory.
-         - Move the SKB and memory dump code into separate functions.
          - ATA protocol support?? 
          - VINES TCP/IP encapsulation?? (info needed)
 
@@ -125,7 +164,7 @@
 */
 
 static const char *version =
- "arcnet.c: v2.30 ALPHA 96/01/10 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.41 ALPHA 96/02/10 Avery Pennarun <apenwarr@foxnet.net>\n";
 
  
 
@@ -160,6 +199,36 @@
 
 /**************************************************************************/
 
+/* This driver supports three different "virtual ARCnet devices" running
+ * on the same adapter, in order to communicate with various different
+ * TCP/IP-over-ARCnet implementations.  They are:
+ *	arc0	- RFC1201 Internet-standard protocol
+ *	arc0e	- Ethernet-encapsulation protocol (as used by Windows)
+ *	arc0s	- "Simpler" (but outdated) RFC1051 internet standard.
+ *
+ * arc0e and arc0s are created when arc0 is ifconfig'ed up.  You can disable
+ * either or both of them by undefining CONFIG_ARCNET_ETH and/or
+ * CONFIG_ARCNET_1051.
+ */
+#define CONFIG_ARCNET_ETH
+#define CONFIG_ARCNET_1051
+
+/* On a fast computer, the buffer copy from memory to the ARCnet card during
+ * a transmit can hog the bus just a little too long.  SLOW_XMIT_COPY
+ * replaces the fast memcpy() with a slower for() loop that seems to solve
+ * my problems with ftape.
+ *
+ * Probably a better solution would be to use memcpy_toio (more portable
+ * anyway) and modify that routine to support REALLY_SLOW_IO-style
+ * defines; ARCnet probably is not the only driver that can screw up an
+ * ftape DMA transfer.
+ *
+ * Turn this off if you don't have timing-sensitive DMA (ie. a tape drive)
+ * and would like the little bit of speed back.  It's on by default because
+ * - trust me - it's very difficult to figure out that you need it!
+ */
+#define SLOW_XMIT_COPY
+
 /* The card sends the reconfiguration signal when it loses the connection to
  * the rest of its network. It is a 'Hello, is anybody there?' cry.  This
  * usually happens when a new computer on the network is powered on or when
@@ -189,24 +258,34 @@
  */
 #define RECON_THRESHOLD 30
 
-/* Define this if you want to make sure transmitted packets are "acknowledged"
- * by the destination host, as long as they're not to the broadcast address.
- *
- * That way, if one segment of a split packet doesn't get through, it can be
- * resent immediately rather than confusing the other end.  We don't
- * actually do that yet, though.
- *
- * Disable this to return to 1.02-style behaviour, if you have problems.
- */
-#define VERIFY_ACK
-
 /* Define this to the minimum "timeout" value.  If a transmit takes longer
  * than TX_TIMEOUT jiffies, Linux will abort the TX and retry.  On a large
  * network, or one with heavy network traffic, this timeout may need to be
- * increased.
+ * increased.  The larger it is, though, the longer it will be between
+ * necessary transmits - don't set this too large.
  */
 #define TX_TIMEOUT 20
 
+/* Define this to speed up the autoprobe by assuming if only one io port and
+ * shmem are left in the list at Stage 5, they must correspond to each
+ * other.
+ *
+ * This is undefined by default because it might not always be true.  Speed
+ * demons can turn it on - I think it should be fine if you only have one
+ * ARCnet card installed.
+ *
+ * If no ARCnet cards are installed, this delay never happens anyway and thus
+ * the option has no effect.
+ */
+#undef FAST_PROBE
+
+/* Define this to speed up "ifconfig up" by moving the card reset command
+ * around.  This is a new option in 2.41 ALPHA.  If it causes problems,
+ * undefine this to get the old behaviour; then send me email, because if
+ * there are no problems, this option will go away very soon.
+ */
+#define FAST_IFCONFIG
+
 /* Define this if you want to make it easier to use the "call trace" when
  * a kernel NULL pointer assignment occurs.  Hopefully unnecessary, most of
  * the time.  It will make all the function names (and other things) show
@@ -224,55 +303,66 @@
  *		and HOSTNAME is your hostname/ip address
  * and then resetting your routes.
  *
+ * An ioctl() should be used for this instead, someday.
+ *
  * Note: only debug flags included in the ARCNET_DEBUG_MAX define will
  *   actually be available.  GCC will (at least, GCC 2.7.0 will) notice
  *   lines using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize
  *   them out.
  */
-#define D_NORMAL	1	/* D_NORMAL  normal operational info	*/
-#define	D_INIT		2	/* D_INIT    show init/probe messages	*/
-#define D_EXTRA		4	/* D_EXTRA   extra information		*/
-/* debug levels past this point give LOTS of output! */
-#define D_DURING	8	/* D_DURING  during normal use (irq's)	*/
-#define D_TX		16	/* D_TX	     show tx packets		*/
-#define D_RX		32	/* D_RX	     show rx packets		*/
-#define D_SKB		64	/* D_SKB     dump skb's			*/
+#define D_NORMAL	1	/* important operational info		*/
+#define D_EXTRA		2	/* useful, but non-vital information	*/
+#define	D_INIT		4	/* show init/probe messages		*/
+#define D_INIT_REASONS	8	/* show reasons for discarding probes	*/
+/* debug levels below give LOTS of output during normal operation! */
+#define D_DURING	16	/* trace operations (including irq's)	*/
+#define D_TX		32	/* show tx packets			*/
+#define D_RX		64	/* show rx packets			*/
+#define D_SKB		128	/* show skb's				*/
 
 #ifndef ARCNET_DEBUG_MAX
 #define ARCNET_DEBUG_MAX (~0)		/* enable ALL debug messages */
-/*#define ARCNET_DEBUG_MAX (D_NORMAL|D_INIT|D_EXTRA) */
+/*#define ARCNET_DEBUG_MAX (D_NORMAL|D_EXTRA|D_INIT|D_INIT_REASONS) */
 /*#define ARCNET_DEBUG_MAX 0	*/	/* enable NO debug messages */
 #endif
 
 #ifndef ARCNET_DEBUG
-#define ARCNET_DEBUG (D_NORMAL|D_INIT|D_EXTRA)
-/*#define ARCNET_DEBUG (D_NORMAL|D_INIT)*/
+#define ARCNET_DEBUG (D_NORMAL|D_EXTRA|D_INIT)
+/*#define ARCNET_DEBUG (D_NORMAL)*/
 #endif
 int arcnet_debug = ARCNET_DEBUG;
 
 /* macros to simplify debug checking */
 #define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
-#define BUGMSG(x,msg,args...) BUGLVL(x) printk("%6s: " msg, dev->name , ## args);
+#define BUGMSG2(x,msg,args...) BUGLVL(x) printk(msg , ## args)
+#define BUGMSG(x,msg,args...) BUGMSG2(x,"%6s: " msg, dev->name , ## args)
+
+/* Some useful multiprotocol macros.  The idea here is that GCC will
+ * optimize away multiple tests or assignments to lp->adev.  Relying on this
+ * results in the cleanest mess possible.
+ */
+#define ADEV lp->adev
+ 
+#ifdef CONFIG_ARCNET_ETH
+ #define EDEV lp->edev
+#else
+ #define EDEV lp->adev
+#endif
+
+#ifdef CONFIG_ARCNET_1051
+ #define SDEV lp->sdev
+#else
+ #define SDEV lp->adev
+#endif
+
+#define TBUSY ADEV->tbusy=EDEV->tbusy=SDEV->tbusy
+#define IF_TBUSY (ADEV->tbusy||EDEV->tbusy||SDEV->tbusy)
+
+#define INTERRUPT ADEV->interrupt=EDEV->interrupt=SDEV->interrupt
+#define IF_INTERRUPT (ADEV->interrupt||EDEV->interrupt||SDEV->interrupt)
+
+#define START ADEV->start=EDEV->start=SDEV->start
 
-/* Some useful multiprotocol macros */
-#define TBUSY lp->adev->tbusy \
-		=lp->edev->tbusy \
-		=lp->sdev->tbusy
-#define IF_TBUSY (lp->adev->tbusy \
-		|| lp->edev->tbusy \
-		|| lp->sdev->tbusy)
-
-#define INTERRUPT lp->adev->interrupt \
-		=lp->edev->interrupt \
-		=lp->sdev->interrupt
-#define IF_INTERRUPT (lp->adev->interrupt \
-		|| lp->edev->interrupt \
-		|| lp->sdev->interrupt)
-
-#define START lp->adev->start \
-		=lp->edev->start \
-		=lp->sdev->start
-		
 
 /* The number of low I/O ports used by the ethercard. */
 #define ARCNET_TOTAL_SIZE	16
@@ -287,9 +377,11 @@
 
 #define SETMASK outb(lp->intmask,INTMASK);
 
-	/* Time needed for various things (in clock ticks, 1/100 sec) */
-	/* We mostly don't bother with these - watch out. */
-#define RESETtime 30		/* reset */
+	/* Time needed to reset the card - in jiffies.  This works on my SMC
+	 * PC100.  I can't find a reference that tells me just how long I
+	 * should wait.
+	 */
+#define RESETtime (HZ * 3 / 10)		/* reset */
 
 	/* these are the max/min lengths of packet data. (including
 	 * ClientData header)
@@ -309,8 +401,8 @@
 #define RECONflag       0x04            /* system reconfigured */
 #define TESTflag        0x08            /* test flag */
 #define RESETflag       0x10            /* power-on-reset */
-#define RES1flag        0x20            /* unused */
-#define RES2flag        0x40            /* unused */
+#define RES1flag        0x20            /* reserved - usually set by jumper */
+#define RES2flag        0x40            /* reserved - usually set by jumper */
 #define NORXflag        0x80            /* receiver inhibited */
 
        /* in the command register, the following bits have these meanings:
@@ -455,12 +547,9 @@
 		intmask;	/* current value of INTMASK register */
 	short intx,		/* in TX routine? */
 	      in_txhandler,	/* in TX_IRQ handler? */
-	      sending;		/* transmit in progress? */
-
-#ifdef VERIFY_ACK
-	short lastload_dest,		/* can last loaded packet be acked? */
-	      lasttrans_dest;		/* can last TX'd packet be acked? */
-#endif
+	      sending,		/* transmit in progress? */
+	      lastload_dest,	/* can last loaded packet be acked? */
+	      lasttrans_dest;	/* can last TX'd packet be acked? */
 
 #if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD)
 	time_t first_recon,	/* time of "first" RECON message to count */
@@ -473,29 +562,29 @@
 	struct Incoming incoming[256];	/* one from each address */
 	struct Outgoing outgoing; /* packet currently being sent */
 	
-	struct device *adev,	/* RFC1201 protocol device */
-		 	*edev,	/* Ethernet-Encap device */
-		 	*sdev;	/* RFC1051 protocol device */
+	struct device *adev;	/* RFC1201 protocol device */
+
+#ifdef CONFIG_ARCNET_ETH
+	struct device *edev;	/* Ethernet-Encap device */
+#endif
+
+#ifdef CONFIG_ARCNET_1051
+	struct device *sdev;	/* RFC1051 protocol device */
+#endif
 };
 
 
 /* Index to functions, as function prototypes. */
 extern int arcnet_probe(struct device *dev);
-static int arcnet_memprobe(struct device *dev,u_char *addr);
-static int arcnet_ioprobe(struct device *dev, short ioaddr);
+static int arcnet_found(struct device *dev,int port,int airq,u_long shmem);
 
 static void arcnet_setup(struct device *dev);
-static int arcnetE_init(struct device *dev);
-static int arcnetS_init(struct device *dev);
-
 static int arcnet_open(struct device *dev);
 static int arcnet_close(struct device *dev);
-static int arcnet_reset(struct device *dev);
+static int arcnet_reset(struct device *dev,int reset_delay);
 
 static int arcnet_send_packet_bad(struct sk_buff *skb,struct device *dev);
 static int arcnetA_send_packet(struct sk_buff *skb, struct device *dev);
-static int arcnetE_send_packet(struct sk_buff *skb, struct device *dev);
-static int arcnetS_send_packet(struct sk_buff *skb, struct device *dev);
 static void arcnetA_continue_tx(struct device *dev);
 static void arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
 		char *data,int length,int daddr,int exceptA);
@@ -507,26 +596,35 @@
 static void arcnet_rx(struct device *dev,int recbuf);
 static void arcnetA_rx(struct device *dev,u_char *buf,
 	int length,u_char saddr, u_char daddr);
-static void arcnetE_rx(struct device *dev,u_char *arcsoft,
-	int length,u_char saddr, u_char daddr);
-static void arcnetS_rx(struct device *dev,u_char *buf,
-	int length,u_char saddr, u_char daddr);
 
 static struct enet_statistics *arcnet_get_stats(struct device *dev);
-/*
-static void set_multicast_list(struct device *dev);
-*/
-	/* functions for header/arp/etc building */
+
 int arcnetA_header(struct sk_buff *skb,struct device *dev,
 		unsigned short type,void *daddr,void *saddr,unsigned len);
-int arcnetS_header(struct sk_buff *skb,struct device *dev,
-		unsigned short type,void *daddr,void *saddr,unsigned len);
 int arcnetA_rebuild_header(void *eth,struct device *dev,unsigned long raddr,
 		struct sk_buff *skb);
+unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev);
+
+#ifdef CONFIG_ARCNET_ETH
+	/* functions specific to Ethernet-Encap */
+static int arcnetE_init(struct device *dev);
+static int arcnetE_send_packet(struct sk_buff *skb, struct device *dev);
+static void arcnetE_rx(struct device *dev,u_char *arcsoft,
+	int length,u_char saddr, u_char daddr);
+#endif
+
+#ifdef CONFIG_ARCNET_1051
+	/* functions specific to RFC1051 */
+static int arcnetS_init(struct device *dev);
+static int arcnetS_send_packet(struct sk_buff *skb, struct device *dev);
+static void arcnetS_rx(struct device *dev,u_char *buf,
+	int length,u_char saddr, u_char daddr);
+int arcnetS_header(struct sk_buff *skb,struct device *dev,
+		unsigned short type,void *daddr,void *saddr,unsigned len);
 int arcnetS_rebuild_header(void *eth,struct device *dev,unsigned long raddr,
 		struct sk_buff *skb);
-unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev);
 unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev);
+#endif
 
 #ifdef MODULE
 int  init_module(void);
@@ -535,8 +633,7 @@
 
 #define tx_done(dev) 1
 
-#define JIFFER(time) for (delayval=0; delayval<(time*10); delayval++) \
-		udelay(1000);
+#define JIFFER(time) for (delayval=jiffies+time; jiffies<delayval;) ;
 		
 
 /****************************************************************************
@@ -545,63 +642,54 @@
  *                                                                          *
  ****************************************************************************/
  
-/* Check for a network adaptor of this type, and return '0' if one exists.
+/* Check for an ARCnet network adaptor, and return '0' if one exists.
  *  If dev->base_addr == 0, probe all likely locations.
  *  If dev->base_addr == 1, always return failure.
  *  If dev->base_addr == 2, allocate space for the device and return success
- *  (detachable devices only).
- */
-int
-arcnet_probe(struct device *dev)
-{
-	/* I refuse to probe anything less than 0x200, because anyone using
-	 * an address like that should probably be shot.
-	 */
-	int *port, ports[] = {/* first the suggested values! */
-			      0x300,0x2E0,0x2F0,0x2D0,
-			      /* ...now everything else possible. */
-			      0x200,0x210,0x220,0x230,0x240,0x250,0x260,0x270,
-			      0x280,0x290,0x2a0,0x2b0,0x2c0,
-			            0x310,0x320,0x330,0x340,0x350,0x360,0x370,
-			      0x380,0x390,0x3a0,/* video ports, */0x3e0,0x3f0,
-			      /* a null ends the list */
-			      0};
-	/* I'm not going to probe below 0xA0000 either, for similar reasons.
-	 */
-	unsigned long *addr, addrs[] = {0xD0000,0xE0000,0xA0000,0xB0000,
-					0xC0000,0xF0000,
-					/* from <mdrejhon@magi.com> */
-					0xE1000,
-					0xDD000,0xDC000,
-					0xD9000,0xD8000,0xD5000,0xD4000,0xD1000,
-					0xCD000,0xCC000,
-					0xC9000,0xC8000,0xC5000,0xC4000,
-					/* terminator */
-					0};
-	int base_addr=dev->base_addr, status=0;
-	int delayval,ioaddr;
-	struct arcnet_local *lp;
+ *  			    (detachable devices only).
+ *
+ * NOTE: the list of possible ports/shmems is static, so it is retained
+ * across calls to arcnet_probe.  So, if more than one ARCnet probe is made,
+ * values that were discarded once will not even be tried again.
+ */
+int arcnet_probe(struct device *dev)
+{
+	static int init_once = 0;
+	static int ports[(0x3f0 - 0x200) / 16 + 1];
+	static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1];
+	static int numports=sizeof(ports)/sizeof(ports[0]),
+	    	   numshmems=sizeof(shmems)/sizeof(shmems[0]);
 
-	printk(version);
+	int count,status,delayval,ioaddr,numprint,airq;
+	unsigned long airqmask;
+	int *port;
+	u_long *shmem;
 	
-#if 1
-	BUGLVL(D_NORMAL)
+	if (!init_once)
 	{
-		printk("arcnet: ***\n");
-		printk("arcnet: * Read README.arcnet for important release notes!\n");
-		printk("arcnet: *\n");
-		printk("arcnet: * This is an ALPHA version!  (Last stable release: v2.00)  E-mail me if\n");
-		printk("arcnet: * you have any questions, comments, or bug reports.\n");
-		printk("arcnet: ***\n");
+		for (count=0x200; count<=0x3f0; count+=16)
+			ports[(count-0x200)/16] = count;
+		for (count=0xA0000; count<=0xFF800; count+=2048)
+			shmems[(count-0xA0000)/2048] = count;
 	}
-#else
+	else
+		init_once=1;
+
+	BUGLVL(D_NORMAL) printk(version);
+
+	BUGMSG(D_DURING,"space used for probe buffers: %d+%d=%d bytes\n",
+		sizeof(ports),sizeof(shmems),
+		sizeof(ports)+sizeof(shmems));
+
+	
+#if 1
 	BUGLVL(D_EXTRA)
 	{
 		printk("arcnet: ***\n");
-		printk("arcnet: * Read README.arcnet for important release notes!\n");
+		printk("arcnet: * Read arcnet.txt for important release notes!\n");
 		printk("arcnet: *\n");
-		printk("arcnet: * This version should be stable, but please e-mail\n");
-		printk("arcnet: * me if you have any questions or comments.\n");
+		printk("arcnet: * This is an ALPHA version!  (Last stable release: v2.22)  E-mail me if\n");
+		printk("arcnet: * you have any questions, comments, or bug reports.\n");
 		printk("arcnet: ***\n");
 	}
 #endif
@@ -609,80 +697,367 @@
 	BUGMSG(D_INIT,"given: base %lXh, IRQ %d, shmem %lXh\n",
 			dev->base_addr,dev->irq,dev->mem_start);
 
-	if (base_addr > 0x1ff)		/* Check a single specified location. */
-		status=arcnet_ioprobe(dev, base_addr);
-	else if (base_addr > 0)		/* Don't probe at all. */
+	if (dev->base_addr > 0x1ff)	/* Check a single specified port */
+	{
+		ports[0]=dev->base_addr;
+		numports=1;
+	}
+	else if (dev->base_addr > 0)	/* Don't probe at all. */
 		return -ENXIO;
-	else for (port = &ports[0]; *port; port++)
+		
+	if (dev->mem_start)
+	{
+		shmems[0]=dev->mem_start;
+		numshmems=1;
+	}
+	
+
+	/* Stage 1: abandon any reserved ports, or ones with status==0xFF
+	 * (empty), and reset any others by reading the reset port.
+	 */
+	BUGMSG(D_INIT,"Stage 1: ");
+	numprint=0;
+	for (port = &ports[0]; port-ports<numports; port++)
 	{
+		numprint++;
+		if (numprint>8)
+		{
+			BUGMSG2(D_INIT,"\n");
+			BUGMSG(D_INIT,"Stage 1: ");
+			numprint=1;
+		}
+		BUGMSG2(D_INIT,"%Xh ",*port);
+		
+		ioaddr=*port;
+		
 		if (check_region(*port, ARCNET_TOTAL_SIZE))
 		{
-			BUGMSG(D_INIT,"Skipping %Xh because of check_region...\n",
-					*port);
+			BUGMSG2(D_INIT_REASONS,"(check_region)\n");
+			BUGMSG(D_INIT_REASONS,"Stage 1: ");
+			BUGLVL(D_INIT_REASONS) numprint=0;
+			*port=ports[numports-1];
+			numports--;
+			port--;
+			continue;
+		}
+		
+		if (inb(STATUS) == 0xFF)
+		{
+			BUGMSG2(D_INIT_REASONS,"(empty)\n");
+			BUGMSG(D_INIT_REASONS,"Stage 1: ");
+			BUGLVL(D_INIT_REASONS) numprint=0;
+			*port=ports[numports-1];
+			numports--;
+			port--;
 			continue;
 		}
+		
+		inb(RESET);	/* begin resetting card */
 
-		status=arcnet_ioprobe(dev, *port);
-		if (!status) break;
+		BUGMSG2(D_INIT_REASONS,"\n");
+		BUGMSG(D_INIT_REASONS,"Stage 1: ");
+		BUGLVL(D_INIT_REASONS) numprint=0;
 	}
+	BUGMSG2(D_INIT,"\n");
 	
-	if (status) return status;
+	if (!numports)
+	{
+		BUGMSG(D_INIT,"Stage 1: failed.  No ARCnet cards found.\n");
+		return -ENODEV;
+	}
 	
-	/* arcnet_ioprobe set this */
-	ioaddr=dev->base_addr;
 
-	/* ioprobe turned out okay.  Now reset the card, so we have
-	 * a test byte to look for in shared memory...
+	/* Stage 2: we have now reset any possible ARCnet cards, so we can't
+	 * do anything until they finish.  If D_INIT, print the list of
+	 * cards that are left.
 	 */
-	BUGMSG(D_INIT,"ioprobe okay!  Waiting for reset...\n");
-	inb(RESET);
+	BUGMSG(D_INIT,"Stage 2: ");
+	numprint=0;
+	for (port = &ports[0]; port-ports<numports; port++)
+	{
+		numprint++;
+		if (numprint>8)
+		{
+			BUGMSG2(D_INIT,"\n");
+			BUGMSG(D_INIT,"Stage 2: ");
+			numprint=1;
+		}
+		BUGMSG2(D_INIT,"%Xh ",*port);
+	}
+	BUGMSG2(D_INIT,"\n");
 	JIFFER(RESETtime);
+	
+
+	/* Stage 3: abandon any shmem addresses that don't have the signature
+	 * 0xD1 byte in the right place, or are read-only.
+	 */
+	BUGMSG(D_INIT,"Stage 3: ");
+	numprint=0;
+	for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
+	{
+		u_char *cptr;
+	
+		numprint++;
+		if (numprint>8)
+		{
+			BUGMSG2(D_INIT,"\n");
+			BUGMSG(D_INIT,"Stage 3: ");
+			numprint=1;
+		}
+		BUGMSG2(D_INIT,"%lXh ",*shmem);
+		
+		cptr=(u_char *)(*shmem);
+		
+		if (*cptr != TESTvalue)
+		{
+			BUGMSG2(D_INIT_REASONS,"(mem=%Xh, not %Xh)\n",
+				*cptr,TESTvalue);
+			BUGMSG(D_INIT_REASONS,"Stage 3: ");
+			BUGLVL(D_INIT_REASONS) numprint=0;
+			*shmem=shmems[numshmems-1];
+			numshmems--;
+			shmem--;
+			continue;
+		}
+		
+		/* By writing 0x42 to the TESTvalue location, we also make
+		 * sure no "mirror" shmem areas show up - if they occur
+		 * in another pass through this loop, they will be discarded
+		 * because *cptr != TESTvalue.
+		 */
+		*cptr=0x42;
+		if (*cptr != 0x42)
+		{
+			BUGMSG2(D_INIT_REASONS,"(read only)\n");
+			BUGMSG(D_INIT_REASONS,"Stage 3: ");
+			*shmem=shmems[numshmems-1];
+			numshmems--;
+			shmem--;
+			continue;
+		}
+		
+		BUGMSG2(D_INIT_REASONS,"\n");
+		BUGMSG(D_INIT_REASONS,"Stage 3: ");
+		BUGLVL(D_INIT_REASONS) numprint=0;
+	}
+	BUGMSG2(D_INIT,"\n");
 
-	/* okay, now we have to find the shared memory area. */
-	BUGMSG(D_INIT,"starting memory probe, given %lXh\n",
-			dev->mem_start);
-	if (dev->mem_start)	/* value given - probe just that one */
+	if (!numshmems)
 	{
-		status=arcnet_memprobe(dev,(u_char *)dev->mem_start);
-		if (status) return status;
+		BUGMSG(D_INIT,"Stage 3: failed.  No ARCnet cards found.\n");
+		return -ENODEV;
 	}
-	else			/* no value given - probe everything */
+
+	/* Stage 4: something of a dummy, to report the shmems that are
+	 * still possible after stage 3.
+	 */
+	BUGMSG(D_INIT,"Stage 4: ");
+	numprint=0;
+	for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
 	{
-		for (addr = &addrs[0]; *addr; addr++) {
-			status=arcnet_memprobe(dev,(u_char *)(*addr));
-			if (!status) break;
+		numprint++;
+		if (numprint>8)
+		{
+			BUGMSG2(D_INIT,"\n");
+			BUGMSG(D_INIT,"Stage 4: ");
+			numprint=1;
 		}
-		
-		if (status) return status;
+		BUGMSG2(D_INIT,"%lXh ",*shmem);
 	}
+	BUGMSG2(D_INIT,"\n");
+	
+
+	/* Stage 5: for any ports that have the correct status, can disable
+	 * the RESET flag, and (if no irq is given) generate an autoirq,
+	 * register an ARCnet device.
+	 *
+	 * Currently, we can only register one device per probe, so quit
+	 * after the first one is found.
+	 */
+	BUGMSG(D_INIT,"Stage 5: ");
+	numprint=0;
+	for (port = &ports[0]; port-ports<numports; port++)
+	{
+		numprint++;
+		if (numprint>8)
+		{
+			BUGMSG2(D_INIT,"\n");
+			BUGMSG(D_INIT,"Stage 5: ");
+			numprint=1;
+		}
+		BUGMSG2(D_INIT,"%Xh ",*port);
+		
+		ioaddr=*port;
+		status=inb(STATUS);
+		
+		if ((status & 0x9F)
+			!= (NORXflag|RECONflag|TXFREEflag|RESETflag))
+		{
+			BUGMSG2(D_INIT_REASONS,"(status=%Xh)\n",status);
+			BUGMSG(D_INIT_REASONS,"Stage 5: ");
+			BUGLVL(D_INIT_REASONS) numprint=0;
+			*port=ports[numports-1];
+			numports--;
+			port--;
+			continue;
+		}
+
+		outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
+		status=inb(STATUS);
+		if (status & RESETflag)
+		{
+			BUGMSG2(D_INIT_REASONS," (eternal reset, status=%Xh)\n",
+					status);
+			BUGMSG(D_INIT_REASONS,"Stage 5: ");
+			BUGLVL(D_INIT_REASONS) numprint=0;
+			*port=ports[numports-1];
+			numports--;
+			port--;
+			continue;
+		}
 
-	/* now reserve the irq... */
-	{	
-		int irqval = request_irq(dev->irq, &arcnet_interrupt, 0,
-			"arcnet");
-		if (irqval)
+		/* skip this if an IRQ was given, because maybe we're on a
+		 * machine that locks during autoirq!
+		 */
+		if (!dev->irq)
+		{
+			/* if we do this, we're sure to get an IRQ since the
+			 * card has just reset and the NORXflag is on until
+			 * we tell it to start receiving.
+			 */
+			airqmask = probe_irq_on();
+			outb(NORXflag,INTMASK);
+			/*udelay(1);*/
+			outb(0,INTMASK);
+			airq = probe_irq_off(airqmask);
+	
+			if (airq<=0)
+			{
+				BUGMSG2(D_INIT_REASONS,"(airq=%d)\n",airq);
+				BUGMSG(D_INIT_REASONS,"Stage 5: ");
+				BUGLVL(D_INIT_REASONS) numprint=0;
+				*port=ports[numports-1];
+				numports--;
+				port--;
+				continue;
+			}
+		}
+		else
 		{
-			BUGMSG(D_NORMAL,"unable to get IRQ %d (irqval=%d).\n",
-				dev->irq, irqval);
-			return -EIO;
+			airq=dev->irq;
 		}
 		
-		irq2dev_map[dev->irq]=dev;
+		BUGMSG2(D_INIT,"(%d,", airq);
+		
+		/* Everything seems okay.  But which shmem, if any, puts
+		 * back its signature byte when the card is reset?
+		 *
+		 * If there are multiple cards installed, there might be
+		 * multiple shmems still in the list.
+		 */
+#ifdef FAST_PROBE
+		if (numports>1 || numshmems>1)
+		{
+			inb(RESET);
+			JIFFER(RESETtime);
+		}
+		else
+		{
+			*(u_char *)(shmems[0]) = TESTvalue;
+		}
+#else
+		inb(RESET);
+		JIFFER(RESETtime);
+#endif
+
+
+		for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
+		{
+			u_char *cptr;
+			cptr=(u_char *)(*shmem);
+			
+			if (*cptr == TESTvalue)	/* found one */
+			{
+				BUGMSG2(D_INIT,"%lXh)\n", *shmem);
+
+				/* register the card */
+				status=arcnet_found(dev,*port,airq,*shmem);
+
+				/* remove port and shmem from the lists */
+				*port=ports[numports-1];
+				numports--;
+				*shmem=shmems[numshmems-1];
+				numshmems--;
+				
+				return status;
+			}
+			else
+			{
+				BUGMSG2(D_INIT_REASONS,"%Xh-", *cptr);
+			}
+		}
+
+		BUGMSG2(D_INIT,"no matching shmem)\n");
+		BUGMSG(D_INIT_REASONS,"Stage 5: ");
+		BUGLVL(D_INIT_REASONS) numprint=0;
+		*port=ports[numports-1];
+		numports--;
+		port--;
 	}
-	 
-	/* Grab the region so we can find another board if autoIRQ fails. */
-	request_region(dev->base_addr, ARCNET_TOTAL_SIZE,"arcnet");
+	BUGMSG(D_INIT_REASONS,"\n");
+
+	return -ENODEV;
+}
+
+/* Set up the struct device associated with this card.  Called after
+ * probing succeeds.
+ */
+int arcnet_found(struct device *dev,int port,int airq, u_long shmem)
+{
+	int irqval;
+	u_char *first_mirror,*last_mirror;
+	struct arcnet_local *lp;
+	
+	/* reserve the I/O region */
+	request_region(port,ARCNET_TOTAL_SIZE,"arcnet");
+	dev->base_addr=port;
+
+	/* reserve the irq */
+	irqval = request_irq(airq,&arcnet_interrupt,0,"arcnet");
+	if (irqval)
+	{
+		BUGMSG(D_NORMAL,"unable to get IRQ %d (irqval=%d).\n",
+			airq, irqval);
+		return -ENODEV;
+	}
+	irq2dev_map[airq]=dev;
+	dev->irq=airq;
+	
+	/* find the real shared memory start/end points, including mirrors */
 	
-	BUGMSG(D_NORMAL,"ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n", 
-		dev->base_addr, dev->irq, dev->mem_start);
+	#define BUFFER_SIZE (512)
+	#define MIRROR_SIZE (BUFFER_SIZE*4)
+	
+	first_mirror=last_mirror=(u_char *)shmem;
+	while (*first_mirror==TESTvalue) first_mirror-=MIRROR_SIZE;
+	first_mirror+=MIRROR_SIZE;
+
+	while (*last_mirror==TESTvalue) last_mirror+=MIRROR_SIZE;
+	last_mirror-=MIRROR_SIZE;
 
-	/* Initialize the device structure. */
+	dev->mem_start=(u_long)first_mirror;
+	dev->mem_end=(u_long)last_mirror+MIRROR_SIZE-1;
+	dev->rmem_start=dev->mem_start+BUFFER_SIZE*0;
+	dev->rmem_end=dev->mem_start+BUFFER_SIZE*2-1;
+	 
+	/* Initialize the rest of the device structure. */
+	
 	dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
 	if (dev->priv == NULL)
 		return -ENOMEM;
-	memset(dev->priv, 0, sizeof(struct arcnet_local));
+	memset(dev->priv,0,sizeof(struct arcnet_local));
 	lp=(struct arcnet_local *)(dev->priv);
-
+	
 	dev->open=arcnet_open;
 	dev->stop=arcnet_close;
 	dev->hard_start_xmit=arcnetA_send_packet;
@@ -697,261 +1072,87 @@
 	/* And now fill particular fields with arcnet values */
 	dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
 	dev->hard_header_len=sizeof(struct ClientData);
+	dev->hard_header=arcnetA_header;
+	dev->rebuild_header=arcnetA_rebuild_header;
+	lp->sequence=1;
+	lp->recbuf=0;
+
 	BUGMSG(D_DURING,"ClientData header size is %d.\n",
 		sizeof(struct ClientData));
 	BUGMSG(D_DURING,"HardHeader size is %d.\n",
 		sizeof(struct HardHeader));
 
-		/* since we strip EXTRA_CLIENTDATA bytes off before sending,
-		 * we let Linux add that many bytes to the packet data...
-		 */
-	
-	BUGMSG(D_INIT,"arcnet_probe: resetting card.\n");
-	arcnet_reset(dev);
-	BUGMSG(D_NORMAL,"We appear to be station %d (%02Xh)\n",
-			lp->stationid,lp->stationid);
+	/* get and check the station ID from offset 1 in shmem */
+	lp->stationid = first_mirror[1];
 	if (lp->stationid==0)
-		BUGMSG(D_NORMAL,"WARNING!  Station address 0 is reserved for broadcasts!\n");
-	if (lp->stationid==255)
-		BUGMSG(D_NORMAL,"WARNING!  Station address 255 may confuse DOS networking programs!\n");
+		BUGMSG(D_NORMAL,"WARNING!  Station address 0 is reserved "
+			"for broadcasts!\n");
+	else if (lp->stationid==255)
+		BUGMSG(D_NORMAL,"WARNING!  Station address FF may confuse "
+			"DOS networking programs!\n");
 	dev->dev_addr[0]=lp->stationid;
-	lp->sequence=1;
-	lp->recbuf=0;
 
-	dev->hard_header=arcnetA_header;
-	dev->rebuild_header=arcnetA_rebuild_header;
-	
+	BUGMSG(D_NORMAL,"ARCnet station %02Xh found at %03lXh, IRQ %d, "
+		"ShMem %lXh (%ld bytes).\n",
+		lp->stationid,
+		dev->base_addr,dev->irq,dev->mem_start,
+		dev->mem_end-dev->mem_start+1);
+		
 	return 0;
 }
 
 
-int arcnet_ioprobe(struct device *dev, short ioaddr)
+/* Do a hardware reset on the card, and set up necessary registers.
+ *
+ * This should be called as little as possible, because it disrupts the
+ * token on the network (causes a RECON) and requires a significant delay.
+ *
+ * However, it does make sure the card is in a defined state.
+ */
+int arcnet_reset(struct device *dev,int reset_delay)
 {
-	int airq;
-	unsigned long airqmask;
-
-	BUGMSG(D_INIT,"probing address %Xh\n",ioaddr);
-	BUGMSG(D_INIT," status1=%Xh\n",inb(STATUS));
-
-		
-	/* very simple - all we have to do is reset the card, and if there's
-	 * no irq, it's not an ARCnet.  We can also kill two birds with
-	 * one stone because we detect the IRQ at the same time :)
-	 *
-	 * BUT: some newer cards don't seem to IRQ upon reset, or worse,
-	 * don't reset when BASE+0x08 is read.  This code is no longer
-	 * so simple, and in fact quite dangerous.  It should be redesigned.
-	 */
-	 
-#if 0
-	/* reset the card by reading the reset port */
-	inb(RESET);
-	JIFFER(RESETtime);
-#endif
-
-	/* if status port is FF, there's certainly no arcnet... give up. */
-	if (inb(STATUS)==0xFF)
-	{
-		BUGMSG(D_INIT," probe failed.  Status port empty.\n");
-		return -ENODEV;
-	}
+	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
+	short ioaddr=dev->base_addr;
+	int delayval,recbuf=lp->recbuf;
+	u_char *cardmem;
+	
+	/* no IRQ's, please! */
+	lp->intmask=0;
+	SETMASK;
+	
+	BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
+			dev->name,inb(STATUS));
 
-#if 0
-	/* we'll try to be reasonably sure it's an arcnet by making sure
-	 * the value of the COMMAND port changes automatically once in a
-	 * while.  I have no idea what those values ARE, but at least
-	 * they work.
-	 */
+	if (reset_delay)
 	{
-		int initval,curval;
-		
-		curval=initval=inb(COMMAND);
-		delayval=jiffies+5;
-		while (delayval>=jiffies && curval==initval)
-			curval=inb(COMMAND);
-			
-		if (curval==initval)
-		{
-			BUGLVL(D_INIT," probe failed.  never-changing command port (%02Xh).\n",
-				initval);
-			return -ENODEV;
-		}
+		/* reset the card */
+		inb(RESET);
+		JIFFER(RESETtime);
 	}
-#endif
 
-	BUGMSG(D_INIT," status2=%Xh\n",inb(STATUS));
+	outb(CFLAGScmd|RESETclear, COMMAND); /* clear flags & end reset */
+	outb(CFLAGScmd|CONFIGclear,COMMAND);
 
-	/* now we turn the reset bit off so we can IRQ next reset... */
-	outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
-	if (inb(STATUS) & RESETflag) /* reset flag STILL on */
+	/* verify that the ARCnet signature byte is present */
+	cardmem = (u_char *) dev->mem_start;
+	if (cardmem[0] != TESTvalue)
 	{
-		BUGMSG(D_INIT," probe failed.  eternal reset flag1...(status=%Xh)\n",
-				inb(STATUS));
-		return -ENODEV;
+		BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n");
+		return 1;
 	}
-
-	outb(NORXcmd,COMMAND);
-	outb(0,INTMASK);
-	udelay(1);
-
-	/* set up automatic IRQ detection */
-	airqmask = probe_irq_on();
-	BUGMSG(D_INIT," airqmask=%lXh\n",airqmask);
-
-	/* if we do this, we're sure to get an IRQ since the card
-	 * has just reset and the NORXflag is on until we tell it to
-	 * start receiving.
-	 */
-	outb(NORXflag,INTMASK);
-	udelay(1);
-	outb(0,INTMASK);
-
-	/* and turn the reset flag back off.  On some systems, we NEED to do
-	 * this before we re-enable the IRQ!
-	 */
-	outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
-
-	/* get autoirq results */
-	airq = probe_irq_off(airqmask);
-
-	if (airq>0)
-	{
-		BUGMSG(D_INIT," autoirq is %d\n", airq);
-	}
-	else if (airq<0)
-	{
-		BUGMSG(D_INIT," autoirq MAY be %d (please send mail to Avery)\n",
-			-airq);
-		airq=0;
-	}
-
-	/* if there was no autoirq AND the user hasn't set any defaults,
-	 * give up.
-	 */
-	if (!airq && !(dev->base_addr && dev->irq))
-	{
-		BUGMSG(D_INIT," probe failed.  no autoirq...\n");
-		return -ENODEV;
-	}
-
-	/* otherwise we probably have a card.  Let's make sure. */
-	
-#if 0
-	if (inb(STATUS) & RESETflag) /* reset flag on */
-	{
-		/* now we turn the reset bit off */
-		outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
-	}
-#endif
-	
-	if (inb(STATUS) & RESETflag) /* reset flag STILL on */
-	{
-		BUGMSG(D_INIT," probe failed.  eternal reset flag...(status=%Xh)\n",
-				inb(STATUS));
-		return -ENODEV;
-	}
-	
-	/* okay, we've got a real, live ARCnet on our hands.
-	 * I hope.
-	 */
-	if (!dev->base_addr) dev->base_addr=ioaddr;
-	
-	if (dev->irq < 2)		/* "Auto-IRQ" */
-	{
-		/* we already did the autoirq above, so store the value */
-		dev->irq=airq;
-	}
-	else if (dev->irq == 2)
-	{
-		BUGMSG(D_NORMAL,"IRQ2 == IRQ9, don't worry.\n");
-		dev->irq = 9;
-	}
-
-	BUGMSG(D_INIT,"irq and base address seem okay. (%lXh, IRQ %d)\n",
-			dev->base_addr,dev->irq);
-	return 0;
-}
-
-
-/* A memory probe that is called after the card is reset.
- * It checks for the official TESTvalue in byte 0 and makes sure the buffer
- * has certain characteristics of an ARCnet.
- */
-int arcnet_memprobe(struct device *dev,u_char *addr)
-{
-	BUGMSG(D_INIT,"probing memory at %lXh\n",(u_long)addr);
-		
-	dev->mem_start=0;
-
-	/* ARCnet memory byte 0 is TESTvalue */
-	if (addr[0]!=TESTvalue)
-	{
-		BUGMSG(D_INIT," probe failed.  addr=%lXh, addr[0]=%Xh (not %Xh)\n",
-				(unsigned long)addr,addr[0],TESTvalue);
-		return -ENODEV;
-	}
-	
-	/* now verify the shared memory writability */
-	addr[0]=0x42;
-	if (addr[0]!=0x42)
-	{
-		BUGMSG(D_INIT," probe failed.  addr=%lXh, addr[0]=%Xh (not 42h)\n",
-				(unsigned long)addr,addr[0]);
-	 	return -ENODEV;
-	}
-
-	/* got it!  fill in dev */
-	dev->mem_start=(unsigned long)addr;
-	dev->mem_end=dev->mem_start+512*4-1;
-	dev->rmem_start=dev->mem_start+512*0;
-	dev->rmem_end=dev->mem_start+512*2-1;
-
-	return 0;
-}
-
-
-/* Do a hardware reset on the card.
- */
-int arcnet_reset(struct device *dev)
-{
-	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
-	short ioaddr=dev->base_addr;
-	int delayval,recbuf=lp->recbuf;
-	u_char *cardmem;
-	
-	lp->intmask=0;
-	SETMASK;		/* no IRQ's, please! */
-	
-	BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
-			dev->name,inb(STATUS));
-
-	inb(RESET);		/* Reset by reading this port */
-	JIFFER(RESETtime);
-
-	outb(CFLAGScmd|RESETclear, COMMAND); /* clear flags & end reset */
-	outb(CFLAGScmd|CONFIGclear,COMMAND);
-
-	/* after a reset, the first byte of shared mem is TESTvalue and the
-	 * second byte is our 8-bit ARCnet address.
-	 */
-	cardmem = (u_char *) dev->mem_start;
-	if (cardmem[0] != TESTvalue)
-	{
-		BUGMSG(D_INIT,"reset failed: TESTvalue not present.\n");
-		return 1;
-	}
-	lp->stationid=cardmem[1];  /* save address for later use */
-	
-	/* clear out status variables */
-	recbuf=lp->recbuf=0;
-	lp->txbuf=2;
+	
+	/* clear out status variables */
+	recbuf=lp->recbuf=0;
+	lp->txbuf=2;
 
 	/* enable extended (512-byte) packets */
 	outb(CONFIGcmd|EXTconf,COMMAND);
 	
+#ifndef SLOW_XMIT_COPY
 	/* clean out all the memory to make debugging make more sense :) */
 	BUGLVL(D_DURING)
 		memset((void *)dev->mem_start,0x42,2048);
+#endif
 	
 	/* and enable receive of our first packet to the first buffer */
 	EnableReceiver();
@@ -968,8 +1169,7 @@
 }
 
 
-/*
- * Setup a struct device for ARCnet.  This should really be in net_init.c
+/* Setup a struct device for ARCnet.  This should really be in net_init.c
  * but since there are three different ARCnet devices ANYWAY... <gargle>
  *
  * Actually, the whole idea of having all this kernel-dependent stuff (ie.
@@ -977,17 +1177,18 @@
  *
  * Intelligent defaults?!  Nah.
  */
-
 void arcnet_setup(struct device *dev)
 {
 	int i;
 	for (i=0; i<DEV_NUMBUFFS; i++)
 		skb_queue_head_init(&dev->buffs[i]);
 
-	dev->broadcast[0]	= 0x00;	/* broadcasts on ARCnet are address 0 */
+	dev->broadcast[0]	= 0x00;	/* for us, broadcasts are address 0 */
 	dev->addr_len		= 1;
 	dev->type		= ARPHRD_ARCNET;
-	dev->tx_queue_len 	= 30;	/* Fairly long queue, arcnet is quite speedy */
+	dev->tx_queue_len	= 30;	/* fairly long queue - arcnet is
+					 * quite speedy.
+					 */
 
 	/* New-style flags. */
 	dev->flags		= IFF_BROADCAST;
@@ -999,49 +1200,6 @@
 }
 
 
-/* Initialize the arc0e device.
- */
-static int arcnetE_init(struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
-	ether_setup(dev); /* we're emulating ether here, not ARCnet */
-	dev->dev_addr[0]=0;
-	dev->dev_addr[5]=lp->stationid;
-	dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len-1;
-	dev->open=NULL;
-	dev->stop=NULL;
-	dev->hard_start_xmit=arcnetE_send_packet;
-
-	BUGMSG(D_EXTRA,"ARCnet Ethernet-Encap protocol initialized.\n");
-			
-	return 0;
-}
-
-/* Initialize the arc0s device.
- */
-static int arcnetS_init(struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
-	arcnet_setup(dev);
-       
-	/* And now fill particular fields with arcnet values */
-	dev->dev_addr[0]=lp->stationid;
-	dev->hard_header_len=sizeof(struct S_ClientData);
-	dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len
-		+ S_EXTRA_CLIENTDATA;
-	dev->open=NULL;
-	dev->stop=NULL;
-	dev->hard_start_xmit=arcnetS_send_packet;
-	dev->hard_header=arcnetS_header;
-	dev->rebuild_header=arcnetS_rebuild_header;
-	BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n");
-
-	return 0;
-}
-
-
 /****************************************************************************
  *                                                                          *
  * Open and close the driver                                                *
@@ -1069,13 +1227,20 @@
 		dev->metric=1;
 	}
 
-	BUGLVL(D_EXTRA) printk(version);
-
-	BUGMSG(D_EXTRA,"arcnet_open: resetting card.\n");
+	BUGMSG(D_INIT,"arcnet_open: resetting card.\n");
 	
-	/* try to reset - twice if it fails the first time */
-	if (arcnet_reset(dev) && arcnet_reset(dev))
+#ifdef FAST_IFCONFIG
+	/* try to put the card in a defined state - if it fails the first
+	 * time, actually reset it.
+	 */
+	if (arcnet_reset(dev,0) && arcnet_reset(dev,1))
+		return -ENODEV;
+#else
+	/* reset the card twice in case something goes wrong the first time.
+	 */
+	if (arcnet_reset(dev,1) && arcnet_reset(dev,1))
 		return -ENODEV;
+#endif
 	
 	dev->tbusy=0;
 	dev->interrupt=0;
@@ -1085,7 +1250,8 @@
 	/* The RFC1201 driver is the default - just store */
 	lp->adev=dev;
 	BUGMSG(D_EXTRA,"ARCnet RFC1201 protocol initialized.\n");
-	
+
+#ifdef CONFIG_ARCNET_ETH	
 	/* Initialize the ethernet-encap protocol driver */
 	lp->edev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
 	if (lp->edev == NULL)
@@ -1100,7 +1266,11 @@
 	sprintf(lp->edev->name,"%se",dev->name);
 	lp->edev->init=arcnetE_init;
 	register_netdev(lp->edev);
+#else
+	BUGMSG(D_EXTRA,"Ethernet-Encap protocol not available (disabled).\n");
+#endif
 
+#ifdef CONFIG_ARCNET_1051
 	/* Initialize the RFC1051-encap protocol driver */
 	lp->sdev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
 	memcpy(lp->sdev,dev,sizeof(struct device));
@@ -1108,6 +1278,9 @@
 	sprintf(lp->sdev->name,"%ss",dev->name);
 	lp->sdev->init=arcnetS_init;
 	register_netdev(lp->sdev);
+#else
+	BUGMSG(D_EXTRA,"RFC1051 protocol not available (disabled).\n");
+#endif
 
 	/* we're started */
 	START=1;
@@ -1140,11 +1313,15 @@
 	TBUSY=1;
 	START=0;
 
-	/* Flush TX and disable RX */
+	/* Shut down the card */
+#ifdef FAST_IFCONFIG
+	inb(RESET);	/* reset IRQ won't run if START=0 */
+#else
 	lp->intmask=0;
 	SETMASK;	/* no IRQ's (except RESET, of course) */
 	outb(NOTXcmd,COMMAND);  /* stop transmit */
 	outb(NORXcmd,COMMAND);	/* disable receive */
+#endif
 
 	/* reset more flags */
 	INTERRUPT=0;
@@ -1152,6 +1329,7 @@
 	/* do NOT free lp->adev!!  It's static! */
 	lp->adev=NULL;
 	
+#ifdef CONFIG_ARCNET_ETH
 	/* free the ethernet-encap protocol device */
 	lp->edev->priv=NULL;
 	dev_close(lp->edev);
@@ -1159,7 +1337,9 @@
 	kfree(lp->edev->name);
 	kfree(lp->edev);
 	lp->edev=NULL;
+#endif
 
+#ifdef CONFIG_ARCNET_1051
 	/* free the RFC1051-encap protocol device */
 	lp->sdev->priv=NULL;
 	dev_close(lp->sdev);
@@ -1167,6 +1347,7 @@
 	kfree(lp->sdev->name);
 	kfree(lp->sdev);
 	lp->sdev=NULL;
+#endif
 
 	/* Update the statistics here. (not necessary in ARCnet) */
 
@@ -1229,16 +1410,14 @@
 		
 		if (status&TXFREEflag)	/* transmit _DID_ finish */
 		{
-			BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, inTXh=%d, ticks=%d, mask=%Xh)\n",
-					status,lp->in_txhandler,tickssofar,
-					lp->intmask);
+			BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%d)\n",
+					status,tickssofar,lp->intmask,lp->lasttrans_dest);
 			lp->stats.tx_errors++;
 		}
 		else
 		{
-			BUGMSG(D_NORMAL,"tx timed out (status=%Xh, inTXh=%d, tickssofar=%d, intmask=%Xh)\n",
-					status,lp->in_txhandler,tickssofar,
-					lp->intmask);
+			BUGMSG(D_EXTRA,"tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%d)\n",
+					status,tickssofar,lp->intmask,lp->lasttrans_dest);
 			lp->stats.tx_errors++;
 			lp->stats.tx_aborted_errors++;
 
@@ -1418,289 +1597,99 @@
 }
 
 
-/* Called by the kernel in order to transmit an ethernet-type packet.
+/* After an RFC1201 split packet has been set up, this function calls
+ * arcnetAS_prepare_tx to load the next segment into the card.  This function
+ * does NOT automatically call arcnet_go_tx.
  */
-static int
-arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
+static void arcnetA_continue_tx(struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr,bad;
-	union ArcPacket *arcpacket = 
-		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
-	u_char *arcsoft,daddr;
-	short offset,length=skb->len+1;
-
-	lp->intx++;
+	int ioaddr=dev->base_addr,maxsegsize=XMTU-4;
+	struct Outgoing *out=&(lp->outgoing);
 	
-	bad=arcnet_send_packet_bad(skb,dev);
-	if (bad)
+	BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n",
+		inb(STATUS),lp->intx,lp->in_txhandler,lp->intmask);
+	
+	if (lp->txready)
 	{
-		lp->intx--;
-		return bad;
+		BUGMSG(D_NORMAL,"continue_tx: called with packet in buffer!\n");
+		return;
 	}
-
-	TBUSY=1;
-		
-	if (length>XMTU)
+	
+	if (out->segnum>=out->numsegs)
 	{
-		BUGMSG(D_NORMAL,"MTU must be <= 493 for ethernet encap (length=%d).\n",
-			length);
-		BUGMSG(D_NORMAL,"transmit aborted.\n");
-
-		dev_kfree_skb(skb,FREE_WRITE);
-		lp->intx--;
-		return 0;
+		BUGMSG(D_NORMAL,"continue_tx: building segment %d of %d!\n",
+			out->segnum+1,out->numsegs);
 	}
+
+	if (!out->segnum)	/* first packet */
+		out->hdr->split_flag=((out->numsegs-2)<<1)+1;
+	else
+		out->hdr->split_flag=out->segnum<<1;
+
+	out->seglen=maxsegsize;
+	if (out->seglen>out->dataleft) out->seglen=out->dataleft;
+			
+	BUGMSG(D_TX,"building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n",
+		out->segnum+1,out->seglen,out->numsegs,
+		out->length,out->hdr->split_flag);
+
+	arcnetAS_prepare_tx(dev,((char *)out->hdr)+EXTRA_CLIENTDATA,
+		sizeof(struct ClientData)-EXTRA_CLIENTDATA,
+		out->data,out->seglen,out->hdr->daddr,1);
 		
-	BUGMSG(D_DURING,"starting tx sequence...\n");
+	out->dataleft-=out->seglen;
+	out->data+=out->seglen;
+	out->segnum++;
+}
 
-	lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate btw 2 & 3 */
 
+/* Given an skb, copy a packet into the ARCnet buffers for later transmission
+ * by arcnet_go_tx.
+ */
+static void
+arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
+		char *data,int length,int daddr,int exceptA)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+	struct ClientData *arcsoft;
+	union ArcPacket *arcpacket = 
+		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
+	int offset;
+	
+#ifdef SLOW_XMIT_COPY
+	char *iptr,*iend,*optr;
+#endif
+	
+	lp->txbuf=lp->txbuf^1;	/* XOR with 1 to alternate between 2 and 3 */
+	
+	length+=hdrlen;
+
+	BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
+			hdr,length,data);
+
+#ifndef SLOW_XMIT_COPY
 	/* clean out the page to make debugging make more sense :) */
 	BUGLVL(D_DURING)
 		memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
+#endif
 
-	/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
-	if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
-		daddr=arcpacket->hardheader.destination=0;
-	else
-		daddr=arcpacket->hardheader.destination=
-			((struct ethhdr*)(skb->data))->h_dest[5];
+	arcpacket->hardheader.destination=daddr;
 
 	/* load packet into shared memory */
-	offset=512-length;
-	if (length>MTU)		/* long/exception packet */
+	if (length<=MTU)	/* Normal (256-byte) Packet */
 	{
-		if (length<MinTU) offset-=3;
-		arcpacket->hardheader.offset1=0;
-		arcpacket->hardheader.offset2=offset;
+		arcpacket->hardheader.offset1=offset=256-length;
+		arcsoft=(struct ClientData *)
+			(&arcpacket->raw[offset]);
 	}
-	else			/* short packet */
+	else if (length>=MinTU)	/* Extended (512-byte) Packet */
 	{
-		arcpacket->hardheader.offset1=(offset-=256);
-	}
-	
-	BUGMSG(D_DURING," length=%Xh, offset=%Xh, offset1=%Xh, offset2=%Xh\n",
-			length,offset,arcpacket->hardheader.offset1,
-			arcpacket->hardheader.offset2);
-	
-	arcsoft=&arcpacket->raw[offset];
-	arcsoft[0]=ARC_P_ETHER;
-	arcsoft++;
-		
-	/* copy the packet into ARCnet shmem
-	 *  - the first bytes of ClientData header are skipped
-	 */
-	BUGMSG(D_DURING,"ready to memcpy\n");
-	
-	memcpy(arcsoft,skb->data,skb->len);
-		
-	BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
-			daddr,length);
-				
-	BUGLVL(D_TX)
-	{
-		int countx,county;
-			
-		printk("%6s: packet dump [tx] follows:",dev->name);
-
- 		for (county=0; county<16+(length>=240)*16; county++)
-		{
-			printk("\n[%04X] ",county*16);
-			for (countx=0; countx<16; countx++)
-				printk("%02X ",
-					arcpacket->raw[county*16+countx]);
-		}
-		
-		printk("\n");
-	}
-
-#ifdef VERIFY_ACK
-	lp->lastload_dest=daddr;
-#endif
-	lp->txready=lp->txbuf;	/* packet is ready for sending */
-
-	dev_kfree_skb(skb,FREE_WRITE);
-
-	if (arcnet_go_tx(dev,1))
-	{
-		/* inform upper layers */
-		TBUSY=0;
-		mark_bh(NET_BH);
-	}
-
-	dev->trans_start=jiffies;
-	lp->intx--;
-	
-	/* make sure we didn't ignore a TX IRQ while we were in here */
-	lp->intmask |= TXFREEflag;
-	SETMASK;
-
-	return 0;
-}
-
-
-/* Called by the kernel in order to transmit an RFC1051-type packet.
- */
-static int
-arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr,bad,length;
-	struct S_ClientData *hdr=(struct S_ClientData *)skb->data;
-
-	lp->intx++;
-	
-	bad=arcnet_send_packet_bad(skb,dev);
-	if (bad)
-	{
-		lp->intx--;
-		return bad;
-	}
-	
-	TBUSY=1;
-
-	length = 1 < skb->len ? skb->len : 1;
-
-	BUGLVL(D_SKB)
-	{
-		short i;
-		for(i=0; i<skb->len; i++)
-		{
-			if (i%16 == 0) printk("\n[%04hX] ",i);
-			printk("%02hX ",((unsigned char*)skb->data)[i]);
-		}
-		printk("\n");
-	}
-
-	/* fits in one packet? */
-	if (length-S_EXTRA_CLIENTDATA<=XMTU)
-	{
-		arcnetAS_prepare_tx(dev,
-			skb->data+S_EXTRA_CLIENTDATA,
-			sizeof(struct S_ClientData)-S_EXTRA_CLIENTDATA,
-			skb->data+sizeof(struct S_ClientData),
-			length-sizeof(struct S_ClientData),
-			hdr->daddr,0);
-
-		/* done right away */
-		dev_kfree_skb(skb,FREE_WRITE);
-				
-		if (arcnet_go_tx(dev,1))
-		{
-			/* inform upper layers */
-			TBUSY=0;
-			mark_bh(NET_BH);
-		}
-	}
-	else			/* too big for one - not accepted */
-	{
-		BUGMSG(D_NORMAL,"packet too long (length=%d)\n",
-			length);
-		dev_kfree_skb(skb,FREE_WRITE);
-		lp->stats.tx_dropped++;
-		TBUSY=0;
-		mark_bh(NET_BH);	
-	}
-
-	dev->trans_start=jiffies;
-	lp->intx--;
-
-	/* make sure we didn't ignore a TX IRQ while we were in here */
-	lp->intmask |= TXFREEflag;
-	SETMASK;
-
-	return 0;
-}
-
-
-/* After an RFC1201 split packet has been set up, this function calls
- * arcnetAS_prepare_tx to load the next segment into the card.  This function
- * does NOT automatically call arcnet_go_tx.
- */
-static void arcnetA_continue_tx(struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr,maxsegsize=XMTU-4;
-	struct Outgoing *out=&(lp->outgoing);
-	
-	BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n",
-		inb(STATUS),lp->intx,lp->in_txhandler,lp->intmask);
-	
-	if (lp->txready)
-	{
-		BUGMSG(D_NORMAL,"continue_tx: called with packet in buffer!\n");
-		return;
-	}
-	
-	if (out->segnum>=out->numsegs)
-	{
-		BUGMSG(D_NORMAL,"continue_tx: building segment %d of %d!\n",
-			out->segnum+1,out->numsegs);
-	}
-
-	if (!out->segnum)	/* first packet */
-		out->hdr->split_flag=((out->numsegs-2)<<1)+1;
-	else
-		out->hdr->split_flag=out->segnum<<1;
-
-	out->seglen=maxsegsize;
-	if (out->seglen>out->dataleft) out->seglen=out->dataleft;
-			
-	BUGMSG(D_TX,"building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n",
-		out->segnum+1,out->seglen,out->numsegs,
-		out->length,out->hdr->split_flag);
-
-	arcnetAS_prepare_tx(dev,((char *)out->hdr)+EXTRA_CLIENTDATA,
-		sizeof(struct ClientData)-EXTRA_CLIENTDATA,
-		out->data,out->seglen,out->hdr->daddr,1);
-		
-	out->dataleft-=out->seglen;
-	out->data+=out->seglen;
-	out->segnum++;
-}
-
-
-/* Given an skb, copy a packet into the ARCnet buffers for later transmission
- * by arcnet_go_tx.
- */
-static void
-arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
-		char *data,int length,int daddr,int exceptA)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	struct ClientData *arcsoft;
-	union ArcPacket *arcpacket = 
-		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
-	int offset;
-	
-	lp->txbuf=lp->txbuf^1;	/* XOR with 1 to alternate between 2 and 3 */
-	
-	length+=hdrlen;
-
-	BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
-			hdr,length,data);
-
-	/* clean out the page to make debugging make more sense :) */
-	BUGLVL(D_DURING)
-		memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
-
-	arcpacket->hardheader.destination=daddr;
-
-	/* load packet into shared memory */
-	if (length<=MTU)	/* Normal (256-byte) Packet */
-	{
-		arcpacket->hardheader.offset1=offset=256-length;
-		arcsoft=(struct ClientData *)
-			(&arcpacket->raw[offset]);
-	}
-	else if (length>=MinTU)	/* Extended (512-byte) Packet */
-	{
-		arcpacket->hardheader.offset1=0;
-		arcpacket->hardheader.offset2=offset=512-length;
-		
-		arcsoft=(struct ClientData *)
-			(&arcpacket->raw[offset]);
+		arcpacket->hardheader.offset1=0;
+		arcpacket->hardheader.offset2=offset=512-length;
+		
+		arcsoft=(struct ClientData *)
+			(&arcpacket->raw[offset]);
 	}
 	else if (exceptA)		/* RFC1201 Exception Packet */
 	{
@@ -1735,8 +1724,17 @@
 	 */
 	memcpy((u_char*)arcsoft,
 		(u_char*)hdr,hdrlen);
+#ifdef SLOW_XMIT_COPY
+	for (iptr=data,iend=iptr+length-hdrlen,optr=(char *)arcsoft+hdrlen;
+		iptr<iend; iptr++,optr++)
+	{
+		*optr=*iptr;
+		/*udelay(5);*/
+	}
+#else
 	memcpy((u_char*)arcsoft+hdrlen,
 		data,length-hdrlen);
+#endif
 		
 	BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
 			daddr,length);
@@ -1758,9 +1756,7 @@
 		printk("\n");
 	}
 
-#ifdef VERIFY_ACK
 	lp->lastload_dest=daddr;
-#endif
 	lp->txready=lp->txbuf;	/* packet is ready for sending */
 }
 
@@ -1792,7 +1788,7 @@
 		}
 		return 0;
 	}
-
+	
 	/* start sending */
 	outb(TXcmd|(lp->txready<<3),COMMAND);
 
@@ -1800,10 +1796,8 @@
 	lp->txready=0;
 	lp->sending++;
 
-#ifdef VERIFY_ACK	
 	lp->lasttrans_dest=lp->lastload_dest;
 	lp->lastload_dest=0;
-#endif
 
 	lp->intmask |= TXFREEflag;
 
@@ -1829,18 +1823,29 @@
 arcnet_interrupt(int irq,struct pt_regs *regs)
 {
 	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	int ioaddr;
 	
-	BUGMSG(D_DURING,"in arcnet_interrupt\n");
-
 	if (dev==NULL)
 	{
-		BUGLVL(D_EXTRA)
+		BUGLVL(D_DURING)
 			printk("arcnet: irq %d for unknown device.\n", irq);
 		return;
 	}
 	
-	if (!dev->start) return;
+	BUGMSG(D_DURING,"in arcnet_interrupt\n");
 
+	/* RESET flag was enabled - if !dev->start, we must clear it right
+	 * away (but nothing else) since inthandler() is never called.
+	 */
+	ioaddr=dev->base_addr;
+	if (!dev->start)
+	{
+		if (inb(STATUS) & RESETflag)
+			outb(CFLAGScmd|RESETclear, COMMAND);
+		return;
+	}
+
+	/* Call the "real" interrupt handler. */
 	arcnet_inthandler(dev);
 }
 
@@ -1871,93 +1876,27 @@
 		status = inb(STATUS);
 		didsomething=0;
 	
+
 		/* RESET flag was enabled - card is resetting and if RX
 		 * is disabled, it's NOT because we just got a packet.
 		 */
 		if (status & RESETflag)
 		{
-			outb(CFLAGScmd|RESETclear,COMMAND);
-			BUGMSG(D_INIT,"reset irq (status=%Xh)\n",
+			BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
 					status);
+			arcnet_reset(dev,0);
+			
+			/* all other flag values are just garbage */
+			break;
 		}
-#ifdef DETECT_RECONFIGS
-		if (status & (lp->intmask) & RECONflag)
+		
+		
+		/* RX is inhibited - we must have received something. */
+		if (status & lp->intmask & NORXflag)
 		{
-			outb(CFLAGScmd|CONFIGclear,COMMAND);
-			lp->stats.tx_carrier_errors++;
-			
-			#ifdef SHOW_RECONFIGS
-			BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n",
-					status);
-			#endif /* SHOW_RECONFIGS */
-			
-			#ifdef RECON_THRESHOLD
-			/* is the RECON info empty or old? */
-			if (!lp->first_recon || !lp->last_recon || 
-				jiffies-lp->last_recon > HZ*10)
-			{
-				if (lp->network_down)
-					BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
-				lp->first_recon=lp->last_recon=jiffies;
-				lp->num_recons=lp->network_down=0;
-				
-				BUGMSG(D_DURING,"recon: clearing counters.\n");
-			}
-			else /* add to current RECON counter */
-			{
-				lp->last_recon=jiffies;
-				lp->num_recons++;
-				
-				BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
-					lp->num_recons,
-					(lp->last_recon-lp->first_recon)/HZ,
-					lp->network_down);
-
-				/* if network is marked up;
-				 * and first_recon and last_recon are 60+ sec
-				 *   apart;
-				 * and the average no. of recons counted is
-				 *   > RECON_THRESHOLD/min;
-				 * then print a warning message.
-				 */
-				if (!lp->network_down
-				    && (lp->last_recon-lp->first_recon)<=HZ*60
-				    && lp->num_recons >= RECON_THRESHOLD)
-				{
-					lp->network_down=1;
-					BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
-				}
-				else if (!lp->network_down
-				    && lp->last_recon-lp->first_recon > HZ*60)
-				{
-					/* reset counters if we've gone for
-					 * over a minute.
-					 */
-					lp->first_recon=lp->last_recon;
-					lp->num_recons=1;
-				}
-			}
-			#endif
-		}
-		#ifdef RECON_THRESHOLD
-		else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
-		{
-			if (lp->network_down)
-				BUGMSG(D_NORMAL,"cabling restored?\n");
-			lp->first_recon=lp->last_recon=0;
-			lp->num_recons=lp->network_down=0;
-			
-			BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
-		}
-		#endif
-#endif /* DETECT_RECONFIGS */
-
-		/* RX is inhibited - we must have received something. */
-		if (status & lp->intmask & NORXflag)
-		{
-			int recbuf=lp->recbuf=!lp->recbuf;
-
-			BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
+			int recbuf=lp->recbuf=!lp->recbuf;
+
+			BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
 					status);
 
 			/* enable receive of our next packet */
@@ -1983,12 +1922,11 @@
 			BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
 					status,out->numsegs,out->segnum,out->skb);
 					
-#ifdef VERIFY_ACK
 			if (was_sending && !(status&TXACKflag))
 			{
 				if (lp->lasttrans_dest != 0)
 				{
-					BUGMSG(D_NORMAL,"transmit was not acknowledged! (status=%Xh, dest=%d)\n",
+					BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%d)\n",
 						status,lp->lasttrans_dest);
 					lp->stats.tx_errors++;
 					lp->stats.tx_carrier_errors++;
@@ -2000,7 +1938,7 @@
 							lp->lasttrans_dest);
 				}
 			}
-#endif
+
 			/* send packet if there is one */
 			arcnet_go_tx(dev,0);
 			didsomething++;
@@ -2063,6 +2001,78 @@
 			arcnet_go_tx(dev,0);
 			didsomething++;
 		}
+
+#ifdef DETECT_RECONFIGS
+		if (status & (lp->intmask) & RECONflag)
+		{
+			outb(CFLAGScmd|CONFIGclear,COMMAND);
+			lp->stats.tx_carrier_errors++;
+			
+			#ifdef SHOW_RECONFIGS
+			BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n",
+					status);
+			#endif /* SHOW_RECONFIGS */
+			
+			#ifdef RECON_THRESHOLD
+			/* is the RECON info empty or old? */
+			if (!lp->first_recon || !lp->last_recon || 
+				jiffies-lp->last_recon > HZ*10)
+			{
+				if (lp->network_down)
+					BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
+				lp->first_recon=lp->last_recon=jiffies;
+				lp->num_recons=lp->network_down=0;
+				
+				BUGMSG(D_DURING,"recon: clearing counters.\n");
+			}
+			else /* add to current RECON counter */
+			{
+				lp->last_recon=jiffies;
+				lp->num_recons++;
+				
+				BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
+					lp->num_recons,
+					(lp->last_recon-lp->first_recon)/HZ,
+					lp->network_down);
+
+				/* if network is marked up;
+				 * and first_recon and last_recon are 60+ sec
+				 *   apart;
+				 * and the average no. of recons counted is
+				 *   > RECON_THRESHOLD/min;
+				 * then print a warning message.
+				 */
+				if (!lp->network_down
+				    && (lp->last_recon-lp->first_recon)<=HZ*60
+				    && lp->num_recons >= RECON_THRESHOLD)
+				{
+					lp->network_down=1;
+					BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
+				}
+				else if (!lp->network_down
+				    && lp->last_recon-lp->first_recon > HZ*60)
+				{
+					/* reset counters if we've gone for
+					 * over a minute.
+					 */
+					lp->first_recon=lp->last_recon;
+					lp->num_recons=1;
+				}
+			}
+			#endif
+		}
+		#ifdef RECON_THRESHOLD
+		else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
+		{
+			if (lp->network_down)
+				BUGMSG(D_NORMAL,"cabling restored?\n");
+			lp->first_recon=lp->last_recon=0;
+			lp->num_recons=lp->network_down=0;
+			
+			BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
+		}
+		#endif
+#endif /* DETECT_RECONFIGS */
 	} while (--boguscount && didsomething);
 
 	BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n\n",
@@ -2138,13 +2148,17 @@
 	case ARC_P_NOVELL_EC:
 		arcnetA_rx(lp->adev,arcsoft,length,saddr,daddr);
 		break;
+#ifdef CONFIG_ARCNET_ETH
 	case ARC_P_ETHER:
 		arcnetE_rx(lp->edev,arcsoft,length,saddr,daddr);
-		break;		
+		break;
+#endif
+#ifdef CONFIG_ARCNET_1051
 	case ARC_P_IP_RFC1051:
 	case ARC_P_ARP_RFC1051:
 		arcnetS_rx(lp->sdev,arcsoft,length,saddr,daddr);
 		break;
+#endif
 	case ARC_P_LANSOFT: /* don't understand.  fall through. */
 	default:
 		BUGMSG(D_NORMAL,"received unknown protocol %d (%Xh) from station %d.\n",
@@ -2172,9 +2186,11 @@
        	}
 
 
+#ifndef SLOW_XMIT_COPY
 	/* clean out the page to make debugging make more sense :) */
 	BUGLVL(D_DURING)
 		memset((void *)arcpacket->raw,0x42,512);
+#endif
 
 
 	/* If any worth-while packets have been received, a mark_bh(NET_BH)
@@ -2328,7 +2344,7 @@
 
 		if (in->skb && in->sequence!=arcsoft->sequence)
 		{
-			BUGMSG(D_NORMAL,"wrong seq number, aborting assembly (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
+			BUGMSG(D_NORMAL,"wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
 				saddr,in->sequence,arcsoft->sequence,
 				arcsoft->split_flag);
 	        	kfree_skb(in->skb,FREE_WRITE);
@@ -2478,49 +2494,510 @@
 }
 
 
-/* Packet receiver for non-standard ethernet-style packets
+
+
+/****************************************************************************
+ *                                                                          *
+ * Miscellaneous routines                                                   *
+ *                                                                          *
+ ****************************************************************************/
+
+
+/* Get the current statistics.	This may be called with the card open or
+ * closed.
  */
-static void
-arcnetE_rx(struct device *dev,u_char *arcsoft,
-	int length,u_char saddr, u_char daddr)
+
+static struct enet_statistics *
+arcnet_get_stats(struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	struct sk_buff *skb;
-	
-	BUGMSG(D_DURING,"it's an ethernet-encap packet (length=%d)\n",
+
+	return &lp->stats;
+}
+
+#if 0
+/* Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1	Promiscuous mode, receive all packets
+ * num_addrs == 0	Normal mode, clear multicast list
+ * num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+ *			best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev)
+{
+#if 0	  /* no promiscuous mode at all on most ARCnet models */
+	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
+
+	short ioaddr = dev->base_addr;
+	if (num_addrs) {
+		outw(69, ioaddr);		/* Enable promiscuous mode */
+	} else
+		outw(99, ioaddr);		/* Disable promiscuous mode, use normal mode */
+#endif
+}
+#endif
+
+/* Create the ARCnet ClientData header for an arbitrary protocol layer
+ *
+ * saddr=NULL	means use device source address (always will anyway)
+ * daddr=NULL	means leave destination address (eg unresolved arp)
+ */
+int arcnetA_header(struct sk_buff *skb,struct device *dev,
+		unsigned short type,void *daddr,void *saddr,unsigned len)
+{
+	struct ClientData *head = (struct ClientData *)
+		skb_push(skb,dev->hard_header_len);
+	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
+
+	BUGMSG(D_DURING,"create header from %d to %d; protocol %d (%Xh); size %u.\n",
+			saddr ? *(u_char*)saddr : -1,
+			daddr ? *(u_char*)daddr : -1,
+			type,type,len);
+
+	/* set the protocol ID according to RFC1201 */
+	switch(type)
+	{
+	case ETH_P_IP:
+		head->protocol_id=ARC_P_IP;
+		break;
+	case ETH_P_ARP:
+		head->protocol_id=ARC_P_ARP;
+		break;
+	case ETH_P_RARP:
+		head->protocol_id=ARC_P_RARP;
+		break;
+	case ETH_P_IPX:
+	case ETH_P_802_3:
+	case ETH_P_802_2:
+		head->protocol_id=ARC_P_IPX;
+		break;
+	case ETH_P_ATALK:
+		head->protocol_id=ARC_P_ATALK;
+		break;
+	default:
+		BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n",
+			type,type);
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
+		return 0;
+	}	
+
+	/*
+	 * Set the source hardware address.
+	 *
+	 * This is pretty pointless for most purposes, but it can help
+	 * in debugging.  saddr is stored in the ClientData header and
+	 * removed before sending the packet (since ARCnet does not allow
+	 * us to change the source address in the actual packet sent)
+	 */
+	if(saddr)
+		head->saddr=((u_char*)saddr)[0];
+	else
+		head->saddr=((u_char*)(dev->dev_addr))[0];
+
+	head->split_flag=0;	/* split packets are done elsewhere */
+	head->sequence=0;	/* so are sequence numbers */
+
+	/* supposedly if daddr is NULL, we should ignore it... */
+	if(daddr)
+	{
+		head->daddr=((u_char*)daddr)[0];
+		return dev->hard_header_len;
+	}
+	else
+		head->daddr=0;	/* better fill one in anyway */
+		
+	return -dev->hard_header_len;
+}
+
+
+
+/* Rebuild the ARCnet ClientData header. This is called after an ARP
+ * (or in future other address resolution) has completed on this
+ * sk_buff. We now let ARP fill in the other fields.
+ */
+int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst,
+		struct sk_buff *skb)
+{
+	struct ClientData *head = (struct ClientData *)buff;
+	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
+	int status;
+
+	/*
+	 * Only ARP and IP are currently supported
+	 */
+	 
+	if(head->protocol_id != ARC_P_IP) 
+	{
+		BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n",
+			head->protocol_id,head->protocol_id);
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
+		head->daddr=0;
+		/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/
+		return 0;
+	}
+
+	/*
+	 * Try and get ARP to resolve the header.
+	 */
+#ifdef CONFIG_INET	 
+	BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n",
+			head->saddr,head->daddr,head->protocol_id);
+	status=arp_find(&(head->daddr), dst, dev, dev->pa_addr, skb)? 1 : 0;
+	BUGMSG(D_DURING," rebuilt: from %d to %d; protocol %Xh\n",
+			head->saddr,head->daddr,head->protocol_id);
+	return status;
+#else
+	return 0;	
+#endif	
+}
+
+
+/* Determine a packet's protocol ID.
+ *
+ * With ARCnet we have to convert everything to Ethernet-style stuff.
+ */
+unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev)
+{
+	struct ClientData *head;
+	struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
+
+	/* Pull off the arcnet header. */
+	skb->mac.raw=skb->data;
+	skb_pull(skb,dev->hard_header_len);
+	head=(struct ClientData *)skb->mac.raw;
+	
+	if (head->daddr==0)
+		skb->pkt_type=PACKET_BROADCAST;
+	else if (dev->flags&IFF_PROMISC)
+	{
+		/* if we're not sending to ourselves :) */
+		if (head->daddr != dev->dev_addr[0])
+			skb->pkt_type=PACKET_OTHERHOST;
+	}
+	
+	/* now return the protocol number */
+	switch (head->protocol_id)
+	{
+	case ARC_P_IP:		return htons(ETH_P_IP);
+	case ARC_P_ARP:		return htons(ETH_P_ARP);
+	case ARC_P_RARP:	return htons(ETH_P_RARP);
+
+	case ARC_P_IPX:
+	case ARC_P_NOVELL_EC:
+		return htons(ETH_P_802_3);
+	default:
+		BUGMSG(D_NORMAL,"received packet of unknown protocol id %d (%Xh)\n",
+				head->protocol_id,head->protocol_id);
+		lp->stats.rx_errors++;
+		lp->stats.rx_crc_errors++;
+		return 0;
+	}
+
+	return htons(ETH_P_IP);
+}
+
+
+#ifdef CONFIG_ARCNET_ETH
+/****************************************************************************
+ *                                                                          *
+ * Ethernet-Encap Support                                                   *
+ *                                                                          *
+ ****************************************************************************/
+
+/* Initialize the arc0e device.
+ */
+static int arcnetE_init(struct device *dev)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+
+	ether_setup(dev); /* we're emulating ether here, not ARCnet */
+	dev->dev_addr[0]=0;
+	dev->dev_addr[5]=lp->stationid;
+	dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len-1;
+	dev->open=NULL;
+	dev->stop=NULL;
+	dev->hard_start_xmit=arcnetE_send_packet;
+
+	BUGMSG(D_EXTRA,"ARCnet Ethernet-Encap protocol initialized.\n");
+			
+	return 0;
+}
+
+
+/* Called by the kernel in order to transmit an ethernet-type packet.
+ */
+static int
+arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+	int ioaddr=dev->base_addr,bad;
+	union ArcPacket *arcpacket = 
+		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
+	u_char *arcsoft,daddr;
+	short offset,length=skb->len+1;
+
+	lp->intx++;
+	
+	bad=arcnet_send_packet_bad(skb,dev);
+	if (bad)
+	{
+		lp->intx--;
+		return bad;
+	}
+
+	TBUSY=1;
+		
+	if (length>XMTU)
+	{
+		BUGMSG(D_NORMAL,"MTU must be <= 493 for ethernet encap (length=%d).\n",
+			length);
+		BUGMSG(D_NORMAL,"transmit aborted.\n");
+
+		dev_kfree_skb(skb,FREE_WRITE);
+		lp->intx--;
+		return 0;
+	}
+		
+	BUGMSG(D_DURING,"starting tx sequence...\n");
+
+	lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate btw 2 & 3 */
+
+#ifndef SLOW_XMIT_COPY
+	/* clean out the page to make debugging make more sense :) */
+	BUGLVL(D_DURING)
+		memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
+#endif
+
+	/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
+	if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
+		daddr=arcpacket->hardheader.destination=0;
+	else
+		daddr=arcpacket->hardheader.destination=
+			((struct ethhdr*)(skb->data))->h_dest[5];
+
+	/* load packet into shared memory */
+	offset=512-length;
+	if (length>MTU)		/* long/exception packet */
+	{
+		if (length<MinTU) offset-=3;
+		arcpacket->hardheader.offset1=0;
+		arcpacket->hardheader.offset2=offset;
+	}
+	else			/* short packet */
+	{
+		arcpacket->hardheader.offset1=(offset-=256);
+	}
+	
+	BUGMSG(D_DURING," length=%Xh, offset=%Xh, offset1=%Xh, offset2=%Xh\n",
+			length,offset,arcpacket->hardheader.offset1,
+			arcpacket->hardheader.offset2);
+	
+	arcsoft=&arcpacket->raw[offset];
+	arcsoft[0]=ARC_P_ETHER;
+	arcsoft++;
+		
+	/* copy the packet into ARCnet shmem
+	 *  - the first bytes of ClientData header are skipped
+	 */
+	BUGMSG(D_DURING,"ready to memcpy\n");
+	
+	memcpy(arcsoft,skb->data,skb->len);
+		
+	BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
+			daddr,length);
+				
+	BUGLVL(D_TX)
+	{
+		int countx,county;
+			
+		printk("%6s: packet dump [tx] follows:",dev->name);
+
+ 		for (county=0; county<16+(length>=240)*16; county++)
+		{
+			printk("\n[%04X] ",county*16);
+			for (countx=0; countx<16; countx++)
+				printk("%02X ",
+					arcpacket->raw[county*16+countx]);
+		}
+		
+		printk("\n");
+	}
+
+	lp->lastload_dest=daddr;
+	lp->txready=lp->txbuf;	/* packet is ready for sending */
+
+	dev_kfree_skb(skb,FREE_WRITE);
+
+	if (arcnet_go_tx(dev,1))
+	{
+		/* inform upper layers */
+		TBUSY=0;
+		mark_bh(NET_BH);
+	}
+
+	dev->trans_start=jiffies;
+	lp->intx--;
+	
+	/* make sure we didn't ignore a TX IRQ while we were in here */
+	lp->intmask |= TXFREEflag;
+	SETMASK;
+
+	return 0;
+}
+
+
+/* Packet receiver for ethernet-encap packets.
+ */
+static void
+arcnetE_rx(struct device *dev,u_char *arcsoft,
+	int length,u_char saddr, u_char daddr)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+	struct sk_buff *skb;
+	
+	BUGMSG(D_DURING,"it's an ethernet-encap packet (length=%d)\n",
+			length);
+
+       	skb = alloc_skb(length, GFP_ATOMIC);
+       	if (skb == NULL) {
+       		BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
+       		lp->stats.rx_dropped++;
+       		return;
+       	}
+       	
+       	skb->len = length;
+       	skb->dev = dev;
+       	
+       	memcpy(skb->data,(u_char *)arcsoft+1,length-1);
+
+        BUGLVL(D_SKB)
+        {
+		short i;
+		printk("%6s: rx skb dump follows:\n",dev->name);
+                for(i=0; i<skb->len; i++)
+                {
+			if (i%16==0)
+				printk("\n[%04hX] ",i);
+			else
+                        	printk("%02hX ",((u_char *)skb->data)[i]);
+		}
+                printk("\n");
+        }
+        
+	skb->protocol=eth_type_trans(skb,dev);
+        
+        netif_rx(skb);
+}
+
+#endif /* CONFIG_ARCNET_ETH */
+
+#ifdef CONFIG_ARCNET_1051
+/****************************************************************************
+ *                                                                          *
+ * RFC1051 Support                                                          *
+ *                                                                          *
+ ****************************************************************************/
+
+/* Initialize the arc0s device.
+ */
+static int arcnetS_init(struct device *dev)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+
+	arcnet_setup(dev);
+       
+	/* And now fill particular fields with arcnet values */
+	dev->dev_addr[0]=lp->stationid;
+	dev->hard_header_len=sizeof(struct S_ClientData);
+	dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len
+		+ S_EXTRA_CLIENTDATA;
+	dev->open=NULL;
+	dev->stop=NULL;
+	dev->hard_start_xmit=arcnetS_send_packet;
+	dev->hard_header=arcnetS_header;
+	dev->rebuild_header=arcnetS_rebuild_header;
+	BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n");
+
+	return 0;
+}
+
+
+/* Called by the kernel in order to transmit an RFC1051-type packet.
+ */
+static int
+arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+	int ioaddr=dev->base_addr,bad,length;
+	struct S_ClientData *hdr=(struct S_ClientData *)skb->data;
+
+	lp->intx++;
+	
+	bad=arcnet_send_packet_bad(skb,dev);
+	if (bad)
+	{
+		lp->intx--;
+		return bad;
+	}
+	
+	TBUSY=1;
+
+	length = 1 < skb->len ? skb->len : 1;
+
+	BUGLVL(D_SKB)
+	{
+		short i;
+		for(i=0; i<skb->len; i++)
+		{
+			if (i%16 == 0) printk("\n[%04hX] ",i);
+			printk("%02hX ",((unsigned char*)skb->data)[i]);
+		}
+		printk("\n");
+	}
+
+	/* fits in one packet? */
+	if (length-S_EXTRA_CLIENTDATA<=XMTU)
+	{
+		arcnetAS_prepare_tx(dev,
+			skb->data+S_EXTRA_CLIENTDATA,
+			sizeof(struct S_ClientData)-S_EXTRA_CLIENTDATA,
+			skb->data+sizeof(struct S_ClientData),
+			length-sizeof(struct S_ClientData),
+			hdr->daddr,0);
+
+		/* done right away */
+		dev_kfree_skb(skb,FREE_WRITE);
+				
+		if (arcnet_go_tx(dev,1))
+		{
+			/* inform upper layers */
+			TBUSY=0;
+			mark_bh(NET_BH);
+		}
+	}
+	else			/* too big for one - not accepted */
+	{
+		BUGMSG(D_NORMAL,"packet too long (length=%d)\n",
 			length);
+		dev_kfree_skb(skb,FREE_WRITE);
+		lp->stats.tx_dropped++;
+		TBUSY=0;
+		mark_bh(NET_BH);	
+	}
 
-       	skb = alloc_skb(length, GFP_ATOMIC);
-       	if (skb == NULL) {
-       		BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
-       		lp->stats.rx_dropped++;
-       		return;
-       	}
-       	
-       	skb->len = length;
-       	skb->dev = dev;
-       	
-       	memcpy(skb->data,(u_char *)arcsoft+1,length-1);
+	dev->trans_start=jiffies;
+	lp->intx--;
 
-        BUGLVL(D_SKB)
-        {
-		short i;
-		printk("%6s: rx skb dump follows:\n",dev->name);
-                for(i=0; i<skb->len; i++)
-                {
-			if (i%16==0)
-				printk("\n[%04hX] ",i);
-			else
-                        	printk("%02hX ",((u_char *)skb->data)[i]);
-		}
-                printk("\n");
-        }
-        
-	skb->protocol=eth_type_trans(skb,dev);
-        
-        netif_rx(skb);
+	/* make sure we didn't ignore a TX IRQ while we were in here */
+	lp->intmask |= TXFREEflag;
+	SETMASK;
+
+	return 0;
 }
 
+
 /* Packet receiver for RFC1051 packets; 
  */
 static void
@@ -2578,122 +3055,6 @@
 }
 
 
-
-/****************************************************************************
- *                                                                          *
- * Miscellaneous routines                                                   *
- *                                                                          *
- ****************************************************************************/
-
-
-/* Get the current statistics.	This may be called with the card open or
- * closed.
- */
-
-static struct enet_statistics *
-arcnet_get_stats(struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
-	return &lp->stats;
-}
-
-#if 0
-/* Set or clear the multicast filter for this adaptor.
- * num_addrs == -1	Promiscuous mode, receive all packets
- * num_addrs == 0	Normal mode, clear multicast list
- * num_addrs > 0	Multicast mode, receive normal and MC packets, and do
- *			best-effort filtering.
- */
-static void
-set_multicast_list(struct device *dev)
-{
-#if 0	  /* no promiscuous mode at all on most ARCnet models */
-	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-
-	short ioaddr = dev->base_addr;
-	if (num_addrs) {
-		outw(69, ioaddr);		/* Enable promiscuous mode */
-	} else
-		outw(99, ioaddr);		/* Disable promiscuous mode, use normal mode */
-#endif
-}
-#endif
-
-/* Create the ARCnet ClientData header for an arbitrary protocol layer
- *
- * saddr=NULL	means use device source address (always will anyway)
- * daddr=NULL	means leave destination address (eg unresolved arp)
- */
-int arcnetA_header(struct sk_buff *skb,struct device *dev,
-		unsigned short type,void *daddr,void *saddr,unsigned len)
-{
-	struct ClientData *head = (struct ClientData *)
-		skb_push(skb,dev->hard_header_len);
-	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-
-	BUGMSG(D_DURING,"create header from %d to %d; protocol %d (%Xh); size %u.\n",
-			saddr ? *(u_char*)saddr : -1,
-			daddr ? *(u_char*)daddr : -1,
-			type,type,len);
-
-	/* set the protocol ID according to RFC1201 */
-	switch(type)
-	{
-	case ETH_P_IP:
-		head->protocol_id=ARC_P_IP;
-		break;
-	case ETH_P_ARP:
-		head->protocol_id=ARC_P_ARP;
-		break;
-	case ETH_P_RARP:
-		head->protocol_id=ARC_P_RARP;
-		break;
-	case ETH_P_IPX:
-	case ETH_P_802_3:
-	case ETH_P_802_2:
-		head->protocol_id=ARC_P_IPX;
-		break;
-	case ETH_P_ATALK:
-		head->protocol_id=ARC_P_ATALK;
-		break;
-	default:
-		BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n",
-			type,type);
-		lp->stats.tx_errors++;
-		lp->stats.tx_aborted_errors++;
-		return 0;
-	}	
-
-	/*
-	 * Set the source hardware address.
-	 *
-	 * This is pretty pointless for most purposes, but it can help
-	 * in debugging.  saddr is stored in the ClientData header and
-	 * removed before sending the packet (since ARCnet does not allow
-	 * us to change the source address in the actual packet sent)
-	 */
-	if(saddr)
-		head->saddr=((u_char*)saddr)[0];
-	else
-		head->saddr=((u_char*)(dev->dev_addr))[0];
-
-	head->split_flag=0;	/* split packets are done elsewhere */
-	head->sequence=0;	/* so are sequence numbers */
-
-	/* supposedly if daddr is NULL, we should ignore it... */
-	if(daddr)
-	{
-		head->daddr=((u_char*)daddr)[0];
-		return dev->hard_header_len;
-	}
-	else
-		head->daddr=0;	/* better fill one in anyway */
-		
-	return -dev->hard_header_len;
-}
-
-
 /* Create the ARCnet ClientData header for an arbitrary protocol layer
  *
  * saddr=NULL	means use device source address (always will anyway)
@@ -2751,49 +3112,10 @@
 }
 
 
-
 /* Rebuild the ARCnet ClientData header. This is called after an ARP
  * (or in future other address resolution) has completed on this
  * sk_buff. We now let ARP fill in the other fields.
  */
-int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst,
-		struct sk_buff *skb)
-{
-	struct ClientData *head = (struct ClientData *)buff;
-	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-	int status;
-
-	/*
-	 * Only ARP and IP are currently supported
-	 */
-	 
-	if(head->protocol_id != ARC_P_IP) 
-	{
-		BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n",
-			head->protocol_id,head->protocol_id);
-		lp->stats.tx_errors++;
-		lp->stats.tx_aborted_errors++;
-		head->daddr=0;
-		/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/
-		return 0;
-	}
-
-	/*
-	 * Try and get ARP to resolve the header.
-	 */
-#ifdef CONFIG_INET	 
-	BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n",
-			head->saddr,head->daddr,head->protocol_id);
-	status=arp_find(&(head->daddr), dst, dev, dev->pa_addr, skb)? 1 : 0;
-	BUGMSG(D_DURING," rebuilt: from %d to %d; protocol %Xh\n",
-			head->saddr,head->daddr,head->protocol_id);
-	return status;
-#else
-	return 0;	
-#endif	
-}
-
-
 int arcnetS_rebuild_header(void *buff,struct device *dev,unsigned long dst,
 		struct sk_buff *skb)
 {
@@ -2830,47 +3152,6 @@
  *
  * With ARCnet we have to convert everything to Ethernet-style stuff.
  */
-unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev)
-{
-	struct ClientData *head;
-	struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
-
-	/* Pull off the arcnet header. */
-	skb->mac.raw=skb->data;
-	skb_pull(skb,dev->hard_header_len);
-	head=(struct ClientData *)skb->mac.raw;
-	
-	if (head->daddr==0)
-		skb->pkt_type=PACKET_BROADCAST;
-	else if (dev->flags&IFF_PROMISC)
-	{
-		/* if we're not sending to ourselves :) */
-		if (head->daddr != dev->dev_addr[0])
-			skb->pkt_type=PACKET_OTHERHOST;
-	}
-	
-	/* now return the protocol number */
-	switch (head->protocol_id)
-	{
-	case ARC_P_IP:		return htons(ETH_P_IP);
-	case ARC_P_ARP:		return htons(ETH_P_ARP);
-	case ARC_P_RARP:	return htons(ETH_P_RARP);
-
-	case ARC_P_IPX:
-	case ARC_P_NOVELL_EC:
-		return htons(ETH_P_802_3);
-	default:
-		BUGMSG(D_NORMAL,"received packet of unknown protocol id %d (%Xh)\n",
-				head->protocol_id,head->protocol_id);
-		lp->stats.rx_errors++;
-		lp->stats.rx_crc_errors++;
-		return 0;
-	}
-
-	return htons(ETH_P_IP);
-}
-
-
 unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev)
 {
 	struct S_ClientData *head;
@@ -2907,7 +3188,7 @@
 	return htons(ETH_P_IP);
 }
 
-
+#endif	/* CONFIG_ARCNET_1051 */
 
 /****************************************************************************
  *                                                                          *

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this