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

Next file: linux/drivers/net/com20020.c
Previous file: linux/drivers/net/arc-rimi.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.52/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
@@ -17,6 +17,26 @@
 
 	**********************
 
+	v2.91 ALPHA (97/19/08)
+	  - Add counting of octets in/out.
+
+	v2.90 ALPHA (97/08/08)
+	  - Add support for kernel command line parsing so that chipset
+	    drivers are usable when compiled in.
+
+	v2.80 ALPHA (97/08/01)
+	  - Split source into multiple files; generic arcnet support and
+	    individual chipset drivers. <dwmw2@cam.ac.uk>
+
+	v2.61 ALPHA (97/07/30)    by David Woodhouse (dwmw2@cam.ac.uk) for
+	                            Nortel (Northern Telecom).
+          - Added support for IO-mapped modes and for SMC COM20020 chipset.
+	  - Fixed (avoided) race condition in send_packet routines which was
+            discovered when the buffer copy routines got slow (?).
+          - Fixed support for device naming at load time.
+	  - Added backplane, clock and timeout options for COM20020.
+	  - Added support for promiscuous mode.
+
 	v2.60 ALPHA (96/11/23)
 	  - Added patch from Vojtech Pavlik <vojtech@atrey.karlin.mff.cuni.cz>
 	    and Martin Mares <mj@k332.feld.cvut.cz> to make the driver work
@@ -95,30 +115,26 @@
            This is half-done in ARCnet 2.60, but still uses some
            undocumented i386 stuff.  (We shouldn't call phys_to_virt,
            for example.)
+	 - Allow use of RFC1051 or Ether devices without RFC1201.
+	 - Keep separate stats for each device.
          - Support "arpless" mode like NetBSD does, and as recommended
            by the (obsoleted) RFC1051.
-         - Some way to make RIM_I_MODE runtime switchable?  Yuck...
          - Smarter recovery from RECON-during-transmit conditions. (ie.
            retransmit immediately)
-         - Make arcnetE_send_packet use arcnet_prepare_tx for loading the
-           packet into ARCnet memory.
-         - Probe for multiple devices in one shot (trying to decide whether
-           to do it the "ugly" way or not).
          - Add support for the new 1.3.x IP header cache, and other features.
          - 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)
+     Does this work now, with IO_MAPPED_BUFFERS?
+
          - Autoconfigure PDI5xxPlus cards. (I now have a PDI508Plus to play
            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.
          - ATA protocol support??
          - VINES TCP/IP encapsulation?? (info needed)
 
-
 	Sources:
 	 - Crynwr arcnet.com/arcether.com packet drivers.
 	 - arcnet.c v0.00 dated 1/1/94 and apparently by
@@ -128,6 +144,7 @@
 	 - RFC's 1201 and 1051 - re: TCP/IP over ARCnet
 	 - The official ARCnet COM9026 data sheets (!) thanks to Ken
 		Cornetet <kcornete@nyx10.cs.du.edu>
+	 - The official ARCnet COM20020 data sheets.
 	 - Information on some more obscure ARCnet controller chips, thanks
 	   to the nice people at SMC.
 	 - net/inet/eth.c (from kernel 1.1.50) for header-building info.
@@ -137,7 +154,7 @@
 */
 
 static const char *version =
- "arcnet.c: v2.60 96/11/23 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.91 97/08/19 Avery Pennarun <apenwarr@bond.net> et al.\n";
 
 
 
@@ -164,6 +181,9 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 
+#include <linux/if_arcnet.h>
+#include <linux/arcdevice.h>
+
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -171,95 +191,6 @@
 
 #include <net/arp.h>
 
-/**************************************************************************/
-
-/* Define this if you have a really ancient "RIM I" ARCnet card with no I/O
- * port at all and _only_ shared memory; this option MAY work for you.  It's
- * untested, though, so good luck and write to me with any results!
- */
-#undef RIM_I_MODE
-
-/* Normally, the ARCnet device needs to be assigned a name (default arc0).
- * Ethernet devices have a function to automatically try eth0, eth1, etc
- * until a free name is found.  To name the ARCnet device using an "eth?"
- * device name, define this option.
- */
-#undef CONFIG_ARCNET_ETHNAME
-
-/* 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 on if you have timing-sensitive DMA (ie. a tape drive) and
- * would like to sacrifice a little bit of network speed to reduce tape
- * write retries or some related problem.
- */
-#undef 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
- * the cable is broken.
- *
- * Define DETECT_RECONFIGS if you want to detect network reconfigurations.
- * Recons may be a real nuisance on a larger ARCnet network; if you are a
- * network administrator you probably would like to count them.
- * Reconfigurations will be recorded in stats.tx_carrier_errors (the last
- * field of the /proc/net/dev file).
- *
- * Define SHOW_RECONFIGS if you really want to see a log message whenever
- * a RECON occurs.
- */
-#define DETECT_RECONFIGS
-#undef SHOW_RECONFIGS
-
-/* RECON_THRESHOLD is the maximum number of RECON messages to receive within
- * one minute before printing a "cabling problem" warning.  You must have
- * DETECT_RECONFIGS enabled if you want to use this.  The default value
- * should be fine.
- *
- * After that, a "cabling restored" message will be printed on the next IRQ
- * if no RECON messages have been received for 10 seconds.
- *
- * Do not define RECON_THRESHOLD at all if you want to disable this feature.
- */
-#define RECON_THRESHOLD 30
-
-/* 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.  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, and the
- * extra check makes the autoprobe even more careful.  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
@@ -269,353 +200,83 @@
 
 /**************************************************************************/
 
-/* New debugging bitflags: each option can be enabled individually.
- *
- * These can be set while the driver is running by typing:
- *	ifconfig arc0 down metric 1xxx HOSTNAME
- *		where 1xxx is 1000 + the debug level you want
- *		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	/* 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_EXTRA|D_INIT|D_INIT_REASONS) 	 */
-/*#define ARCNET_DEBUG_MAX 0	*/	/* enable NO messages (bad idea) */
-#endif
-
-#ifndef ARCNET_DEBUG
-#define ARCNET_DEBUG (D_NORMAL|D_EXTRA)
-#endif
-int arcnet_debug = ARCNET_DEBUG;
-
-/* macros to simplify debug checking */
-#define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
-#define BUGMSG2(x,msg,args...) BUGLVL(x) printk(msg, ## args)
-#define BUGMSG(x,msg,args...) BUGMSG2(x,"%s%6s: " msg, \
-            x==D_NORMAL	? KERN_WARNING : \
-      x<=D_INIT_REASONS	? KERN_INFO    : KERN_DEBUG , \
-	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.
+/* These are now provided by the chipset driver. There's a performance 
+ * overhead in using them.
  */
-#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
+#define AINTMASK(x) ((*lp->asetmask)(dev, x))
+#define ARCSTATUS ((*lp->astatus)(dev))
+#define ACOMMAND(x) ((*lp->acommand)(dev, x))
 
 
-/* The number of low I/O ports used by the ethercard. */
-#define ARCNET_TOTAL_SIZE	16
+int arcnet_debug=ARCNET_DEBUG;
 
-/* Handy defines for ARCnet specific stuff */
-	/* COM 9026 controller chip --> ARCnet register addresses */
-#define _INTMASK (ioaddr+0)	/* writable */
-#define _STATUS  (ioaddr+0)	/* readable */
-#define _COMMAND (ioaddr+1)	/* writable, returns random vals on read (?) */
-#define _RESET  (ioaddr+8)	/* software reset (on read) */
+/* Exported function prototypes */
 
-/* RIM I (command/status is memory mapped) versus RIM III (standard I/O
- * mapped) macros.  These make things a bit cleaner.
- */
-#ifdef RIM_I_MODE
-  #define IOADDR	(dev->mem_start+0x800)
-  #define ARCSTATUS	readb(_STATUS)
-  #define ACOMMAND(cmd) writeb((cmd),_COMMAND)
-  #define ARCRESET	writeb(TESTvalue,ioaddr-0x800)	/* fake reset */
-  #define AINTMASK(msk)	writeb((msk),_INTMASK)
-  #define RELEASE_REGION(x,y)	/* nothing */
+#ifdef MODULE
+int  init_module(void);
+void cleanup_module(void);
 #else
-  #define IOADDR	(dev->base_addr)
-  #define ARCSTATUS	inb(_STATUS)
-  #define ACOMMAND(cmd) outb((cmd),_COMMAND)
-  #define AINTMASK(msk)	outb((msk),_INTMASK)
-  #define ARCRESET	inb(_RESET)
-  #define RELEASE_REGION(x,y)	release_region((x),(y))
-#endif
-
-#define SETMASK AINTMASK(lp->intmask)
-
-	/* 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)
-	 * note: packet sizes 250, 251, 252 are impossible (God knows why)
-	 *  so exception packets become necessary.
-	 *
-	 * These numbers are compared with the length of the full packet,
-	 * including ClientData header.
-	 */
-#define MTU	253	/* normal packet max size */
-#define MinTU	257	/* extended packet min size */
-#define XMTU	508	/* extended packet max size */
-
-	/* status/interrupt mask bit fields */
-#define TXFREEflag	0x01            /* transmitter available */
-#define TXACKflag       0x02            /* transmitted msg. ackd */
-#define RECONflag       0x04            /* system reconfigured */
-#define TESTflag        0x08            /* test flag */
-#define RESETflag       0x10            /* power-on-reset */
-#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:
-        *                0-2     command
-        *                3-4     page number (for enable rcv/xmt command)
-        *                 7      receive broadcasts
-        */
-#define NOTXcmd         0x01            /* disable transmitter */
-#define NORXcmd         0x02            /* disable receiver */
-#define TXcmd           0x03            /* enable transmitter */
-#define RXcmd           0x04            /* enable receiver */
-#define CONFIGcmd       0x05            /* define configuration */
-#define CFLAGScmd       0x06            /* clear flags */
-#define TESTcmd         0x07            /* load test flags */
-
-       /* flags for "clear flags" command */
-#define RESETclear      0x08            /* power-on-reset */
-#define CONFIGclear     0x10            /* system reconfigured */
-
-	/* flags for "load test flags" command */
-#define TESTload        0x08            /* test flag (diagnostic) */
-
-	/* byte deposited into first address of buffers on reset */
-#define TESTvalue       0321		 /* that's octal for 0xD1 :) */
-
-	/* for "enable receiver" command */
-#define RXbcasts        0x80            /* receive broadcasts */
-
-	/* flags for "define configuration" command */
-#define NORMALconf      0x00            /* 1-249 byte packets */
-#define EXTconf         0x08            /* 250-504 byte packets */
-
-	/* Starts receiving packets into recbuf.
-	 */
-#define EnableReceiver()	ACOMMAND(RXcmd|(recbuf<<3)|RXbcasts)
-
-	/* RFC1201 Protocol ID's */
-#define ARC_P_IP	212		/* 0xD4 */
-#define ARC_P_ARP	213		/* 0xD5 */
-#define ARC_P_RARP	214		/* 0xD6 */
-#define ARC_P_IPX	250		/* 0xFA */
-#define ARC_P_NOVELL_EC	236		/* 0xEC */
-
-	/* Old RFC1051 Protocol ID's */
-#define ARC_P_IP_RFC1051 240		/* 0xF0 */
-#define ARC_P_ARP_RFC1051 241		/* 0xF1 */
-
-	/* MS LanMan/WfWg protocol */
-#define ARC_P_ETHER	0xE8
-
-	/* Unsupported/indirectly supported protocols */
-#define ARC_P_DATAPOINT_BOOT	0	/* very old Datapoint equipment */
-#define ARC_P_DATAPOINT_MOUNT	1
-#define ARC_P_POWERLAN_BEACON	8	/* Probably ATA-Netbios related */
-#define ARC_P_POWERLAN_BEACON2	243
-#define ARC_P_LANSOFT	251		/* 0xFB - what is this? */
-#define ARC_P_ATALK	0xDD
-
-	/* the header required by the card itself */
-struct HardHeader
-{
-	u_char	source,		/* source ARCnet - filled in automagically */
-		destination,	/* destination ARCnet - 0 for broadcast */
-		offset1,	/* offset of ClientData (256-byte packets) */
-		offset2;	/* offset of ClientData (512-byte packets) */
-};
-
-	/* a complete ARCnet packet */
-union ArcPacket
-{
-	struct HardHeader hardheader;	/* the hardware header */
-	u_char raw[512];		/* raw packet info, incl ClientData */
-};
-
-	/* the "client data" header - RFC1201 information
-	 * notice that this screws up if it's not an even number of bytes
-	 * <sigh>
-	 */
-struct ClientData
-{
-	/* data that's NOT part of real packet - we MUST get rid of it before
-	 * actually sending!!
-	 */
-	u_char  saddr,		/* Source address - needed for IPX */
-		daddr;		/* Destination address */
-
-	/* data that IS part of real packet */
-	u_char	protocol_id,	/* ARC_P_IP, ARC_P_ARP, etc */
-		split_flag;	/* for use with split packets */
-	u_short	sequence;	/* sequence number */
-};
-#define EXTRA_CLIENTDATA (sizeof(struct ClientData)-4)
-
-
-	/* the "client data" header - RFC1051 information
-	 * this also screws up if it's not an even number of bytes
-	 * <sigh again>
-	 */
-struct S_ClientData
-{
-	/* data that's NOT part of real packet - we MUST get rid of it before
-	 * actually sending!!
-	 */
-	u_char  saddr,		/* Source address - needed for IPX */
-		daddr,		/* Destination address */
-		junk;		/* padding to make an even length */
-
-	/* data that IS part of real packet */
-	u_char	protocol_id;	/* ARC_P_IP, ARC_P_ARP, etc */
-};
-#define S_EXTRA_CLIENTDATA (sizeof(struct S_ClientData)-1)
-
-
-/* "Incoming" is information needed for each address that could be sending
- * to us.  Mostly for partially-received split packets.
- */
-struct Incoming
-{
-	struct sk_buff *skb;		/* packet data buffer             */
-	unsigned char lastpacket,	/* number of last packet (from 1) */
-		      numpackets;	/* number of packets in split     */
-	u_short sequence;		/* sequence number of assembly	  */
-};
-
-struct Outgoing
-{
-	struct sk_buff *skb;		/* buffer from upper levels */
-	struct ClientData *hdr;		/* clientdata of last packet */
-	u_char *data;			/* pointer to data in packet */
-	short length,			/* bytes total */
-	      dataleft,			/* bytes left */
-	      segnum,			/* segment being sent */
-	      numsegs,			/* number of segments */
-	      seglen;			/* length of segment */
-};
-
-
-/* Information that needs to be kept for each board. */
-struct arcnet_local {
-	struct net_device_stats stats;
-	u_short sequence;	/* sequence number (incs with each packet) */
-	u_char stationid,	/* our 8-bit station address */
-		recbuf,		/* receive buffer # (0 or 1) */
-		txbuf,		/* transmit buffer # (2 or 3) */
-		txready,	/* buffer where a packet is ready to send */
-		intmask;	/* current value of INTMASK register */
-	short intx,		/* in TX routine? */
-	      in_txhandler,	/* in TX_IRQ handler? */
-	      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 */
-		last_recon;	/* time of most recent RECON */
-	int num_recons,		/* number of RECONs between first and last. */
-	    network_down;	/* do we think the network is down? */
-#endif
-
-	struct timer_list timer; /* the timer interrupt struct */
-	struct Incoming incoming[256];	/* one from each address */
-	struct Outgoing outgoing; /* packet currently being sent */
-
-	struct device *adev;	/* RFC1201 protocol device */
-
-#ifdef CONFIG_ARCNET_ETH
-	struct device *edev;	/* Ethernet-Encap device */
+void arcnet_init(void);
+static int init_module(void);
+#ifdef CONFIG_ARCNET_COM90xx
+extern char com90xx_explicit;
+extern int arc90xx_probe(struct device *dev);
 #endif
-
-#ifdef CONFIG_ARCNET_1051
-	struct device *sdev;	/* RFC1051 protocol device */
 #endif
-};
 
-
-/* Index to functions, as function prototypes. */
+void arcnet_tx_done(struct device *dev, struct arcnet_local *lp);
+void arcnet_use_count (int open);
+void arcnet_setup(struct device *dev);
+void arcnet_makename(char *device);
+void arcnetA_continue_tx(struct device *dev);
+int arcnet_go_tx(struct device *dev,int enable_irq);
+void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr);
+
+
+EXPORT_SYMBOL(arcnet_debug);
+EXPORT_SYMBOL(arcnet_tx_done);
+EXPORT_SYMBOL(arcnet_use_count);
+EXPORT_SYMBOL(arcnet_setup);
+EXPORT_SYMBOL(arcnet_makename);
+EXPORT_SYMBOL(arcnetA_continue_tx);
+EXPORT_SYMBOL(arcnet_go_tx);
+EXPORT_SYMBOL(arcnet_interrupt);
+EXPORT_SYMBOL(arcnet_rx);
 
 #if ARCNET_DEBUG_MAX & D_SKB
-static void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,
+void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,
 	char *desc);
+EXPORT_SYMBOL(arcnet_dump_skb);
 #else
 #	define arcnet_dump_skb(dev,skb,desc) ;
 #endif
 
 #if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
-static void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,
+void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,
 	char *desc);
+EXPORT_SYMBOL(arcnet_dump_packet);
 #else
 #	define arcnet_dump_packet(dev,buffer,ext,desc) ;
 #endif
 
-extern int arcnet_probe(struct device *dev);
-static int arcnet_found(struct device *dev,int port,int airq,u_long shmem);
+/* Internal function prototypes */
 
-static void arcnet_setup(struct device *dev);
 static int arcnet_open(struct device *dev);
 static int arcnet_close(struct device *dev);
-static int arcnet_reset(struct device *dev,int reset_delay);
-
+static int arcnetA_header(struct sk_buff *skb,struct device *dev,
+		unsigned short type,void *daddr,void *saddr,unsigned len);
+static int arcnetA_rebuild_header(struct sk_buff *skb);
 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 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);
-static int arcnet_go_tx(struct device *dev,int enable_irq);
-
-static void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs);
-static void arcnet_inthandler(struct device *dev);
-
-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 struct net_device_stats *arcnet_get_stats(struct device *dev);
+static unsigned short arcnetA_type_trans(struct sk_buff *skb,
+					 struct device *dev);
 
-int arcnetA_header(struct sk_buff *skb,struct device *dev,
-		unsigned short type,void *daddr,void *saddr,unsigned len);
-int arcnetA_rebuild_header(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 */
@@ -626,6 +287,7 @@
 	int length,u_char saddr, u_char daddr);
 #endif
 
+
 #ifdef CONFIG_ARCNET_1051
 	/* functions specific to RFC1051 */
 static int arcnetS_init(struct device *dev);
@@ -633,20 +295,15 @@
 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,
+static int arcnetS_header(struct sk_buff *skb,struct device *dev,
 		unsigned short type,void *daddr,void *saddr,unsigned len);
-int arcnetS_rebuild_header(struct sk_buff *skb);
-unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev);
+static int arcnetS_rebuild_header(struct sk_buff *skb);
+static unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev);
 #endif
 
-#ifdef MODULE
-int  init_module(void);
-void cleanup_module(void);
-#endif
 
-#define tx_done(dev) 1
 
-#define JIFFER(time) for (delayval=jiffies+time; jiffies<delayval;) ;
+
 
 
 /****************************************************************************
@@ -699,1209 +356,568 @@
 }
 #endif
 
-/****************************************************************************
- *                                                                          *
- * Probe and initialization                                                 *
- *                                                                          *
- ****************************************************************************/
 
-#ifdef RIM_I_MODE
 
-/* We cannot probe for a RIM I card; one reason is I don't know how to reset
- * them.  In fact, we can't even get their node ID automatically.  So, we
- * need to be passed a specific shmem address, IRQ, and node ID (stored in
- * dev->base_addr)
+
+/* 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.
+ * "new-style flags") setup per-net-device is kind of weird anyway.
+ *
+ * Intelligent defaults?!  Nah.
  */
-__initfunc(int arcnet_probe(struct device *dev))
+
+void arcnet_setup(struct device *dev)
 {
-	BUGLVL(D_NORMAL) printk(version);
-	BUGMSG(D_NORMAL,"Compiled for ARCnet RIM I (autoprobe disabled)\n");
-	BUGMSG(D_NORMAL,"Given: node %02lXh, shmem %lXh, irq %d\n",
-		dev->base_addr,dev->mem_start,dev->irq);
+	dev_init_buffers(dev);
 
-	if (dev->mem_start<=0 || dev->irq<=0)
-	{
-		BUGMSG(D_NORMAL,"No autoprobe for RIM I; you "
-			"must specify the shmem and irq!\n");
-		return -ENODEV;
-	}
+	dev->broadcast[0]	= 0x00;	/* for us, broadcasts are address 0 */
+	dev->addr_len		= 1;
+	dev->type		= ARPHRD_ARCNET;
+	dev->tx_queue_len	= 30;
 
-	if (dev->base_addr<=0 || dev->base_addr>255)
-	{
-		BUGMSG(D_NORMAL,"You need to specify your card's station "
-			"ID!\n");
-		return -ENODEV;
-	}
+	/* New-style flags. */
+	dev->flags		= IFF_BROADCAST;
+	dev->family		= AF_INET;
+	dev->pa_addr		= 0;
+	dev->pa_brdaddr 	= 0;
+	dev->pa_mask		= 0;
+	dev->pa_alen		= 4;
+
+
+	/* Put in this stuff here, so we don't have to export the symbols 
+	 * to the chipset drivers.
+	 */
 
-	return arcnet_found(dev,dev->base_addr,dev->irq,dev->mem_start);
+  	dev->open=arcnet_open;
+	dev->stop=arcnet_close;
+	dev->hard_start_xmit=arcnetA_send_packet;
+	dev->get_stats=arcnet_get_stats;
+	dev->hard_header=arcnetA_header;
+	dev->rebuild_header=arcnetA_rebuild_header;
 }
 
-#else /* not RIM_I_MODE, so use a real autoprobe */
 
-/* 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).
- *
- * 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.
+/****************************************************************************
+ *                                                                          *
+ * Open and close the driver                                                *
+ *                                                                          *
+ ****************************************************************************/
+
+
+/* Open/initialize the board.  This is called sometime after booting when
+ * the 'ifconfig' program is run.
  *
- * FIXME: grab all devices in one shot and eliminate the big static array.
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
  */
+static int
+arcnet_open(struct device *dev)
+{
+  struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+ 
+  if (dev->metric>=1000)
+    {
+      arcnet_debug=dev->metric-1000;
+      printk(KERN_INFO "%6s: debug level set to %d\n",dev->name,arcnet_debug);
+      dev->metric=1;
+    }
+  
+  BUGMSG(D_INIT,"arcnet_open: resetting card.\n");
+  
+  /* try to put the card in a defined state - if it fails the first
+   * time, actually reset it.
+   */
+  if ((*lp->arcnet_reset)(dev,0) && (*lp->arcnet_reset)(dev,1))
+    return -ENODEV;
+#if 0
+  /* reset the card twice in case something goes wrong the first time.
+   */
+  if ((*(lp->arcnet_reset))(dev,1) && (*(lp->arcnet_reset))(dev,1))
+    return -ENODEV;
+#endif
+  
+  dev->tbusy=0;
+  dev->interrupt=0;
+  lp->intx=0;
+  lp->in_txhandler=0;
+  
+  /* The RFC1201 driver is the default - just store */
+  lp->adev=dev;
+
+  /* we're started */
+  dev->start=1;
+  
+#ifdef CONFIG_ARCNET_ETH
+  /* Initialize the ethernet-encap protocol driver */
+  lp->edev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
+  if (lp->edev == NULL)
+    return -ENOMEM;
+  memcpy(lp->edev,dev,sizeof(struct device));
+  lp->edev->type=ARPHRD_ETHER;
+  lp->edev->name=(char *)kmalloc(10,GFP_KERNEL);
+  if (lp->edev->name == NULL) {
+    kfree(lp->edev);
+    lp->edev = NULL;
+    return -ENOMEM;
+  }
+  sprintf(lp->edev->name,"%se",dev->name);
+  lp->edev->init=arcnetE_init;
+  register_netdev(lp->edev);
+#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));
+  lp->sdev->name=(char *)kmalloc(10,GFP_KERNEL);
+  sprintf(lp->sdev->name,"%ss",dev->name);
+  lp->sdev->init=arcnetS_init;
+  register_netdev(lp->sdev);
+#endif
+    
+  /* Enable TX if we need to */
+  if (lp->en_dis_able_TX)
+    (*lp->en_dis_able_TX)(dev, 1);
+  
+  /* make sure we're ready to receive IRQ's.
+   * arcnet_reset sets this for us, but if we receive one before
+   * START is set to 1, it could be ignored.  So, we turn IRQ's
+   * off, then on again to clean out the IRQ controller.
+   */
+  
+  AINTMASK(0);
+  udelay(1);	/* give it time to set the mask before
+		 * we reset it again. (may not even be
+		 * necessary)
+		 */
+  SETMASK;
+  
+  /* Let it increase its use count */
+  (*lp->openclose_device)(1);
+  
+  return 0;
+}
 
-static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata = { 0 };
-static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata = { 0 };
 
-__initfunc(int arcnet_probe(struct device *dev))
+/* The inverse routine to arcnet_open - shuts down the card.
+ */
+static int
+arcnet_close(struct device *dev)
 {
-	static int init_once = 0;
-	static int numports=sizeof(ports)/sizeof(ports[0]),
-	    	   numshmems=sizeof(shmems)/sizeof(shmems[0]);
-
-	int count,status,delayval,ioaddr,numprint,airq,retval=-ENODEV,
-		openparen=0;
-	unsigned long airqmask;
-	int *port;
-	u_long *shmem;
+  struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+  
+  if (test_and_set_bit(0, (int *)&dev->tbusy))
+    BUGMSG(D_NORMAL, "arcnet_close: tbusy already set!\n");
 
-	if (!init_once)
-	{
-		for (count=0x200; count<=0x3f0; count+=16)
-			ports[(count-0x200)/16] = count;
-		for (count=0xA0000; count<=0xFF800; count+=2048)
-			shmems[(count-0xA0000)/2048] = count;
-		init_once=1;
-	}
+  dev->start=0;
+#ifdef CONFIG_ARCNET_1051
+  lp->sdev->tbusy=1;
+  lp->sdev->start=0;
+#endif
+#ifdef CONFIG_ARCNET_ETH
+  lp->edev->tbusy=1;
+  lp->edev->start=0;
+#endif
 
-	BUGLVL(D_NORMAL) printk(version);
+  
+  /* Shut down the card */
+  
+  /* Disable TX if we need to */
+  if (lp->en_dis_able_TX)
+    (*lp->en_dis_able_TX)(dev, 0);
+  
+  (*lp->arcnet_reset)(dev, 3);	/* reset IRQ won't run if START=0 */
+#if 0
+  lp->intmask=0;
+  SETMASK;	/* no IRQ's (except RESET, of course) */
+  ACOMMAND(NOTXcmd);	/* stop transmit */
+  ACOMMAND(NORXcmd);	/* disable receive */
+#endif
+  
+  /* reset more flags */
+	dev->interrupt=0;
+#ifdef CONFIG_ARCNET_ETH
+	lp->edev->interrupt=0;
+#endif
+#ifdef CONFIG_ARCNET_1051
+	lp->sdev->interrupt=0;
+#endif
 
-	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 arcnet.txt for important release notes!\n");
-		printk("arcnet: *\n");
-		printk("arcnet: * This is an ALPHA version!  (Last stable release: v2.56)  E-mail me if\n");
-		printk("arcnet: * you have any questions, comments, or bug reports.\n");
-		printk("arcnet: ***\n");
-	}
+  
+  /* 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);
+  unregister_netdev(lp->edev);
+  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);
+  unregister_netdev(lp->sdev);
+  kfree(lp->sdev->name);
+  kfree(lp->sdev);
+  lp->sdev=NULL;
+#endif
+  
+  /* Update the statistics here. (not necessary in ARCnet) */
+  
+  /* Decrease the use count */
+  (*lp->openclose_device)(0);
+  
+  return 0;
+}
 
-	BUGMSG(D_INIT,"given: base %lXh, IRQ %d, shmem %lXh\n",
-			dev->base_addr,dev->irq,dev->mem_start);
 
-	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;
 
-	if (dev->mem_start)
+/****************************************************************************
+ *                                                                          *
+ * Transmitter routines                                                     *
+ *                                                                          *
+ ****************************************************************************/
+
+/* Generic error checking routine for arcnet??_send_packet
+ */
+static int
+arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
+{
+  struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+  
+  BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
+	 ARCSTATUS,lp->intx);
+  
+  if (lp->in_txhandler)
+    {
+      BUGMSG(D_NORMAL,"send_packet called while in txhandler!\n");
+      lp->stats.tx_dropped++;
+      return 1;
+    }
+  
+  if (lp->intx>1)
+    {
+      BUGMSG(D_NORMAL,"send_packet called while intx!\n");
+      lp->stats.tx_dropped++;
+      return 1;
+    }
+  
+  if (test_bit(0, (int *)&dev->tbusy))
+    {
+      /* If we get here, some higher level has decided we are broken.
+	 There should really be a "kick me" function call instead. */
+      int tickssofar = jiffies - dev->trans_start;
+
+      int status=ARCSTATUS;
+      
+      if (tickssofar < TX_TIMEOUT)
+	{
+	  BUGMSG(D_DURING,"premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n",
+		 status,tickssofar,lp->outgoing.skb,
+		 lp->outgoing.numsegs,
+		 lp->outgoing.segnum);
+	  return 1;
+	}
+      
+      lp->intmask &= ~TXFREEflag;
+      SETMASK;
+      
+      if (status&TXFREEflag)	/* transmit _DID_ finish */
+	{
+	  BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n",
+		 status,tickssofar,lp->intmask,lp->lasttrans_dest);
+	  lp->stats.tx_errors++;
+	}
+      else
+	{
+	  BUGMSG(D_EXTRA,"tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n",
+		 status,tickssofar,lp->intmask,lp->lasttrans_dest);
+	  lp->stats.tx_errors++;
+	  lp->stats.tx_aborted_errors++;
+	  
+	  ACOMMAND(NOTXcmd);
+	}
+      
+      if (lp->outgoing.skb)
 	{
-		shmems[0]=dev->mem_start;
-		numshmems=1;
+	  dev_kfree_skb(lp->outgoing.skb,FREE_WRITE);
+	  lp->stats.tx_dropped++;
 	}
+      lp->outgoing.skb=NULL;
+      
+#ifdef CONFIG_ARCNET_ETH
+      lp->edev->tbusy=0;
+#endif
+#ifdef CONFIG_ARCNET_1051
+      lp->sdev->tbusy=0;
+#endif
+      if (!test_and_clear_bit(0,(int *)&dev->tbusy))
+	BUGMSG(D_EXTRA, "after timing out, tbusy was clear!\n");
 
+      lp->txready=0;
+      lp->sending=0;
+      
+      return 1;
+    }
+  
+  if (lp->txready)	/* transmit already in progress! */
+    {
+      BUGMSG(D_NORMAL,"trying to start new packet while busy! (status=%Xh)\n",
+	     ARCSTATUS);
+      lp->intmask &= ~TXFREEflag;
+      SETMASK;
+      ACOMMAND(NOTXcmd); /* abort current send */
+      (*lp->inthandler)(dev); /* fake an interrupt */
+      lp->stats.tx_errors++;
+      lp->stats.tx_fifo_errors++;
+      lp->txready=0;	/* we definitely need this line! */
+      
+      return 1;
+    }
+  
+  /* Block a timer-based transmit from overlapping.  This could better be
+     done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+  if (test_and_set_bit(0, (int *)&lp->adev->tbusy))
+    {
+      BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
+	     ARCSTATUS,lp->intx,jiffies-dev->trans_start);
+      lp->stats.tx_errors++;
+      lp->stats.tx_fifo_errors++;
+      return -EBUSY;
+    }
+#ifdef CONFIG_ARCNET_1051
+  lp->sdev->tbusy=1;
+#endif
+#ifdef CONFIG_ARCNET_ETH
+  lp->edev->tbusy=1;
+#endif
+  
+  return 0;
+}
 
-	/* 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))
-		{
-			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;
-		}
+/* Called by the kernel in order to transmit a packet.
+ */
+static int
+arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
+{
+  struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+  int bad,oldmask=0;
+  struct Outgoing *out=&(lp->outgoing);
+  
+  lp->intx++;
+  
+  oldmask |= lp->intmask;
+  lp->intmask=0;
+  SETMASK;
+  
+  bad=arcnet_send_packet_bad(skb,dev);
+  if (bad)
+    {
+      lp->intx--;
+      lp->intmask=oldmask;
+      SETMASK;
+      return bad;
+    }
+  
+  /* arcnet_send_packet_pad has already set tbusy - don't bother here. */
+  
+  lp->intmask = oldmask & ~TXFREEflag;
+  SETMASK;
+  
+  out->length = 1 < skb->len ? skb->len : 1;
+  out->hdr=(struct ClientData*)skb->data;
+  out->skb=skb;
+  
+  BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx");
+  
+  out->hdr->sequence=(lp->sequence++);
+  
+  /* fits in one packet? */
+  if (out->length-EXTRA_CLIENTDATA<=XMTU)
+    {
+      BUGMSG(D_DURING,"not splitting %d-byte packet. (split_flag=%d)\n",
+	     out->length,out->hdr->split_flag);
+      if (out->hdr->split_flag)
+	BUGMSG(D_NORMAL,"short packet has split_flag set?! (split_flag=%d)\n",
+	       out->hdr->split_flag);
+      out->numsegs=1;
+      out->segnum=1;
+      (*lp->prepare_tx)(dev,
+			((char *)out->hdr)+EXTRA_CLIENTDATA,
+			sizeof(struct ClientData)-EXTRA_CLIENTDATA,
+			((char *)skb->data)+sizeof(struct ClientData),
+			out->length-sizeof(struct ClientData),
+			out->hdr->daddr,1,0);
+      
+      /* done right away */
+      lp->stats.tx_bytes += out->skb->len;
+      dev_kfree_skb(out->skb,FREE_WRITE);
+      out->skb=NULL;
+      
+      if (arcnet_go_tx(dev,1))
+	{
+	  /* inform upper layers */
+	  arcnet_tx_done(dev, lp);
+	}
+    }
+  else			/* too big for one - split it */
+    {
+      int maxsegsize=XMTU-4;
+      
+      out->data=(u_char *)skb->data
+	+ sizeof(struct ClientData);
+      out->dataleft=out->length-sizeof(struct ClientData);
+      out->numsegs=(out->dataleft+maxsegsize-1)/maxsegsize;
+      out->segnum=0;
+      
+      BUGMSG(D_TX,"packet (%d bytes) split into %d fragments:\n",
+	     out->length,out->numsegs);
+      
+      /* if a packet waiting, launch it */
+      arcnet_go_tx(dev,1);
+      
+      if (!lp->txready)
+	{
+	  /* prepare a packet, launch it and prepare
+	   * another.
+	   */
+	  arcnetA_continue_tx(dev);
+	  if (arcnet_go_tx(dev,1))
+	    {
+	      arcnetA_continue_tx(dev);
+	      arcnet_go_tx(dev,1);
+	    }
+	}
+      
+      /* if segnum==numsegs, the transmission is finished;
+       * free the skb right away.
+       */
+
+      if (out->segnum==out->numsegs)
+	{
+	  /* transmit completed */
+	  out->segnum++;
+	  if (out->skb)
+	    {
+	      lp->stats.tx_bytes += skb->len;
+	      dev_kfree_skb(out->skb,FREE_WRITE);
+	    }
+	  out->skb=NULL;
+	}
+    }
+  
+  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;
+}
 
-		if (ARCSTATUS == 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;
-		}
 
-		ARCRESET;	/* begin resetting card */
+/* 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.
+ */
+void arcnetA_continue_tx(struct device *dev)
+{
+  struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+  int maxsegsize=XMTU-4;
+  struct Outgoing *out=&(lp->outgoing);
+  
+  BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n",
+	 ARCSTATUS,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);
+  
+  (*lp->prepare_tx)(dev,((char *)out->hdr)+EXTRA_CLIENTDATA,
+		    sizeof(struct ClientData)-EXTRA_CLIENTDATA,
+		    out->data,out->seglen,out->hdr->daddr,1,0);
+  
+  out->dataleft-=out->seglen;
+  out->data+=out->seglen;
+  out->segnum++;
+}
 
-		BUGMSG2(D_INIT_REASONS,"\n");
-		BUGMSG(D_INIT_REASONS,"Stage 1: ");
-		BUGLVL(D_INIT_REASONS) numprint=0;
-	}
-	BUGMSG2(D_INIT,"\n");
 
-	if (!numports)
-	{
-		BUGMSG(D_NORMAL,"Stage 1: No ARCnet cards found.\n");
-		return -ENODEV;
-	}
+/* Actually start transmitting a packet that was placed in the card's
+ * buffer by arcnetAS_prepare_tx.  Returns 1 if a Tx is really started.
+ *
+ * This should probably always be called with the INTMASK register set to 0,
+ * so go_tx is not called recursively.
+ *
+ * The enable_irq flag determines whether to actually write INTMASK value
+ * to the card; TXFREEflag is always OR'ed into the memory variable either
+ * way.
+ */
+int arcnet_go_tx(struct device *dev,int enable_irq)
+{
+	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
 
+	BUGMSG(D_DURING,"go_tx: status=%Xh, intmask=%Xh, txready=%d, sending=%d\n",
+		ARCSTATUS,lp->intmask,lp->txready,lp->sending);
 
-	/* 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,"Stage 2: ");
-	numprint=0;
-	for (port = &ports[0]; port-ports<numports; port++)
+	if (lp->sending || !lp->txready)
 	{
-		numprint++;
-		if (numprint>8)
+		if (enable_irq && lp->sending)
 		{
-			BUGMSG2(D_INIT,"\n");
-			BUGMSG(D_INIT,"Stage 2: ");
-			numprint=1;
+			lp->intmask |= TXFREEflag;
+			SETMASK;
 		}
-		BUGMSG2(D_INIT,"%Xh ",*port);
+		return 0;
 	}
-	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_long ptr;
+	/* start sending */
+	ACOMMAND(TXcmd|(lp->txready<<3));
 
-		numprint++;
-		if (numprint>8)
-		{
-			BUGMSG2(D_INIT,"\n");
-			BUGMSG(D_INIT,"Stage 3: ");
-			numprint=1;
-		}
-		BUGMSG2(D_INIT,"%lXh ",*shmem);
+	lp->stats.tx_packets++;
+	lp->txready=0;
+	lp->sending++;
 
-		ptr=(u_long)(*shmem);
+	lp->lasttrans_dest=lp->lastload_dest;
+	lp->lastload_dest=0;
 
-		if (readb(ptr) != TESTvalue)
-		{
-			BUGMSG2(D_INIT_REASONS,"(mem=%02Xh, not %02Xh)\n",
-				readb(ptr),TESTvalue);
-			BUGMSG(D_INIT_REASONS,"Stage 3: ");
-			BUGLVL(D_INIT_REASONS) numprint=0;
-			*shmem=shmems[numshmems-1];
-			numshmems--;
-			shmem--;
-			continue;
-		}
+	lp->intmask |= TXFREEflag;
 
-		/* 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.
-		 */
-		writeb(0x42,ptr);
-		if (readb(ptr) != 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");
-
-	if (!numshmems)
-	{
-		BUGMSG(D_NORMAL,"Stage 3: No ARCnet cards found.\n");
-		return -ENODEV;
-	}
-
-	/* 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++)
-	{
-		numprint++;
-		if (numprint>8)
-		{
-			BUGMSG2(D_INIT,"\n");
-			BUGMSG(D_INIT,"Stage 4: ");
-			numprint=1;
-		}
-		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=ARCSTATUS;
-
-		if ((status & 0x9D)
-			!= (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;
-		}
-
-		ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear);
-		status=ARCSTATUS;
-		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;
-		}
-
-		/* skip this completely 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();
-			AINTMASK(NORXflag);
-			udelay(1);
-			AINTMASK(0);
-			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
-		{
-			airq=dev->irq;
-		}
-
-		BUGMSG2(D_INIT,"(%d,", airq);
-		openparen=1;
-
-		/* 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)
-		{
-			ARCRESET;
-			JIFFER(RESETtime);
-		}
-		else
-		{
-			/* just one shmem and port, assume they match */
-			writeb(TESTvalue,shmems[0]);
-		}
-#else
-		ARCRESET;
-		JIFFER(RESETtime);
-#endif
-
-
-		for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
-		{
-			u_long ptr;
-			ptr=(u_long)(*shmem);
-
-			if (readb(ptr) == TESTvalue)	/* found one */
-			{
-				BUGMSG2(D_INIT,"%lXh)\n", *shmem);
-				openparen=0;
-
-				/* register the card */
-				retval=arcnet_found(dev,*port,airq,*shmem);
-				if (retval) openparen=0;
-
-				/* remove shmem from the list */
-				*shmem=shmems[numshmems-1];
-				numshmems--;
-
-				break;
-			}
-			else
-			{
-				BUGMSG2(D_INIT_REASONS,"%Xh-", readb(ptr));
-			}
-		}
-
-		if (openparen)
-		{
-			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--;
-
-		if (!retval) break;
-	}
-	BUGMSG(D_INIT_REASONS,"\n");
-
-	/* Now put back TESTvalue on all leftover shmems.
-	 */
-	for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
-		writeb(TESTvalue,*shmem);
-
-	if (retval) BUGMSG(D_NORMAL,"Stage 5: No ARCnet cards found.\n");
-	return retval;
-}
-
-#endif /* !RIM_I_MODE */
-
-
-/* Set up the struct device associated with this card.  Called after
- * probing succeeds.
- */
-__initfunc(int arcnet_found(struct device *dev,int port,int airq, u_long shmem))
-{
-	u_long first_mirror,last_mirror;
-	struct arcnet_local *lp;
-	int mirror_size;
-
-	/* reserve the irq */
-	if (request_irq(airq,&arcnet_interrupt,0,"arcnet",NULL))
-	{
-		BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq);
-		return -ENODEV;
-	}
-	irq2dev_map[airq]=dev;
-	dev->irq=airq;
-
-#ifdef RIM_I_MODE
-	dev->base_addr=0;
-	writeb(TESTvalue,shmem);
-	writeb(port,shmem+1);	/* actually the node ID */
-#else
-	/* reserve the I/O region - guaranteed to work by check_region */
-	request_region(port,ARCNET_TOTAL_SIZE,"arcnet");
-	dev->base_addr=port;
-#endif
-
-	/* find the real shared memory start/end points, including mirrors */
-
-	#define BUFFER_SIZE (512)
-	#define MIRROR_SIZE (BUFFER_SIZE*4)
-
-	/* guess the actual size of one "memory mirror" - the number of
-	 * bytes between copies of the shared memory.  On most cards, it's
-	 * 2k (or there are no mirrors at all) but on some, it's 4k.
-	 */
-	mirror_size=MIRROR_SIZE;
-	if (readb(shmem)==TESTvalue
-	    && readb(shmem-mirror_size)!=TESTvalue
-	    && readb(shmem-2*mirror_size)==TESTvalue)
-		mirror_size*=2;
-
-	first_mirror=last_mirror=shmem;
-	while (readb(first_mirror)==TESTvalue) first_mirror-=mirror_size;
-	first_mirror+=mirror_size;
-
-	while (readb(last_mirror)==TESTvalue) last_mirror+=mirror_size;
-	last_mirror-=mirror_size;
-
-	dev->mem_start=first_mirror;
-	dev->mem_end=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)
-	{
-		irq2dev_map[airq] = NULL;
-		free_irq(airq,NULL);
-		RELEASE_REGION(port,ARCNET_TOTAL_SIZE);
-		return -ENOMEM;
-	}
-	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;
-	dev->get_stats=arcnet_get_stats;
-	/*dev->set_multicast_list = &set_multicast_list;*/
-
-	/* Fill in the fields of the device structure with generic
-	 * values.
-	 */
-	arcnet_setup(dev);
-
-	/* 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));
-
-	/* get and check the station ID from offset 1 in shmem */
-	lp->stationid = readb(first_mirror+1);
-	if (lp->stationid==0)
-		BUGMSG(D_NORMAL,"WARNING!  Station address 00 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;
-
-	BUGMSG(D_NORMAL,"ARCnet station %02Xh found at %03lXh, IRQ %d, "
-		"ShMem %lXh (%ld*%d bytes).\n",
-		lp->stationid,
-		dev->base_addr,dev->irq,dev->mem_start,
-		(dev->mem_end-dev->mem_start+1)/mirror_size,mirror_size);
-
-	return 0;
-}
-
-
-/* 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)
-{
-	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
-	short ioaddr=IOADDR;
-	int delayval,recbuf=lp->recbuf;
-
-	/* no IRQ's, please! */
-	lp->intmask=0;
-	SETMASK;
-
-	BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
-			dev->name,ARCSTATUS);
-
-	if (reset_delay)
-	{
-		/* reset the card */
-		ARCRESET;
-		JIFFER(RESETtime);
-	}
-
-	ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */
-	ACOMMAND(CFLAGScmd|CONFIGclear);
-
-	/* verify that the ARCnet signature byte is present */
-	if (readb(dev->mem_start) != TESTvalue)
-	{
-		BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n");
-		return 1;
-	}
-
-	/* clear out status variables */
-	recbuf=lp->recbuf=0;
-	lp->txbuf=2;
-
-	/* enable extended (512-byte) packets */
-	ACOMMAND(CONFIGcmd|EXTconf);
-
-#ifndef SLOW_XMIT_COPY
-	/* clean out all the memory to make debugging make more sense :) */
-	BUGLVL(D_DURING)
-		memset_io(dev->mem_start,0x42,2048);
-#endif
-
-	/* and enable receive of our first packet to the first buffer */
-	EnableReceiver();
-
-	/* re-enable interrupts */
-	lp->intmask|=NORXflag;
-#ifdef DETECT_RECONFIGS
-	lp->intmask|=RECONflag;
-#endif
-	SETMASK;
-
-	/* done!  return success. */
-	return 0;
-}
-
-
-/* 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.
- * "new-style flags") setup per-net-device is kind of weird anyway.
- *
- * Intelligent defaults?!  Nah.
- */
-
-void arcnet_setup(struct device *dev)
-{
-	dev_init_buffers(dev);
-
-	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.
-					 */
-
-	/* New-style flags. */
-	dev->flags		= IFF_BROADCAST;
-	dev->family		= AF_INET;
-	dev->pa_addr		= 0;
-	dev->pa_brdaddr 	= 0;
-	dev->pa_mask		= 0;
-	dev->pa_alen		= 4;
-}
-
-
-/****************************************************************************
- *                                                                          *
- * Open and close the driver                                                *
- *                                                                          *
- ****************************************************************************/
-
-
-/* Open/initialize the board.  This is called sometime after booting when
- * the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
- */
-static int
-arcnet_open(struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=IOADDR;
-
-	if (dev->metric>=1000)
-	{
-		arcnet_debug=dev->metric-1000;
-		printk(KERN_INFO "%6s: debug level set to %d\n",dev->name,arcnet_debug);
-		dev->metric=1;
-	}
-
-	BUGMSG(D_INIT,"arcnet_open: resetting card.\n");
-
-#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;
-	lp->intx=0;
-	lp->in_txhandler=0;
-
-	/* The RFC1201 driver is the default - just store */
-	lp->adev=dev;
-	BUGMSG(D_NORMAL,"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)
-		return -ENOMEM;
-	memcpy(lp->edev,dev,sizeof(struct device));
-	lp->edev->name=(char *)kmalloc(10,GFP_KERNEL);
-	if (lp->edev->name == NULL) {
-		kfree(lp->edev);
-		lp->edev = NULL;
-		return -ENOMEM;
-	}
-	sprintf(lp->edev->name,"%se",dev->name);
-	lp->edev->init=arcnetE_init;
-	register_netdev(lp->edev);
-#else
-	BUGMSG(D_NORMAL,"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));
-	lp->sdev->name=(char *)kmalloc(10,GFP_KERNEL);
-	sprintf(lp->sdev->name,"%ss",dev->name);
-	lp->sdev->init=arcnetS_init;
-	register_netdev(lp->sdev);
-#else
-	BUGMSG(D_NORMAL,"RFC1051 protocol not available (disabled).\n");
-#endif
-
-	/* we're started */
-	START=1;
-
-	/* make sure we're ready to receive IRQ's.
-	 * arcnet_reset sets this for us, but if we receive one before
-	 * START is set to 1, it could be ignored.  So, we turn IRQ's
-	 * off, then on again to clean out the IRQ controller.
-	 */
-	AINTMASK(0);
-	udelay(1);	/* give it time to set the mask before
-			 * we reset it again. (may not even be
-			 * necessary)
-			 */
-	SETMASK;
-
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-
-/* The inverse routine to arcnet_open - shuts down the card.
- */
-static int
-arcnet_close(struct device *dev)
-{
-	int ioaddr=IOADDR;
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
-	TBUSY=1;
-	START=0;
-
-	/* Shut down the card */
-#ifdef FAST_IFCONFIG
-	ARCRESET;	/* reset IRQ won't run if START=0 */
-#else
-	lp->intmask=0;
-	SETMASK;	/* no IRQ's (except RESET, of course) */
-	ACOMMAND(NOTXcmd);	/* stop transmit */
-	ACOMMAND(NORXcmd);	/* disable receive */
-#endif
-
-	/* reset more flags */
-	INTERRUPT=0;
-
-	/* 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);
-	unregister_netdev(lp->edev);
-	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);
-	unregister_netdev(lp->sdev);
-	kfree(lp->sdev->name);
-	kfree(lp->sdev);
-	lp->sdev=NULL;
-#endif
-
-	/* Update the statistics here. (not necessary in ARCnet) */
-
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
+	if (enable_irq)	SETMASK;
 
-
-
-/****************************************************************************
- *                                                                          *
- * Transmitter routines                                                     *
- *                                                                          *
- ****************************************************************************/
-
-/* Generic error checking routine for arcnet??_send_packet
- */
-static int
-arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=IOADDR;
-
-	BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
-			ARCSTATUS,lp->intx);
-
-	if (lp->in_txhandler)
-	{
-		BUGMSG(D_NORMAL,"send_packet called while in txhandler!\n");
-		lp->stats.tx_dropped++;
-		return 1;
-	}
-
-	if (lp->intx>1)
-	{
-		BUGMSG(D_NORMAL,"send_packet called while intx!\n");
-		lp->stats.tx_dropped++;
-		return 1;
-	}
-
-	if (IF_TBUSY)
-	{
-		/* If we get here, some higher level has decided we are broken.
-		   There should really be a "kick me" function call instead. */
-		int tickssofar = jiffies - dev->trans_start;
-		/*int recbuf=lp->recbuf;*/
-		int status=ARCSTATUS;
-
-		if (tickssofar < TX_TIMEOUT)
-		{
-			BUGMSG(D_DURING,"premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n",
-					status,tickssofar,lp->outgoing.skb,
-					lp->outgoing.numsegs,
-					lp->outgoing.segnum);
-			return 1;
-		}
-
-		lp->intmask &= ~TXFREEflag;
-		SETMASK;
-
-		if (status&TXFREEflag)	/* transmit _DID_ finish */
-		{
-			BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n",
-					status,tickssofar,lp->intmask,lp->lasttrans_dest);
-			lp->stats.tx_errors++;
-		}
-		else
-		{
-			BUGMSG(D_EXTRA,"tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n",
-					status,tickssofar,lp->intmask,lp->lasttrans_dest);
-			lp->stats.tx_errors++;
-			lp->stats.tx_aborted_errors++;
-
-			ACOMMAND(NOTXcmd);
-		}
-
-		if (lp->outgoing.skb)
-		{
-			dev_kfree_skb(lp->outgoing.skb,FREE_WRITE);
-			lp->stats.tx_dropped++;
-		}
-		lp->outgoing.skb=NULL;
-
-		TBUSY=0;
-		lp->txready=0;
-		lp->sending=0;
-
-		return 1;
-	}
-
-	if (lp->txready)	/* transmit already in progress! */
-	{
-		BUGMSG(D_NORMAL,"trying to start new packet while busy! (status=%Xh)\n",
-			ARCSTATUS);
-		lp->intmask &= ~TXFREEflag;
-		SETMASK;
-		ACOMMAND(NOTXcmd); /* abort current send */
-		arcnet_inthandler(dev); /* fake an interrupt */
-		lp->stats.tx_errors++;
-		lp->stats.tx_fifo_errors++;
-		lp->txready=0;	/* we definitely need this line! */
-
-		return 1;
-	}
-
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-        if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
-        {
-            BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
-            		ARCSTATUS,lp->intx,jiffies-dev->trans_start);
-            lp->stats.tx_errors++;
-            lp->stats.tx_fifo_errors++;
-            return -EBUSY;
-        }
-
-	return 0;
-}
-
-
-/* Called by the kernel in order to transmit a packet.
- */
-static int
-arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=IOADDR,bad;
-	struct Outgoing *out=&(lp->outgoing);
-
-	lp->intx++;
-
-	bad=arcnet_send_packet_bad(skb,dev);
-	if (bad)
-	{
-		lp->intx--;
-		return bad;
-	}
-
-	TBUSY=1;
-
-	out->length = 1 < skb->len ? skb->len : 1;
-	out->hdr=(struct ClientData*)skb->data;
-	out->skb=skb;
-
-	BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx");
-
-	out->hdr->sequence=(lp->sequence++);
-
-	/* fits in one packet? */
-	if (out->length-EXTRA_CLIENTDATA<=XMTU)
-	{
-		BUGMSG(D_DURING,"not splitting %d-byte packet. (split_flag=%d)\n",
-				out->length,out->hdr->split_flag);
-		if (out->hdr->split_flag)
-			BUGMSG(D_NORMAL,"short packet has split_flag set?! (split_flag=%d)\n",
-				out->hdr->split_flag);
-		out->numsegs=1;
-		out->segnum=1;
-		arcnetAS_prepare_tx(dev,
-			((char *)out->hdr)+EXTRA_CLIENTDATA,
-			sizeof(struct ClientData)-EXTRA_CLIENTDATA,
-			((char *)skb->data)+sizeof(struct ClientData),
-			out->length-sizeof(struct ClientData),
-			out->hdr->daddr,1);
-
-		/* done right away */
-		dev_kfree_skb(out->skb,FREE_WRITE);
-		out->skb=NULL;
-
-		if (arcnet_go_tx(dev,1))
-		{
-			/* inform upper layers */
-			TBUSY=0;
-			mark_bh(NET_BH);
-		}
-	}
-	else			/* too big for one - split it */
-	{
-		int maxsegsize=XMTU-4;
-
-		out->data=(u_char *)skb->data
-				+ sizeof(struct ClientData);
-		out->dataleft=out->length-sizeof(struct ClientData);
-		out->numsegs=(out->dataleft+maxsegsize-1)/maxsegsize;
-		out->segnum=0;
-
-		BUGMSG(D_TX,"packet (%d bytes) split into %d fragments:\n",
-			out->length,out->numsegs);
-
-		/* if a packet waiting, launch it */
-		arcnet_go_tx(dev,1);
-
-		if (!lp->txready)
-		{
-			/* prepare a packet, launch it and prepare
-			 * another.
-			 */
-			arcnetA_continue_tx(dev);
-			if (arcnet_go_tx(dev,1))
-			{
-				arcnetA_continue_tx(dev);
-				arcnet_go_tx(dev,1);
-			}
-		}
-
-		/* if segnum==numsegs, the transmission is finished;
-		 * free the skb right away.
-		 */
-		if (out->segnum==out->numsegs)
-		{
-			/* transmit completed */
-			out->segnum++;
-			if (out->skb)
-				dev_kfree_skb(out->skb,FREE_WRITE);
-			out->skb=NULL;
-		}
-	}
-
-	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=IOADDR,maxsegsize=XMTU-4;
-	struct Outgoing *out=&(lp->outgoing);
-
-	BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n",
-		ARCSTATUS,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 *)phys_to_virt(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_io(dev->mem_start+lp->txbuf*512,0x42,512);
-#endif
-
-	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]);
-	}
-	else if (exceptA)		/* RFC1201 Exception Packet */
-	{
-		arcpacket->hardheader.offset1=0;
-		arcpacket->hardheader.offset2=offset=512-length-4;
-		arcsoft=(struct ClientData *)
-			(&arcpacket->raw[offset+4]);
-
-		/* exception-specific stuff - these four bytes
-		 * make the packet long enough to fit in a 512-byte
-		 * frame.
-		 */
-		arcpacket->raw[offset+0]=hdr[0];
-		arcpacket->raw[offset+1]=0xFF; /* FF flag */
-			arcpacket->raw[offset+2]=0xFF; /* FF padding */
-			arcpacket->raw[offset+3]=0xFF; /* FF padding */
-	}
-	else				/* "other" Exception packet */
-	{
-		/* RFC1051 - set 4 trailing bytes to 0 */
-		memset(&arcpacket->raw[508],0,4);
-
-		/* now round up to MinTU */
-		arcpacket->hardheader.offset1=0;
-		arcpacket->hardheader.offset2=offset=512-MinTU;
-		arcsoft=(struct ClientData *)(&arcpacket->raw[offset]);
-	}
-
-
-	/* copy the packet into ARCnet shmem
-	 *  - the first bytes of ClientData header are skipped
-	 */
-	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);
-
-	BUGLVL(D_TX) arcnet_dump_packet(dev,arcpacket->raw,length>MTU,"tx");
-	lp->lastload_dest=daddr;
-	lp->txready=lp->txbuf;	/* packet is ready for sending */
-}
-
-/* Actually start transmitting a packet that was placed in the card's
- * buffer by arcnetAS_prepare_tx.  Returns 1 if a Tx is really started.
- *
- * This should probably always be called with the INTMASK register set to 0,
- * so go_tx is not called recursively.
- *
- * The enable_irq flag determines whether to actually write INTMASK value
- * to the card; TXFREEflag is always OR'ed into the memory variable either
- * way.
- */
-static int
-arcnet_go_tx(struct device *dev,int enable_irq)
-{
-	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
-	int ioaddr=IOADDR;
-
-	BUGMSG(D_DURING,"go_tx: status=%Xh, intmask=%Xh, txready=%d, sending=%d\n",
-		ARCSTATUS,lp->intmask,lp->txready,lp->sending);
-
-	if (lp->sending || !lp->txready)
-	{
-		if (enable_irq && lp->sending)
-		{
-			lp->intmask |= TXFREEflag;
-			SETMASK;
-		}
-		return 0;
-	}
-
-	/* start sending */
-	ACOMMAND(TXcmd|(lp->txready<<3));
-
-	lp->stats.tx_packets++;
-	lp->txready=0;
-	lp->sending++;
-
-	lp->lasttrans_dest=lp->lastload_dest;
-	lp->lastload_dest=0;
-
-	lp->intmask |= TXFREEflag;
-
-	if (enable_irq)	SETMASK;
-
-	return 1;
-}
+	return 1;
+}
 
 
 /****************************************************************************
@@ -1911,274 +927,82 @@
  ****************************************************************************/
 
 
-/* The typical workload of the driver:  Handle the network interface
- * interrupts.  This doesn't do much right now except call arcnet_inthandler,
- * which takes different parameters but may be called from other places
- * as well.
- */
-static void
-arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs)
-{
-	struct device *dev = (struct device *)(irq2dev_map[irq]);
-	int ioaddr;
-
-	if (dev==NULL)
-	{
-		BUGLVL(D_DURING)
-			printk(KERN_DEBUG "arcnet: irq %d for unknown device.\n", irq);
-		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=IOADDR;	/* can't do this before checking dev!=NULL */
-	if (!dev->start)
-	{
-		if (ARCSTATUS & RESETflag)
-			ACOMMAND(CFLAGScmd|RESETclear);
-		return;
-	}
-
-	/* Call the "real" interrupt handler. */
-	arcnet_inthandler(dev);
-}
-
-
-/* The actual interrupt handler routine - handle various IRQ's generated
- * by the card.
- */
-static void
-arcnet_inthandler(struct device *dev)
-{
-	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
-	int ioaddr=IOADDR, status, boguscount = 3, didsomething;
-
-	if (IF_INTERRUPT)
-	{
-		BUGMSG(D_NORMAL,"DRIVER PROBLEM!  Nested arcnet interrupts!\n");
-		return;	/* don't even try. */
-	}
-
-	AINTMASK(0);
-	INTERRUPT = 1;
-
-	BUGMSG(D_DURING,"in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
-		ARCSTATUS,lp->intmask);
-
-	do
-	{
-		status = ARCSTATUS;
-		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)
-		{
-			BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
-					status);
-			arcnet_reset(dev,0);
-
-			/* all other flag values are just garbage */
-			break;
-		}
-
-
-		/* 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",
-					status);
-
-			/* enable receive of our next packet */
-			EnableReceiver();
-
-			/* Got a packet. */
-			arcnet_rx(dev,!recbuf);
-			didsomething++;
-		}
-
-		/* it can only be an xmit-done irq if we're xmitting :) */
-		/*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
-		if (status & lp->intmask & TXFREEflag)
-		{
-			struct Outgoing *out=&(lp->outgoing);
-			int was_sending=lp->sending;
-
-			lp->intmask &= ~TXFREEflag;
-
-			lp->in_txhandler++;
-			if (was_sending) lp->sending--;
-
-			BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
-					status,out->numsegs,out->segnum,out->skb);
-
-			if (was_sending && !(status&TXACKflag))
-			{
-				if (lp->lasttrans_dest != 0)
-				{
-					BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n",
-						status,lp->lasttrans_dest);
-					lp->stats.tx_errors++;
-					lp->stats.tx_carrier_errors++;
-				}
-				else
-				{
-					BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n",
-							status,
-							lp->lasttrans_dest);
-				}
-			}
-
-			/* send packet if there is one */
-			arcnet_go_tx(dev,0);
-			didsomething++;
-
-			if (lp->intx)
-			{
-				BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
-					ARCSTATUS,lp->intx);
-				lp->in_txhandler--;
-				continue;
-			}
-
-			if (!lp->outgoing.skb)
-			{
-				BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
-
-				/* inform upper layers */
-				if (!lp->txready && IF_TBUSY)
-				{
-					TBUSY=0;
-					mark_bh(NET_BH);
-				}
-				lp->in_txhandler--;
-				continue;
-			}
-
-			/* if more than one segment, and not all segments
-			 * are done, then continue xmit.
-			 */
-			if (out->segnum<out->numsegs)
-				arcnetA_continue_tx(dev);
-			arcnet_go_tx(dev,0);
-
-			/* if segnum==numsegs, the transmission is finished;
-			 * free the skb.
-			 */
-			if (out->segnum>=out->numsegs)
-			{
-				/* transmit completed */
-				out->segnum++;
-				if (out->skb)
-					dev_kfree_skb(out->skb,FREE_WRITE);
-				out->skb=NULL;
-
-				/* inform upper layers */
-				if (!lp->txready && IF_TBUSY)
-				{
-					TBUSY=0;
-					mark_bh(NET_BH);
-				}
-			}
-			didsomething++;
-
-			lp->in_txhandler--;
-		}
-		else if (lp->txready && !lp->sending && !lp->intx)
-		{
-			BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n",
-						status);
-			arcnet_go_tx(dev,0);
-			didsomething++;
-		}
-
-#ifdef DETECT_RECONFIGS
-		if (status & (lp->intmask) & RECONflag)
-		{
-			ACOMMAND(CFLAGScmd|CONFIGclear);
-			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;
+/* The typical workload of the driver:  Handle the network interface
+ * interrupts. Establish which device needs attention, and call the correct
+ * chipset interrupt handler.
+ */
+void
+arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs)
+{
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	struct arcnet_local *lp;
+	
+	if (dev==NULL)
+	  {
+	    BUGLVL(D_DURING)
+	      printk(KERN_DEBUG "arcnet: irq %d for unknown device.\n", irq);
+	    return;
+	  }
+	
+	BUGMSG(D_DURING,"in arcnet_interrupt\n");
+	
+	
+	lp=(struct arcnet_local *)dev->priv;
+	
+	/* RESET flag was enabled - if !dev->start, we must clear it right
+	 * away (but nothing else) since inthandler() is never called.
+	 */
+	
+	if (!dev->start)
+	  {	    
+	    if (ARCSTATUS & RESETflag)
+	      ACOMMAND(CFLAGScmd|RESETclear);
+	    return;
+	  }
+	
+
+	if (test_and_set_bit(0, (int *)&dev->interrupt))
+	  {
+	    BUGMSG(D_NORMAL,"DRIVER PROBLEM!  Nested arcnet interrupts!\n");
+	    return;	/* don't even try. */
+	  }
+#ifdef CONFIG_ARCNET_1051
+	lp->sdev->interrupt=1;
+#endif
+#ifdef CONFIG_ARCNET_ETH
+	lp->edev->interrupt=1;
+#endif
 
-			BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
-		}
-		#endif
-#endif /* DETECT_RECONFIGS */
-	} while (--boguscount && didsomething);
+	/* Call the "real" interrupt handler. */
+	(*lp->inthandler)(dev);
 
-	BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
-			ARCSTATUS,boguscount);
-	BUGMSG(D_DURING,"\n");
+#ifdef CONFIG_ARCNET_ETH
+	lp->edev->interrupt=0;
+#endif
+#ifdef CONFIG_ARCNET_1051
+	lp->sdev->interrupt=0;
+#endif
+	if (!test_and_clear_bit(0, (int *)&dev->interrupt))
+	  BUGMSG(D_NORMAL, "Someone cleared our dev->interrupt flag!\n");
 
-	SETMASK;	/* put back interrupt mask */
+}
 
-	INTERRUPT=0;
+void arcnet_tx_done(struct device *dev, struct arcnet_local *lp)
+{
+  if (dev->tbusy)
+    {
+#ifdef CONFIG_ARCNET_ETH
+      lp->edev->tbusy=0;
+#endif
+#ifdef CONFIG_ARCNET_1051
+      lp->sdev->tbusy=0;
+#endif
+      if (!test_and_clear_bit(0, (int *)&dev->tbusy))
+	BUGMSG(D_NORMAL, "In arcnet_tx_done: Someone cleared our dev->tbusy"
+	       " flag!\n");
+      
+      mark_bh(NET_BH);
+    }
 }
 
 
@@ -2188,374 +1012,335 @@
  *                                                                          *
  ****************************************************************************/
 
-
-/* A packet has arrived; grab it from the buffers and possibly unsplit it.
+/* 
  * This is a generic packet receiver that calls arcnet??_rx depending on the
  * protocol ID found.
  */
-static void
-arcnet_rx(struct device *dev,int recbuf)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=IOADDR;
-	union ArcPacket *arcpacket=
-		(union ArcPacket *)phys_to_virt(dev->mem_start+recbuf*512);
-	u_char *arcsoft;
-	short length,offset;
-	u_char daddr,saddr;
 
-	lp->stats.rx_packets++;
-
-	saddr=arcpacket->hardheader.source;
-	daddr=arcpacket->hardheader.destination;
-
-	/* if source is 0, it's a "used" packet! */
-	if (saddr==0)
-	{
-		BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n",
-			ARCSTATUS);
-		lp->stats.rx_errors++;
-		return;
-	}
-	arcpacket->hardheader.source=0;
-
-	if (arcpacket->hardheader.offset1) /* Normal Packet */
-	{
-		offset=arcpacket->hardheader.offset1;
-		arcsoft=&arcpacket->raw[offset];
-		length=256-offset;
-	}
-	else		/* ExtendedPacket or ExceptionPacket */
-	{
-		offset=arcpacket->hardheader.offset2;
-		arcsoft=&arcpacket->raw[offset];
-
-		length=512-offset;
-	}
-
-       	BUGMSG(D_DURING,"received packet from %02Xh to %02Xh (%d bytes)\n",
-       			saddr,daddr,length);
-
-	/* call the right receiver for the protocol */
-	switch (arcsoft[0])
-	{
-	case ARC_P_IP:
-	case ARC_P_ARP:
-	case ARC_P_RARP:
-	case ARC_P_IPX:
-	case ARC_P_NOVELL_EC:
-		arcnetA_rx(lp->adev,arcsoft,length,saddr,daddr);
-		break;
+void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr)
+{
+  struct device *dev=lp->adev;
+  
+  BUGMSG(D_DURING,"received packet from %02Xh to %02Xh (%d bytes)\n",
+	 saddr,daddr,length);
+  
+  /* call the right receiver for the protocol */
+  switch (arcsoft[0])
+    {
+    case ARC_P_IP:
+    case ARC_P_ARP:
+    case ARC_P_RARP:
+    case ARC_P_IPX:
+    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;
+    case ARC_P_ETHER:
+      arcnetE_rx(lp->edev,arcsoft,length,saddr,daddr);
+      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_DATAPOINT_BOOT:
-	case ARC_P_DATAPOINT_MOUNT:
-		break;
-	case ARC_P_POWERLAN_BEACON:
-	case ARC_P_POWERLAN_BEACON2:
-		break;
-	case ARC_P_LANSOFT: /* don't understand.  fall through. */
-	default:
-		BUGMSG(D_EXTRA,"received unknown protocol %d (%Xh) from station %d.\n",
-			arcsoft[0],arcsoft[0],saddr);
-		lp->stats.rx_errors++;
-		lp->stats.rx_crc_errors++;
-		break;
-	}
-
-        BUGLVL(D_RX) arcnet_dump_packet(dev,arcpacket->raw,length>240,"rx");
-
-
-#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)
-	 * has been done by netif_rx and Linux will handle them after we
-	 * return.
-	 */
+    case ARC_P_IP_RFC1051:
+    case ARC_P_ARP_RFC1051:
+      arcnetS_rx(lp->sdev,arcsoft,length,saddr,daddr);
+      break;
+#endif
+    case ARC_P_DATAPOINT_BOOT:
+    case ARC_P_DATAPOINT_MOUNT:
+      break;
+    case ARC_P_POWERLAN_BEACON:
+    case ARC_P_POWERLAN_BEACON2:
+      break;
+    case ARC_P_LANSOFT: /* don't understand.  fall through. */
+    default:
+      BUGMSG(D_EXTRA,"received unknown protocol %d (%Xh) from station %d.\n",
+	     arcsoft[0],arcsoft[0],saddr);
+      lp->stats.rx_errors++;
+      lp->stats.rx_crc_errors++;
+      break;
+    }
+  
+  /* If any worth-while packets have been received, a mark_bh(NET_BH)
+   * has been done by netif_rx and Linux will handle them after we
+   * return.
+   */
+  
+  
 }
 
 
+
 /* Packet receiver for "standard" RFC1201-style packets
  */
 static void
 arcnetA_rx(struct device *dev,u_char *buf,
-	int length,u_char saddr, u_char daddr)
+	   int length, u_char saddr, u_char daddr)
 {
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	struct sk_buff *skb;
-	struct ClientData *arcsoft,*soft;
-
-	BUGMSG(D_DURING,"it's an RFC1201 packet (length=%d)\n",
-			length);
-
-	/* compensate for EXTRA_CLIENTDATA (which isn't actually in the
-	 * packet)
-	 */
-	arcsoft=(struct ClientData *)(buf-EXTRA_CLIENTDATA);
-	length+=EXTRA_CLIENTDATA;
-
-	if (arcsoft->split_flag==0xFF)  /* Exception Packet */
-	{
-		BUGMSG(D_DURING,"compensating for exception packet\n");
-
-		/* skip over 4-byte junkola */
-		arcsoft=(struct ClientData *)
-			((u_char *)arcsoft + 4);
-		length-=4;
+  struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+  struct sk_buff *skb;
+  struct ClientData *arcsoft,*soft;
+  
+  BUGMSG(D_DURING,"it's an RFC1201 packet (length=%d)\n",
+	 length);
+  
+  /* compensate for EXTRA_CLIENTDATA (which isn't actually in the
+   * packet)
+   */
+  arcsoft=(struct ClientData *)(buf-EXTRA_CLIENTDATA);
+  length+=EXTRA_CLIENTDATA;
+  
+  if (arcsoft->split_flag==0xFF)  /* Exception Packet */
+    {
+      BUGMSG(D_DURING,"compensating for exception packet\n");
+      
+      /* skip over 4-byte junkola */
+      arcsoft=(struct ClientData *)
+	((u_char *)arcsoft + 4);
+      length-=4;
+    }
+  
+  if (!arcsoft->split_flag)		/* not split */
+    {
+      struct Incoming *in=&lp->incoming[saddr];
+      
+      BUGMSG(D_RX,"incoming is not split (splitflag=%d)\n",
+	     arcsoft->split_flag);
+      
+      if (in->skb)	/* already assembling one! */
+	{
+	  BUGMSG(D_EXTRA,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
+		 in->sequence,arcsoft->split_flag,
+		 arcsoft->sequence);
+	  lp->aborted_seq=arcsoft->sequence;
+	  kfree_skb(in->skb,FREE_WRITE);
+	  lp->stats.rx_errors++;
+	  lp->stats.rx_missed_errors++;
+	  in->skb=NULL;
+	}
+      
+      in->sequence=arcsoft->sequence;
+      
+      skb = alloc_skb(length, GFP_ATOMIC);
+      if (skb == NULL) {
+	BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
+	lp->stats.rx_dropped++;
+	return;
+      }
+      soft=(struct ClientData *)skb->data;
+      
+      skb_put(skb,length);
+      skb->dev = dev;
+      
+      memcpy((u_char *)soft+EXTRA_CLIENTDATA,
+	     (u_char *)arcsoft+EXTRA_CLIENTDATA,
+	     length-EXTRA_CLIENTDATA);
+      soft->daddr=daddr;
+      soft->saddr=saddr;
+      
+      /* ARP packets have problems when sent from DOS.
+       * source address is always 0 on some systems!  So we take
+       * the hardware source addr (which is impossible to fumble)
+       * and insert it ourselves.
+       */
+      if (soft->protocol_id == ARC_P_ARP)
+	{
+	  struct arphdr *arp=(struct arphdr *)
+	    ((char *)soft+sizeof(struct ClientData));
+	  
+	  /* make sure addresses are the right length */
+	  if (arp->ar_hln==1 && arp->ar_pln==4)
+	    {
+	      char *cptr=(char *)(arp)+sizeof(struct arphdr);
+	      
+	      if (!*cptr)	/* is saddr = 00? */
+		{
+		  BUGMSG(D_EXTRA,"ARP source address was 00h, set to %02Xh.\n",
+			 saddr);
+		  lp->stats.rx_crc_errors++;
+		  *cptr=saddr;
+		}
+	      else
+		{
+		  BUGMSG(D_DURING,"ARP source address (%Xh) is fine.\n",
+			 *cptr);
+		}
+	    }
+	  else
+	    {
+	      BUGMSG(D_NORMAL,"funny-shaped ARP packet. (%Xh, %Xh)\n",
+		     arp->ar_hln,arp->ar_pln);
+	      lp->stats.rx_errors++;
+	      lp->stats.rx_crc_errors++;
+	    }
+	}
+      
+      BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
+      
+      lp->stats.rx_bytes += skb->len;
+      skb->protocol=arcnetA_type_trans(skb,dev);
+      netif_rx(skb);
+    }
+  else			/* split packet */
+    {
+      /* NOTE:  MSDOS ARP packet correction should only need to
+       * apply to unsplit packets, since ARP packets are so short.
+       *
+       * My interpretation of the RFC1201 (ARCnet) document is that
+       * if a packet is received out of order, the entire assembly
+       * process should be aborted.
+       *
+       * The RFC also mentions "it is possible for successfully
+       * received packets to be retransmitted."  As of 0.40 all
+       * previously received packets are allowed, not just the
+       * most recent one.
+       *
+       * We allow multiple assembly processes, one for each
+       * ARCnet card possible on the network.  Seems rather like
+       * a waste of memory.  Necessary?
+       */
+      
+      struct Incoming *in=&lp->incoming[saddr];
+      
+      BUGMSG(D_RX,"packet is split (splitflag=%d, seq=%d)\n",
+	     arcsoft->split_flag,in->sequence);
+      
+      if (in->skb && in->sequence!=arcsoft->sequence)
+	{
+	  BUGMSG(D_EXTRA,"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);
+	  in->skb=NULL;
+	  lp->stats.rx_errors++;
+	  lp->stats.rx_missed_errors++;
+	  in->lastpacket=in->numpackets=0;
+	}
+      
+      if (arcsoft->split_flag & 1)	/* first packet in split */
+	{
+	  BUGMSG(D_RX,"brand new splitpacket (splitflag=%d)\n",
+		 arcsoft->split_flag);
+	  if (in->skb)	/* already assembling one! */
+	    {
+	      BUGMSG(D_EXTRA,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
+		     in->sequence,arcsoft->split_flag,
+		     arcsoft->sequence);
+	      lp->stats.rx_errors++;
+	      lp->stats.rx_missed_errors++;
+	      kfree_skb(in->skb,FREE_WRITE);
+	    }
+	  
+	  in->sequence=arcsoft->sequence;
+	  in->numpackets=((unsigned)arcsoft->split_flag>>1)+2;
+	  in->lastpacket=1;
+	  
+	  if (in->numpackets>16)
+	    {
+	      BUGMSG(D_EXTRA,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
+		     arcsoft->split_flag);
+	      lp->stats.rx_errors++;
+	      lp->stats.rx_length_errors++;
+	      return;
+	    }
+	  
+	  in->skb=skb=alloc_skb(508*in->numpackets
+				+ sizeof(struct ClientData),
+				GFP_ATOMIC);
+	  if (skb == NULL) {
+	    BUGMSG(D_NORMAL,"(split) memory squeeze, dropping packet.\n");
+	    lp->stats.rx_dropped++;
+	    return;
+	  }
+	  
+	  soft=(struct ClientData *)skb->data;
+	  
+	  skb_put(skb,sizeof(struct ClientData));
+	  skb->dev=dev;
+	  
+	  memcpy((u_char *)soft+EXTRA_CLIENTDATA,
+		 (u_char *)arcsoft+EXTRA_CLIENTDATA,
+		 sizeof(struct ClientData)-EXTRA_CLIENTDATA);
+	  soft->split_flag=0; /* final packet won't be split */
+	}
+      else			/* not first packet */
+	{
+	  int packetnum=((unsigned)arcsoft->split_flag>>1) + 1;
+	  
+	  /* if we're not assembling, there's no point
+	   * trying to continue.
+	   */
+	  if (!in->skb)
+	    {
+	      if (lp->aborted_seq != arcsoft->sequence)
+		{
+		  BUGMSG(D_EXTRA,"can't continue split without starting first! (splitflag=%d, seq=%d, aborted=%d)\n",
+			 arcsoft->split_flag,arcsoft->sequence, lp->aborted_seq);
+		  lp->stats.rx_errors++;
+		  lp->stats.rx_missed_errors++;
+		}
+	      return;
+	    }
+	  
+	  in->lastpacket++;
+	  if (packetnum!=in->lastpacket) /* not the right flag! */
+	    {
+	      /* harmless duplicate? ignore. */
+	      if (packetnum<=in->lastpacket-1)
+		{
+		  BUGMSG(D_EXTRA,"duplicate splitpacket ignored! (splitflag=%d)\n",
+			 arcsoft->split_flag);
+		  lp->stats.rx_errors++;
+		  lp->stats.rx_frame_errors++;
+		  return;
+		}
+	      
+	      /* "bad" duplicate, kill reassembly */
+	      BUGMSG(D_EXTRA,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
+		     in->sequence,arcsoft->split_flag,
+		     arcsoft->sequence);
+	      lp->aborted_seq=arcsoft->sequence;
+	      kfree_skb(in->skb,FREE_WRITE);
+	      in->skb=NULL;
+	      lp->stats.rx_errors++;
+	      lp->stats.rx_missed_errors++;
+	      in->lastpacket=in->numpackets=0;
+	      return;
+	    }
+	  
+	  soft=(struct ClientData *)in->skb->data;
+	}
+      
+      skb=in->skb;
+      
+      memcpy(skb->data+skb->len,
+	     (u_char *)arcsoft+sizeof(struct ClientData),
+	     length-sizeof(struct ClientData));
+      skb_put(skb,length-sizeof(struct ClientData));
+      
+      soft->daddr=daddr;
+      soft->saddr=saddr;
+      
+      /* are we done? */
+      if (in->lastpacket == in->numpackets)
+	{
+	  if (!skb || !in->skb)
+	    {
+	      BUGMSG(D_NORMAL,"?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n",
+		     skb,in->skb);
+	    }
+	  else
+	    {
+	      in->skb=NULL;
+	      in->lastpacket=in->numpackets=0;
+	      
+	      BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
+	      
+	      lp->stats.rx_bytes += skb->len;
+	      skb->protocol=arcnetA_type_trans(skb,dev);
+	      netif_rx(skb);
+	    }
 	}
-
-	if (!arcsoft->split_flag)		/* not split */
-	{
-		struct Incoming *in=&lp->incoming[saddr];
-
-		BUGMSG(D_RX,"incoming is not split (splitflag=%d)\n",
-			arcsoft->split_flag);
-
-		if (in->skb)	/* already assembling one! */
-        	{
-        		BUGMSG(D_EXTRA,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
-        			in->sequence,arcsoft->split_flag,
-        			arcsoft->sequence);
-        		kfree_skb(in->skb,FREE_WRITE);
-			lp->stats.rx_errors++;
-        		lp->stats.rx_missed_errors++;
-        		in->skb=NULL;
-        	}
-
-        	in->sequence=arcsoft->sequence;
-
-         	skb = alloc_skb(length, GFP_ATOMIC);
-         	if (skb == NULL) {
-         		BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
-         		lp->stats.rx_dropped++;
-         		return;
-         	}
-         	soft=(struct ClientData *)skb->data;
-
-         	skb->len = length;
-         	skb->dev = dev;
-
-         	memcpy((u_char *)soft+EXTRA_CLIENTDATA,
-         		(u_char *)arcsoft+EXTRA_CLIENTDATA,
-         		length-EXTRA_CLIENTDATA);
-         	soft->daddr=daddr;
-         	soft->saddr=saddr;
-
-         	/* ARP packets have problems when sent from DOS.
-         	 * source address is always 0 on some systems!  So we take
-         	 * the hardware source addr (which is impossible to fumble)
-         	 * and insert it ourselves.
-         	 */
-         	if (soft->protocol_id == ARC_P_ARP)
-         	{
-         		struct arphdr *arp=(struct arphdr *)
-         				((char *)soft+sizeof(struct ClientData));
-
-         		/* make sure addresses are the right length */
-         		if (arp->ar_hln==1 && arp->ar_pln==4)
-         		{
-         			char *cptr=(char *)(arp)+sizeof(struct arphdr);
-
-         			if (!*cptr)	/* is saddr = 00? */
-         			{
-         				BUGMSG(D_EXTRA,"ARP source address was 00h, set to %02Xh.\n",
-         						saddr);
-         				lp->stats.rx_crc_errors++;
-         				*cptr=saddr;
-         			}
-         			else
-         			{
-         				BUGMSG(D_DURING,"ARP source address (%Xh) is fine.\n",
-         					*cptr);
-         			}
-         		}
-         		else
-         		{
-         			BUGMSG(D_NORMAL,"funny-shaped ARP packet. (%Xh, %Xh)\n",
-         				arp->ar_hln,arp->ar_pln);
-         			lp->stats.rx_errors++;
-         			lp->stats.rx_crc_errors++;
-         		}
-         	}
-
-		BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
-
-		skb->protocol=arcnetA_type_trans(skb,dev);
-
-         	netif_rx(skb);
-         }
-         else			/* split packet */
-         {
-	         /* NOTE:  MSDOS ARP packet correction should only need to
-	          * apply to unsplit packets, since ARP packets are so short.
-	          *
-	          * My interpretation of the RFC1201 (ARCnet) document is that
-	          * if a packet is received out of order, the entire assembly
-	          * process should be aborted.
-	          *
-	          * The RFC also mentions "it is possible for successfully
-	          * received packets to be retransmitted."  As of 0.40 all
-	          * previously received packets are allowed, not just the
-	          * most recent one.
-	          *
-	          * We allow multiple assembly processes, one for each
-	          * ARCnet card possible on the network.  Seems rather like
-	          * a waste of memory.  Necessary?
-	          */
-
-	        struct Incoming *in=&lp->incoming[saddr];
-
-	        BUGMSG(D_RX,"packet is split (splitflag=%d, seq=%d)\n",
-	        	arcsoft->split_flag,in->sequence);
-
-		if (in->skb && in->sequence!=arcsoft->sequence)
-		{
-			BUGMSG(D_EXTRA,"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);
-	        	in->skb=NULL;
-			lp->stats.rx_errors++;
-	        	lp->stats.rx_missed_errors++;
-	        	in->lastpacket=in->numpackets=0;
-	        }
-
-	        if (arcsoft->split_flag & 1)	/* first packet in split */
-	        {
-	        	BUGMSG(D_RX,"brand new splitpacket (splitflag=%d)\n",
-	        		arcsoft->split_flag);
-	        	if (in->skb)	/* already assembling one! */
-	        	{
-	        		BUGMSG(D_EXTRA,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
-	        			in->sequence,arcsoft->split_flag,
-	        			arcsoft->sequence);
-				lp->stats.rx_errors++;
-	        		lp->stats.rx_missed_errors++;
-	        		kfree_skb(in->skb,FREE_WRITE);
-	        	}
-
-			in->sequence=arcsoft->sequence;
-	        	in->numpackets=((unsigned)arcsoft->split_flag>>1)+2;
-	        	in->lastpacket=1;
-
-	        	if (in->numpackets>16)
-	        	{
-	        		BUGMSG(D_EXTRA,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
-	        			arcsoft->split_flag);
-	        		lp->stats.rx_errors++;
-	        		lp->stats.rx_length_errors++;
-	        		return;
-	        	}
-
-                	in->skb=skb=alloc_skb(508*in->numpackets
-                			+ sizeof(struct ClientData),
-	                		GFP_ATOMIC);
-                	if (skb == NULL) {
-                		BUGMSG(D_NORMAL,"(split) memory squeeze, dropping packet.\n");
-                		lp->stats.rx_dropped++;
-                		return;
-                	}
-
-                	soft=(struct ClientData *)skb->data;
-
-                	skb->len=sizeof(struct ClientData);
-                	skb->dev=dev;
-
-	         	memcpy((u_char *)soft+EXTRA_CLIENTDATA,
-        	 		(u_char *)arcsoft+EXTRA_CLIENTDATA,
-         			sizeof(struct ClientData)-EXTRA_CLIENTDATA);
-         		soft->split_flag=0; /* final packet won't be split */
-	        }
-	        else			/* not first packet */
-	        {
-			int packetnum=((unsigned)arcsoft->split_flag>>1) + 1;
-
-			/* if we're not assembling, there's no point
-			 * trying to continue.
-			 */
-			if (!in->skb)
-			{
-				BUGMSG(D_EXTRA,"can't continue split without starting first! (splitflag=%d, seq=%d)\n",
-					arcsoft->split_flag,arcsoft->sequence);
-				lp->stats.rx_errors++;
-				lp->stats.rx_missed_errors++;
-				return;
-			}
-
-	        	in->lastpacket++;
-	        	if (packetnum!=in->lastpacket) /* not the right flag! */
-	        	{
-				/* harmless duplicate? ignore. */
-				if (packetnum<=in->lastpacket-1)
-				{
-					BUGMSG(D_EXTRA,"duplicate splitpacket ignored! (splitflag=%d)\n",
-						arcsoft->split_flag);
-					lp->stats.rx_errors++;
-					lp->stats.rx_frame_errors++;
-					return;
-				}
-
-				/* "bad" duplicate, kill reassembly */
-				BUGMSG(D_EXTRA,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
-					in->sequence,arcsoft->split_flag,
-					arcsoft->sequence);
-	        		kfree_skb(in->skb,FREE_WRITE);
-	        		in->skb=NULL;
-				lp->stats.rx_errors++;
-	        		lp->stats.rx_missed_errors++;
-	        		in->lastpacket=in->numpackets=0;
-	        		return;
-	        	}
-
-	               	soft=(struct ClientData *)in->skb->data;
-	        }
-
-	        skb=in->skb;
-
-	        memcpy(skb->data+skb->len,
-	               (u_char *)arcsoft+sizeof(struct ClientData),
-	               length-sizeof(struct ClientData));
-
-         	skb->len+=length-sizeof(struct ClientData);
-
-         	soft->daddr=daddr;
-         	soft->saddr=saddr;
-
-         	/* are we done? */
-         	if (in->lastpacket == in->numpackets)
-         	{
-         		if (!skb || !in->skb)
-         		{
-         			BUGMSG(D_NORMAL,"?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n",
-         				skb,in->skb);
-         		}
-         		else
-         		{
-	         		in->skb=NULL;
-        	 		in->lastpacket=in->numpackets=0;
-
-				BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
-
-				skb->protocol=arcnetA_type_trans(skb,dev);
-
-	         		netif_rx(skb);
-	         	}
-        	}
-         }
+    }
 }
 
 
@@ -2574,99 +1359,83 @@
 
 static struct net_device_stats *arcnet_get_stats(struct device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
-	return &lp->stats;
+  struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+  
+  return &lp->stats;
 }
 
-#if 0	/* standard ARCnet cards have no promiscuous mode */
-/* 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 (num_addrs) {
-		/* Enable promiscuous mode */
-	} else
-		/* Disable promiscuous mode, use normal mode */
-}
-#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)
+static 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;
+  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;
 }
 
 
@@ -2675,42 +1444,42 @@
  * (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(struct sk_buff *skb)
+static int arcnetA_rebuild_header(struct sk_buff *skb)
 {
-	struct ClientData *head = (struct ClientData *)skb->data;
-	struct device *dev=skb->dev;
-	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-	int status;
-
-	/*
-	 * Only ARP and IP are currently supported
-	 *
-	 * FIXME: Anyone want to spec IPv6 over ARCnet ?
-	 */
-
-	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 to get ARP to resolve the header.
-	 */
+  struct ClientData *head = (struct ClientData *)skb->data;
+  struct device *dev=skb->dev;
+  struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
+  int status;
+  
+  /*
+   * Only ARP and IP are currently supported
+   *
+   * FIXME: Anyone want to spec IPv6 over ARCnet ?
+   */
+  
+  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 to 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),skb)? 1 : 0;
-	BUGMSG(D_DURING," rebuilt: from %d to %d; protocol %Xh\n",
-			head->saddr,head->daddr,head->protocol_id);
-	return status;
+  BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n",
+	 head->saddr,head->daddr,head->protocol_id);
+  status=arp_find(&(head->daddr),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;
+  return 0;
 #endif
 }
 
@@ -2719,42 +1488,42 @@
  *
  * With ARCnet we have to convert everything to Ethernet-style stuff.
  */
-unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev)
+static 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:
-		lp->stats.rx_errors++;
-		lp->stats.rx_crc_errors++;
-		return 0;
-	}
-
-	return htons(ETH_P_IP);
+  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:
+      lp->stats.rx_errors++;
+      lp->stats.rx_crc_errors++;
+      return 0;
+    }
+  
+  return htons(ETH_P_IP);
 }
 
 
@@ -2769,19 +1538,17 @@
  */
 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=arcnetE_open_close;
-	dev->stop=arcnetE_open_close;
-	dev->hard_start_xmit=arcnetE_send_packet;
-
-	BUGMSG(D_NORMAL,"ARCnet Ethernet-Encap protocol initialized.\n");
-
-	return 0;
+  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 archdr)-dev->hard_header_len-1;
+  dev->open=arcnetE_open_close;
+  dev->stop=arcnetE_open_close;
+  dev->hard_start_xmit=arcnetE_send_packet;
+  
+  return 0;
 }
 
 
@@ -2790,7 +1557,7 @@
  */
 static int arcnetE_open_close(struct device *dev)
 {
-	return 0;
+  return 0;
 }
 
 
@@ -2799,97 +1566,80 @@
 static int
 arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=IOADDR,bad;
-	union ArcPacket *arcpacket =
-		(union ArcPacket *)phys_to_virt(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_io(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) arcnet_dump_packet(dev,arcpacket->raw,length>=240,"tx");
-
-	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);
-	}
-
+  struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+  int bad,oldmask=0;
+  u_char daddr;
+  short offset,length=skb->len+1;
+  u_char proto=ARC_P_ETHER;
+  
+  lp->intx++;
+  
+  oldmask |= lp->intmask;
+  lp->intmask=0;
+  SETMASK;
+  
+  bad=arcnet_send_packet_bad(skb,dev);
+  if (bad)
+    {
+      lp->intx--;
+      lp->intmask=oldmask;
+      SETMASK;
+      return bad;
+    }
+  
+  /* arcnet_send_packet_pad has already set tbusy - don't bother here. */
+
+  lp->intmask=oldmask;
+  SETMASK;
+  
+  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");
+  
+  /* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
+  if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
+    daddr=0;
+  else
+    daddr=((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;
+    }
+  else			/* short packet */
+    {
+      offset-=256;
+    }
+  
+  BUGMSG(D_DURING," length=%Xh, offset=%Xh\n",
+	 length,offset);
+  
+
+
+  (*lp->prepare_tx)(dev, &proto, 1, skb->data, length-1, daddr, 0, 
+			   offset);
+  
+  
+  
+  dev_kfree_skb(skb,FREE_WRITE);
+
+  if (arcnet_go_tx(dev,1))
+    {
+      /* inform upper layers */
+      arcnet_tx_done(lp->adev, lp);
+    }
+  
 	dev->trans_start=jiffies;
 	lp->intx--;
 
@@ -2920,15 +1670,16 @@
        		return;
        	}
 
-       	skb->len = length;
+       	skb_put(skb,length);
+
        	skb->dev = dev;
 
        	memcpy(skb->data,(u_char *)arcsoft+1,length-1);
 
         BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
 
+	lp->stats.rx_bytes += skb->len;
 	skb->protocol=eth_type_trans(skb,dev);
-
         netif_rx(skb);
 }
 
@@ -2945,23 +1696,22 @@
  */
 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=arcnetS_open_close;
-	dev->stop=arcnetS_open_close;
-	dev->hard_start_xmit=arcnetS_send_packet;
-	dev->hard_header=arcnetS_header;
-	dev->rebuild_header=arcnetS_rebuild_header;
-	BUGMSG(D_NORMAL,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n");
-
-	return 0;
+  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 archdr)-dev->hard_header_len
+    + S_EXTRA_CLIENTDATA;
+  dev->open=arcnetS_open_close;
+  dev->stop=arcnetS_open_close;
+  dev->hard_start_xmit=arcnetS_send_packet;
+  dev->hard_header=arcnetS_header;
+  dev->rebuild_header=arcnetS_rebuild_header;
+  
+  return 0;
 }
 
 
@@ -2970,7 +1720,7 @@
  */
 static int arcnetS_open_close(struct device *dev)
 {
-	return 0;
+  return 0;
 }
 
 
@@ -2979,63 +1729,61 @@
 static int
 arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
 {
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=IOADDR,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) arcnet_dump_skb(dev,skb,"tx");
-
-	/* fits in one packet? */
-	if (length-S_EXTRA_CLIENTDATA<=XMTU)
-	{
-		arcnetAS_prepare_tx(dev,
+  struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+  int 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;
+    }
+
+  /* arcnet_send_packet_pad has already set tbusy - don't bother here. */
+  
+  length = 1 < skb->len ? skb->len : 1;
+  
+  BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx");
+  
+  /* fits in one packet? */
+  if (length-S_EXTRA_CLIENTDATA<=XMTU)
+    {
+      (*lp->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;
+			hdr->daddr,0,0);
+      
+      /* done right away */
+      dev_kfree_skb(skb,FREE_WRITE);
+      
+      if (arcnet_go_tx(dev,1))
+	{
+	  /* inform upper layers */
+	  arcnet_tx_done(lp->adev, lp);
+	}
+    }
+  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++;
+      arcnet_tx_done(lp->adev, lp);
+    }
+  
+  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;
 }
 
 
@@ -3043,47 +1791,45 @@
  */
 static void
 arcnetS_rx(struct device *dev,u_char *buf,
-	int length,u_char saddr, u_char daddr)
+	   int length,u_char saddr, u_char daddr)
 {
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	struct sk_buff *skb;
-	struct S_ClientData *arcsoft,*soft;
-
-	arcsoft=(struct S_ClientData *)(buf-S_EXTRA_CLIENTDATA);
-	length+=S_EXTRA_CLIENTDATA;
-
-	BUGMSG(D_DURING,"it's an RFC1051 packet (length=%d)\n",
-			length);
-
-
-
-	{    /* was "if not split" in A protocol, S is never split */
-
-         	skb = alloc_skb(length, GFP_ATOMIC);
-         	if (skb == NULL) {
-         		BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
-         		lp->stats.rx_dropped++;
-         		return;
-         	}
-         	soft=(struct S_ClientData *)skb->data;
-		skb->len = length;
-		memcpy((u_char *)soft + sizeof(struct S_ClientData)
-				- S_EXTRA_CLIENTDATA,
-			(u_char *)arcsoft + sizeof(struct S_ClientData)
-				- S_EXTRA_CLIENTDATA,
-			length - sizeof(struct S_ClientData)
-				+ S_EXTRA_CLIENTDATA);
-		soft->protocol_id=arcsoft->protocol_id;
-         	soft->daddr=daddr;
-         	soft->saddr=saddr;
-         	skb->dev = dev;  /* is already lp->sdev */
-
-		BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
-
-		skb->protocol=arcnetS_type_trans(skb,dev);
-
-         	netif_rx(skb);
-         }
+  struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+  struct sk_buff *skb;
+  struct S_ClientData *arcsoft,*soft;
+  
+  arcsoft=(struct S_ClientData *)(buf-S_EXTRA_CLIENTDATA);
+  length+=S_EXTRA_CLIENTDATA;
+  
+  BUGMSG(D_DURING,"it's an RFC1051 packet (length=%d)\n",
+	 length);
+  
+  
+  
+  {    /* was "if not split" in A protocol, S is never split */
+    
+    skb = alloc_skb(length, GFP_ATOMIC);
+    if (skb == NULL) {
+      BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
+      lp->stats.rx_dropped++;
+      return;
+    }
+    soft=(struct S_ClientData *)skb->data;
+    skb_put(skb,length);
+
+    memcpy((u_char *)soft + sizeof(struct S_ClientData) - S_EXTRA_CLIENTDATA,
+	   (u_char *)arcsoft + sizeof(struct S_ClientData) -S_EXTRA_CLIENTDATA,
+	   length - sizeof(struct S_ClientData) + S_EXTRA_CLIENTDATA);
+    soft->protocol_id=arcsoft->protocol_id;
+    soft->daddr=daddr;
+    soft->saddr=saddr;
+    skb->dev = dev;  /* is already lp->sdev */
+    
+    BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
+    
+    lp->stats.rx_bytes += skb->len;
+    skb->protocol=arcnetS_type_trans(skb,dev);
+    netif_rx(skb);
+  }
 }
 
 
@@ -3092,55 +1838,55 @@
  * saddr=NULL	means use device source address (always will anyway)
  * daddr=NULL	means leave destination address (eg unresolved arp)
  */
-int arcnetS_header(struct sk_buff *skb,struct device *dev,
-		unsigned short type,void *daddr,void *saddr,unsigned len)
+static int arcnetS_header(struct sk_buff *skb,struct device *dev,
+			  unsigned short type,void *daddr,void *saddr,unsigned len)
 {
-	struct S_ClientData *head = (struct S_ClientData *)
-		skb_push(skb,dev->hard_header_len);
-	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-
-	/* set the protocol ID according to RFC1051 */
-	switch(type)
-	{
-	case ETH_P_IP:
-		head->protocol_id=ARC_P_IP_RFC1051;
-		BUGMSG(D_DURING,"S_header: IP_RFC1051 packet.\n");
-		break;
-	case ETH_P_ARP:
-		head->protocol_id=ARC_P_ARP_RFC1051;
-		BUGMSG(D_DURING,"S_header: ARP_RFC1051 packet.\n");
-		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];
-
-	/* supposedly if daddr is NULL, we should ignore it... */
-	if(daddr)
-	{
+  struct S_ClientData *head = (struct S_ClientData *)
+    skb_push(skb,dev->hard_header_len);
+  struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
+  
+  /* set the protocol ID according to RFC1051 */
+  switch(type)
+    {
+    case ETH_P_IP:
+      head->protocol_id=ARC_P_IP_RFC1051;
+      BUGMSG(D_DURING,"S_header: IP_RFC1051 packet.\n");
+      break;
+    case ETH_P_ARP:
+      head->protocol_id=ARC_P_ARP_RFC1051;
+      BUGMSG(D_DURING,"S_header: ARP_RFC1051 packet.\n");
+      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];
+  
+  /* 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;
+    }
+  else
+    head->daddr=0;	/* better fill one in anyway */
+  
+  return -dev->hard_header_len;
 }
 
 
@@ -3148,34 +1894,34 @@
  * (or in future other address resolution) has completed on this
  * sk_buff. We now let ARP fill in the other fields.
  */
-int arcnetS_rebuild_header(struct sk_buff *skb)
+static int arcnetS_rebuild_header(struct sk_buff *skb)
 {
-	struct device *dev=skb->dev;
-	struct S_ClientData *head = (struct S_ClientData *)skb->data;
-	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-
-	/*
-	 * Only ARP and IP are currently supported
-	 */
-
-	if(head->protocol_id != ARC_P_IP_RFC1051)
-	{
-		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 to get ARP to resolve the header.
-	 */
+  struct device *dev=skb->dev;
+  struct S_ClientData *head = (struct S_ClientData *)skb->data;
+  struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
+  
+  /*
+   * Only ARP and IP are currently supported
+   */
+  
+  if(head->protocol_id != ARC_P_IP_RFC1051)
+    {
+      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 to get ARP to resolve the header.
+   */
 #ifdef CONFIG_INET
-	return arp_find(&(head->daddr),skb)? 1 : 0;
+  return arp_find(&(head->daddr),skb)? 1 : 0;
 #else
-	return 0;
+  return 0;
 #endif
 }
 
@@ -3186,36 +1932,36 @@
  */
 unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev)
 {
-	struct S_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 S_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_RFC1051:	return htons(ETH_P_IP);
-	case ARC_P_ARP_RFC1051:	return htons(ETH_P_ARP);
-	case ARC_P_ATALK:   return htons(ETH_P_ATALK); /* untested appletalk */
-	default:
-		lp->stats.rx_errors++;
-		lp->stats.rx_crc_errors++;
-		return 0;
-	}
-
-	return htons(ETH_P_IP);
+  struct S_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 S_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_RFC1051:	return htons(ETH_P_IP);
+    case ARC_P_ARP_RFC1051:	return htons(ETH_P_ARP);
+    case ARC_P_ATALK:   return htons(ETH_P_ATALK); /* untested appletalk */
+    default:
+      lp->stats.rx_errors++;
+      lp->stats.rx_crc_errors++;
+      return 0;
+    }
+  
+  return htons(ETH_P_IP);
 }
 
 #endif	/* CONFIG_ARCNET_1051 */
@@ -3227,88 +1973,151 @@
  ****************************************************************************/
 
 
+
 #ifdef MODULE
 
-static char devicename[9] = "";
-static struct device thiscard = {
-  devicename, /* device name is inserted by linux/drivers/net/net_init.c */
-  0, 0, 0, 0,
-  0, 0,  /* I/O address, IRQ */
-  0, 0, 0, NULL, arcnet_probe
-};
+void cleanup_module(void)
+{
+  printk("Generic arcnet support removed.\n");
+}
+
+void arcnet_use_count(int open)
+{ 
+  if (open)
+    MOD_INC_USE_COUNT;
+  else
+    MOD_DEC_USE_COUNT;
+}
+
+#else
 
+void arcnet_use_count(int open)
+{
+}
 
-static int io=0x0;	/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
-static int irqnum=0;	/* or use the insmod io= irq= shmem= options */
-static int irq=0;
-static int shmem=0;
-static char *device = NULL;	/* use eg. device="arc1" to change name */
+struct device arcnet_devs[MAX_ARCNET_DEVS];
+int arcnet_num_devs=0;
+char arcnet_dev_names[MAX_ARCNET_DEVS][10];
 
-MODULE_PARM(io, "i");
-MODULE_PARM(irqnum, "i");
-MODULE_PARM(shmem, "i");
+void arcnet_init(void)
+{
+  int c;
+  
+  (void) init_module();
 
-#ifdef RIM_I_MODE
-  static int node=0;	/* you must specify the node ID for RIM I cards */
+  /* Don't register_netdev here. The chain hasn't been initialised. */
+  
+#ifdef CONFIG_ARCNET_COM90xx
+  if ((!com90xx_explicit) && arcnet_num_devs < MAX_ARCNET_DEVS)
+    {
+      arcnet_devs[arcnet_num_devs].init=arc90xx_probe;
+      arcnet_devs[arcnet_num_devs].name=
+	(char *)&arcnet_dev_names[arcnet_num_devs];
+      arcnet_num_devs++;
+    }
 #endif
 
-int init_module(void)
-{
-	struct device *dev=&thiscard;
-	if (device)
-		strcpy(dev->name,device);
-	#ifndef CONFIG_ARCNET_ETHNAME
-	  else if (!dev->name[0]) strcpy(dev->name,"arc0");
-	#endif
+  if (!arcnet_num_devs)
+    {
+      printk("Don't forget to load the chipset driver.\n");
+      return;  
+    }
 
-	#ifdef RIM_I_MODE
-	if (node) io=node;
-	#endif
+  /* Link into the device chain */
 
-	dev->base_addr=io;
+  /* Q: Should we put ourselves at the beginning or the end of the chain? */
+  /* Probably the end, because we're not so fast, but... */
 
-	if (irq) irqnum=irq;
-	dev->irq=irqnum;
-	if (dev->irq==2) dev->irq=9;
+  for (c=0; c< (arcnet_num_devs-1); c++)
+    arcnet_devs[c].next=&arcnet_devs[c+1];
 
-	if (shmem)
-	{
-		dev->mem_start=shmem;
-		dev->mem_end=thiscard.mem_start+512*4-1;
-		dev->rmem_start=thiscard.mem_start+512*0;
-		dev->rmem_end=thiscard.mem_start+512*2-1;
-	}
+  arcnet_devs[c].next=dev_base;
+  dev_base=&arcnet_devs[0];
+  
+  /* Give names to those without them */
+  
+  for (c=0; c< arcnet_num_devs; c++)
+    if (!arcnet_dev_names[c][0])
+      arcnet_makename((char *)&arcnet_dev_names[c]);
 
-	if (register_netdev(dev) != 0)
-		return -EIO;
-	return 0;
 }
-
-void cleanup_module(void)
+static
+#endif /* MODULE */
+int init_module()
 {
-	struct device *dev=&thiscard;
-	int ioaddr=IOADDR;
+ 
+#if 1
+  BUGLVL(D_EXTRA)
+    {
+      printk("arcnet: ***\n");
+      printk("arcnet: * Read arcnet.txt for important release notes!\n");
+      printk("arcnet: *\n");
+      printk("arcnet: * This is an ALPHA version!  (Last stable release: v2.56)  E-mail me if\n");
+      printk("arcnet: * you have any questions, comments, or bug reports.\n");
+      printk("arcnet: ***\n");
+    }
+#endif
+
+  printk("%sGeneric arcnet support for Linux kernel.\n"
+	 "Available protocols: ARCnet RFC1201"
+#ifdef CONFIG_ARCNET_ETH
+	 ", Ethernet-Encap"
+#endif
+#ifdef CONFIG_ARCNET_1051
+	 ", ARCnet RFC1051"
+#endif
+#ifdef MODULE
+	 ".\nDon't forget to load the chipset driver"
+#endif
+	".\n",version);
+  return 0;
+}
+
 
-	if (dev->start) arcnet_close(dev);
 
-	/* Flush TX and disable RX */
-	if (ioaddr)
-	{
-		AINTMASK(0);		/* disable IRQ's */
-		ACOMMAND(NOTXcmd);	/* stop transmit */
-		ACOMMAND(NORXcmd);	/* disable receive */
-	}
 
-	if (dev->irq)
-	{
-		irq2dev_map[dev->irq] = NULL;
-		free_irq(dev->irq,NULL);
-	}
 
-	if (dev->base_addr) RELEASE_REGION(dev->base_addr,ARCNET_TOTAL_SIZE);
-	unregister_netdev(dev);
-	kfree(dev->priv);
-	dev->priv = NULL;
+void arcnet_makename(char *device)
+{
+  __u32 arcmask=0;
+  struct device *dev;
+  char *c;
+  int arcnum;
+
+  for (dev = dev_base; dev; dev=dev->next)
+    {
+      arcnum=0;
+
+      if (!strncmp(dev->name, "arc", 3))
+	{
+	  c = &dev->name[3];
+	  while ((*c)>='0' && (*c)<='9')
+	    {
+	      arcnum *= 10;
+	      arcnum += (*(c++)-'0');
+      	    }
+	  
+	  if (arcnum<32)              
+	    arcmask |= ((__u32)1 << arcnum);
+	}
+      
+      
+    }
+  
+  /* arcmask now holds a mask of the first 32 arcnet names available */
+  
+  if ((__u32)~arcmask)
+    {
+      for (arcnum=0; arcmask&1; arcnum++, arcmask >>=1)
+	;
+      
+      sprintf (device, "arc%d",arcnum);
+    } 
+  else
+    {
+      printk (KERN_INFO "arcnet: Can't find name for device\n");
+      sprintf (device, "arc???");
+    }
 }
 
-#endif /* MODULE */
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov