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

Next file: linux/drivers/net/com20020.c
Previous file: linux/drivers/net/arcnet/rfc1201.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
@@ -1,1981 +0,0 @@
-/*      $Id: arcnet.c,v 1.34 1997/11/09 11:04:55 mj Exp $
-
-   Written 1994-1996 by Avery Pennarun,
-   derived from skeleton.c by Donald Becker.
-
-   **********************
-
-   The original copyright was as follows:
-
-   skeleton.c Written 1993 by Donald Becker.
-   Copyright 1993 United States Government as represented by the
-   Director, National Security Agency.  This software may only be used
-   and distributed according to the terms of the GNU Public License as
-   modified by SRC, incorporated herein by reference.
-
-   **********************
-
-   v3.02 (98/06/07)
-   - Use register_netdevice() instead of register_netdev() to create
-   new devices for RFC1051 and Ethernet encapsulation in arcnet_open.
-   Likewise for unregistering them later. This avoids the deadlock 
-   encountered because the original routines call rtnl_lock() when
-   it's already locked. [dw]
-
-   v3.01 (98/04/17)
-   - Interrupt handler now also checks dev->[se]dev are non-NULL
-   to avoid crashes in interrupts during card init. [dw]
-
-   v3.00 (97/11/09)
-   - Minor cleanup of debugging messages. [mj]
-
-   v2.93 ALPHA (97/11/06)
-   - irq2dev mapping removed.
-   - Interrupt handler now checks whether dev->priv is non-null in order
-   to avoid crashes in interrupts which come during card init. [mj]
-
-   v2.92 ALPHA (97/09/02)
-   - Code cleanup [Martin Mares <mj@atrey.karlin.mff.cuni.cz>]
-   - Better probing for the COM90xx chipset, although only as
-   a temporary solution until we implement adding of all found
-   devices at once. [mj]
-
-   v2.91 ALPHA (97/08/19)
-   - 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. <Dave@imladris.demon.co.uk>
-
-   v2.61 ALPHA (97/07/30)  by David Woodhouse (Dave@imladris.demon.co.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@suse.cz>
-   and Martin Mares <mj@k332.feld.cvut.cz> to make the driver work
-   with the new Linux 2.1.x memory management.  I modified their
-   patch quite a bit though; bugs are my fault.  More changes should
-   be made to get eliminate any remaining phys_to_virt calls.
-   - Quietly ignore protocol id's 0, 1, 8, and 243.  Thanks to Jake
-   Messinger <jake@ams.com> for reporting these codes and their
-   meanings.
-   - Smarter shmem probe for cards with 4k mirrors. (does it work?)
-   - Initial support for RIM I type cards which use no I/O ports at
-   all.  To use this option, you need to compile with RIM_I_MODE
-   enabled.  Thanks to Kolja Waschk <kawk@yo.com> for explaining
-   RIM I programming to me.  Now, does my RIM I code actually
-   work?
-
-   v2.56 (96/10/18)
-   - Turned arc0e/arc0s startup messages back on by default, as most
-   people will probably not notice the additional devices
-   otherwise.  This causes undue confusion.
-   - Fixed a tiny but noticeable bug in the packet debugging routines
-   (thanks Tomasz)
-
-   The following has been SUMMARIZED.  The complete ChangeLog is
-   available in the full Linux-ARCnet package at
-   http://www.worldvisions.ca/~apenwarr/arcnet
-
-   v2.50 (96/02/24)
-   - Massively improved autoprobe routines; they now work even as a
-   module.  Thanks to Vojtech Pavlik <vojtech@suse.cz>
-   for his ideas and help in this area.
-   - Changed printk's around quite a lot.
-
-   v2.22 (95/12/08)
-   - Major cleanups, speedups, and better code-sharing.
-   - Eliminated/changed many useless/meaningless/scary debug messages
-   (and, in most cases, the bugs that caused them).
-   - Better IPX support.
-   - lp->stats updated properly.
-   - RECON checking now by default only prints a message if there are
-   excessive errors (ie. your cable is probably broken).
-   - New RFC1051-compliant "arc0s" virtual device by Tomasz
-   Motylewski.
-   - Excess debug messages can be compiled out to reduce code size.
-
-   v2.00 (95/09/06)
-   - ARCnet RECON messages are now detected and logged as "carrier"
-   errors.
-   - The TXACK flag is now checked, and errors are logged.
-   - Debug levels are now completely different.  See the README.
-   - Massive code cleanups, with several no-longer-necessary and some
-   completely useless options removed.
-   - Multiprotocol support.  You can now use the "arc0e" device to
-   send "Ethernet-Encapsulation" packets, which are compatible with
-   Windows for Workgroups and LAN Manager, and possibly other
-   software.  See the README for more information.
-
-   v1.02 (95/06/21)
-   - A fix to make "exception" packets sent from Linux receivable
-   on other systems.  (The protocol_id byte was sometimes being set
-   incorrectly, and Linux wasn't checking it on receive so it
-   didn't show up)
-
-   v1.01 (95/03/24)
-   - Fixed some IPX-related bugs. (Thanks to Tomasz Motylewski
-   <motyl@tichy.ch.uj.edu.pl> for the patches to make arcnet work
-   with dosemu!)
-
-   v1.00 (95/02/15)
-   - Initial non-alpha release.
-
-
-   TO DO: (semi-prioritized)
-
-   - Use cleaner "architecture-independent" shared memory access.
-   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.
-   - Smarter recovery from RECON-during-transmit conditions. (ie.
-   retransmit immediately)
-   - Add support for the new 1.3.x IP header cache, and other features.
-   - Replace setting of debug level with the "metric" flag hack by
-   something that still exists. SIOCDEVPRIVATE is a good candidate, 
-   but it would require an extra user-level utility.
-
-   - 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! :)
-   - 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
-   Donald Becker - it didn't work :)
-   - skeleton.c v0.05 dated 11/16/93 by Donald Becker
-   (from Linux Kernel 1.1.45)
-   - 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.
-   - Alternate Linux ARCnet source by V.Shergin <vsher@sao.stavropol.su>
-   - Textual information and more alternate source from Joachim Koenig
-   <jojo@repas.de>
- */
-
-static const char *version =
-"arcnet.c: v3.02 98/06/07 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
-
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/version.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#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>
-#include <asm/dma.h>
-
-#include <net/arp.h>
-
-/* 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
- * up as kernel symbols.  (especially handy when using arcnet as a module)
- */
-#undef static
-
-/**************************************************************************/
-
-/* These are now provided by the chipset driver. There's a performance
- * overhead in using them.
- */
-
-#define AINTMASK(x) ((*lp->asetmask)(dev, x))
-#define ARCSTATUS ((*lp->astatus)(dev))
-#define ACOMMAND(x) ((*lp->acommand)(dev, x))
-
-int arcnet_debug = ARCNET_DEBUG;
-
-/* Exported function prototypes */
-
-#ifdef MODULE
-int init_module(void);
-void cleanup_module(void);
-#else
-int arcnet_init(void);
-static int init_module(void);
-#ifdef CONFIG_ARCNET_COM90xx
-extern char com90xx_explicit;
-extern int arc90xx_probe(struct net_device *dev);
-#endif
-#endif
-
-void arcnet_tx_done(struct net_device *dev, struct arcnet_local *lp);
-void arcnet_use_count(int open);
-void arcnet_setup(struct net_device *dev);
-void arcnet_makename(char *device);
-void arcnetA_continue_tx(struct net_device *dev);
-int arcnet_go_tx(struct net_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
-void arcnet_dump_skb(struct net_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)
-void arcnet_dump_packet(struct net_device *dev, u_char * buffer, int ext,
-			char *desc);
-EXPORT_SYMBOL(arcnet_dump_packet);
-#else
-#define arcnet_dump_packet(dev,buffer,ext,desc) ;
-#endif
-
-/* Internal function prototypes */
-
-static int arcnet_open(struct net_device *dev);
-static int arcnet_close(struct net_device *dev);
-static int arcnetA_header(struct sk_buff *skb, struct net_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 net_device *dev);
-static int arcnetA_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void arcnetA_rx(struct net_device *dev, u_char * buf,
-		       int length, u_char saddr, u_char daddr);
-static struct net_device_stats *arcnet_get_stats(struct net_device *dev);
-static unsigned short arcnetA_type_trans(struct sk_buff *skb,
-					 struct net_device *dev);
-
-
-#ifdef CONFIG_ARCNET_ETH
-	/* functions specific to Ethernet-Encap */
-static int arcnetE_init(struct net_device *dev);
-static int arcnetE_open_close(struct net_device *dev);
-static int arcnetE_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void arcnetE_rx(struct net_device *dev, u_char * arcsoft,
-		       int length, u_char saddr, u_char daddr);
-#endif
-
-
-#ifdef CONFIG_ARCNET_1051
-	/* functions specific to RFC1051 */
-static int arcnetS_init(struct net_device *dev);
-static int arcnetS_open_close(struct net_device *dev);
-static int arcnetS_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void arcnetS_rx(struct net_device *dev, u_char * buf,
-		       int length, u_char saddr, u_char daddr);
-static int arcnetS_header(struct sk_buff *skb, struct net_device *dev,
-	    unsigned short type, void *daddr, void *saddr, unsigned len);
-static int arcnetS_rebuild_header(struct sk_buff *skb);
-static unsigned short arcnetS_type_trans(struct sk_buff *skb, struct net_device *dev);
-#endif
-
-
-/****************************************************************************
- *                                                                          *
- * Packet dumps for debugging                                               *
- *                                                                          *
- ****************************************************************************/
-
-/* Dump the contents of an sk_buff
- */
-#if ARCNET_DEBUG_MAX & D_SKB
-void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc)
-{
-	int i;
-	long flags;
-
-	save_flags(flags);
-	cli();
-	printk(KERN_DEBUG "%6s: skb dump (%s) follows:", dev->name, desc);
-	for (i = 0; i < skb->len; i++) {
-		if (i % 16 == 0)
-			printk("\n" KERN_DEBUG "[%04X] ", i);
-		printk("%02X ", ((u_char *) skb->data)[i]);
-	}
-	printk("\n");
-	restore_flags(flags);
-}
-#endif
-
-
-/* Dump the contents of an ARCnet buffer
- */
-#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
-void arcnet_dump_packet(struct net_device *dev, u_char * buffer, int ext, char *desc)
-{
-	int i;
-	long flags;
-
-	save_flags(flags);
-	cli();
-	printk(KERN_DEBUG "%6s: packet dump (%s) follows:", dev->name, desc);
-	for (i = 0; i < 256 + (ext != 0) * 256; i++) {
-		if (i % 16 == 0)
-			printk("\n" KERN_DEBUG "[%04X] ", i);
-		printk("%02X ", buffer[i]);
-	}
-	printk("\n");
-	restore_flags(flags);
-}
-#endif
-
-
-/* Setup a struct net_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 net_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;
-
-	/* New-style flags. */
-	dev->flags = IFF_BROADCAST;
-
-	/* Put in this stuff here, so we don't have to export the symbols
-	 * to the chipset drivers.
-	 */
-
-	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;
-}
-
-
-/****************************************************************************
- *                                                                          *
- * 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 net_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;
-
-	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 net_device *) kmalloc(sizeof(struct net_device), GFP_KERNEL);
-	if (lp->edev == NULL)
-		return -ENOMEM;
-	memcpy(lp->edev, dev, sizeof(struct net_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_netdevice(lp->edev);
-#endif
-
-#ifdef CONFIG_ARCNET_1051
-	/* Initialize the RFC1051-encap protocol driver */
-	lp->sdev = (struct net_device *) kmalloc(sizeof(struct net_device) + 10, GFP_KERNEL);
-	if (lp->sdev == NULL) {
-#ifdef CONFIG_ARCNET_ETH
-		if (lp->edev)
-			kfree(lp->edev);
-		lp->edev = NULL;
-		return -ENOMEM;
-#endif
-	}
-	memcpy(lp->sdev, dev, sizeof(struct net_device));
-	lp->sdev->name = (char *) (lp + 1);
-	sprintf(lp->sdev->name, "%ss", dev->name);
-	lp->sdev->init = arcnetS_init;
-	register_netdevice(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;
-}
-
-
-/* The inverse routine to arcnet_open - shuts down the card.
- */
-static int arcnet_close(struct net_device *dev)
-{
-	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");
-
-	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
-
-	/* 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
-
-	/* 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;
-	unregister_netdevice(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;
-	unregister_netdevice(lp->sdev);
-	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;
-}
-
-
-/****************************************************************************
- *                                                                          *
- * Transmitter routines                                                     *
- *                                                                          *
- ****************************************************************************/
-
-/* Generic error checking routine for arcnet??_send_packet
- */
-static int arcnet_send_packet_bad(struct sk_buff *skb, struct net_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) {
-			dev_kfree_skb(lp->outgoing.skb);
-			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;
-}
-
-
-/* Called by the kernel in order to transmit a packet.
- */
-static int arcnetA_send_packet(struct sk_buff *skb, struct net_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);
-		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);
-			}
-			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.
- */
-void arcnetA_continue_tx(struct net_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++;
-}
-
-
-/* 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 net_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);
-
-	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;
-}
-
-
-/****************************************************************************
- *                                                                          *
- * Interrupt handler                                                        *
- *                                                                          *
- ****************************************************************************/
-
-
-/* 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 net_device *dev = dev_id;
-	struct arcnet_local *lp;
-
-	if (dev == NULL) {
-		BUGMSG(D_DURING, "arcnet: irq %d for unknown device.\n", irq);
-		return;
-	}
-	BUGMSG(D_DURING, "in arcnet_interrupt\n");
-
-	lp = (struct arcnet_local *) dev->priv;
-	if (!lp) {
-		BUGMSG(D_DURING, "arcnet: irq ignored.\n");
-		return;
-	}
-	/* 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
-	if (lp->sdev)
-		lp->sdev->interrupt = 1;
-#endif
-#ifdef CONFIG_ARCNET_ETH
-	if (lp->edev)
-		lp->edev->interrupt = 1;
-#endif
-
-	/* Call the "real" interrupt handler. */
-	(*lp->inthandler) (dev);
-
-#ifdef CONFIG_ARCNET_ETH
-	if (lp->edev)
-		lp->edev->interrupt = 0;
-#endif
-#ifdef CONFIG_ARCNET_1051
-	if (lp->sdev)
-		lp->sdev->interrupt = 0;
-#endif
-	if (!test_and_clear_bit(0, (int *) &dev->interrupt))
-		BUGMSG(D_NORMAL, "Someone cleared our dev->interrupt flag!\n");
-
-}
-
-void arcnet_tx_done(struct net_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);
-	}
-}
-
-
-/****************************************************************************
- *                                                                          *
- * Receiver routines                                                        *
- *                                                                          *
- ****************************************************************************/
-
-/*
- * This is a generic packet receiver that calls arcnet??_rx depending on the
- * protocol ID found.
- */
-
-void arcnet_rx(struct arcnet_local *lp, u_char * arcsoft, short length, int saddr, int daddr)
-{
-	struct net_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;
-#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;
-	}
-
-	/* 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 net_device *dev, u_char * buf,
-		       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;
-	}
-	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);
-			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);
-			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);
-			}
-			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);
-				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);
-			}
-		}
-	}
-}
-
-
-/****************************************************************************
- *                                                                          *
- * Miscellaneous routines                                                   *
- *                                                                          *
- ****************************************************************************/
-
-/* Get the current statistics.  This may be called with the card open or
- * closed.
- */
-
-static struct net_device_stats *arcnet_get_stats(struct net_device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
-
-	return &lp->stats;
-}
-
-
-/* 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)
- */
-static int arcnetA_header(struct sk_buff *skb, struct net_device *dev,
-	     unsigned short type, void *daddr, void *saddr, unsigned len)
-{
-	struct ClientData *head = (struct ClientData *)
-	skb_push(skb, dev->hard_header_len);
-	struct arcnet_local *lp = (struct arcnet_local *) (dev->priv);
-
-	BUGMSG(D_DURING, "create header from %d to %d; protocol %d (%Xh); size %u.\n",
-	       saddr ? *(u_char *) saddr : -1,
-	       daddr ? *(u_char *) daddr : -1,
-	       type, type, len);
-
-	/* set the protocol ID according to RFC1201 */
-	switch (type) {
-	case ETH_P_IP:
-		head->protocol_id = ARC_P_IP;
-		break;
-	case ETH_P_ARP:
-		head->protocol_id = ARC_P_ARP;
-		break;
-	case ETH_P_RARP:
-		head->protocol_id = ARC_P_RARP;
-		break;
-	case ETH_P_IPX:
-	case ETH_P_802_3:
-	case ETH_P_802_2:
-		head->protocol_id = ARC_P_IPX;
-		break;
-	case ETH_P_ATALK:
-		head->protocol_id = ARC_P_ATALK;
-		break;
-	default:
-		BUGMSG(D_NORMAL, "I don't understand protocol %d (%Xh)\n",
-		       type, type);
-		lp->stats.tx_errors++;
-		lp->stats.tx_aborted_errors++;
-		return 0;
-	}
-
-	/*
-	 * Set the source hardware address.
-	 *
-	 * This is pretty pointless for most purposes, but it can help
-	 * in debugging.  saddr is stored in the ClientData header and
-	 * removed before sending the packet (since ARCnet does not allow
-	 * us to change the source address in the actual packet sent)
-	 */
-	if (saddr)
-		head->saddr = ((u_char *) saddr)[0];
-	else
-		head->saddr = ((u_char *) (dev->dev_addr))[0];
-
-	head->split_flag = 0;	/* split packets are done elsewhere */
-	head->sequence = 0;	/* so are sequence numbers */
-
-	/* supposedly if daddr is NULL, we should ignore it... */
-	if (daddr) {
-		head->daddr = ((u_char *) daddr)[0];
-		return dev->hard_header_len;
-	} else
-		head->daddr = 0;	/* better fill one in anyway */
-
-	return -dev->hard_header_len;
-}
-
-
-/* Rebuild the ARCnet ClientData header. This is called after an ARP
- * (or in future other address resolution) has completed on this
- * sk_buff. We now let ARP fill in the other fields.
- */
-static int arcnetA_rebuild_header(struct sk_buff *skb)
-{
-	struct ClientData *head = (struct ClientData *) skb->data;
-	struct net_device *dev = skb->dev;
-	struct arcnet_local *lp = (struct arcnet_local *) (dev->priv);
-#ifdef CONFIG_INET
-	int status;
-#endif
-
-	/*
-	 * 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;
-#else
-	return 0;
-#endif
-}
-
-
-/* Determine a packet's protocol ID.
-
- * With ARCnet we have to convert everything to Ethernet-style stuff.
- */
-static unsigned short arcnetA_type_trans(struct sk_buff *skb, struct net_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);
-}
-
-
-#ifdef CONFIG_ARCNET_ETH
-/****************************************************************************
- *                                                                          *
- * Ethernet-Encap Support                                                   *
- *                                                                          *
- ****************************************************************************/
-
-/* Initialize the arc0e device.
- */
-static int arcnetE_init(struct net_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 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;
-}
-
-
-/* Bring up/down the arc0e device - we don't actually have to do anything,
- * since our parent arc0 handles the card I/O itself.
- */
-static int arcnetE_open_close(struct net_device *dev)
-{
-	return 0;
-}
-
-
-/* Called by the kernel in order to transmit an ethernet-type packet.
- */
-static int arcnetE_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	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);
-		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);
-
-	if (arcnet_go_tx(dev, 1)) {
-		/* inform upper layers */
-		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;
-}
-
-
-/* Packet receiver for ethernet-encap packets.
- */
-static void arcnetE_rx(struct net_device *dev, u_char * arcsoft,
-		       int length, u_char saddr, u_char daddr)
-{
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
-	struct sk_buff *skb;
-
-	BUGMSG(D_DURING, "it's an ethernet-encap packet (length=%d)\n",
-	       length);
-
-	skb = alloc_skb(length, GFP_ATOMIC);
-	if (skb == NULL) {
-		BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
-		lp->stats.rx_dropped++;
-		return;
-	}
-	skb_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);
-}
-
-#endif				/* CONFIG_ARCNET_ETH */
-
-#ifdef CONFIG_ARCNET_1051
-/****************************************************************************
- *                                                                          *
- * RFC1051 Support                                                          *
- *                                                                          *
- ****************************************************************************/
-
-/* Initialize the arc0s device.
- */
-static int arcnetS_init(struct net_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 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;
-}
-
-
-/* Bring up/down the arc0s device - we don't actually have to do anything,
- * since our parent arc0 handles the card I/O itself.
- */
-static int arcnetS_open_close(struct net_device *dev)
-{
-	return 0;
-}
-
-
-/* Called by the kernel in order to transmit an RFC1051-type packet.
- */
-static int arcnetS_send_packet(struct sk_buff *skb, struct net_device *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, 0);
-
-		/* done right away */
-		dev_kfree_skb(skb);
-
-		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);
-		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;
-}
-
-
-/* Packet receiver for RFC1051 packets;
- */
-static void arcnetS_rx(struct net_device *dev, u_char * buf,
-		       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_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);
-	}
-}
-
-
-/* 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)
- */
-static int arcnetS_header(struct sk_buff *skb, struct net_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) {
-		head->daddr = ((u_char *) daddr)[0];
-		return dev->hard_header_len;
-	} else
-		head->daddr = 0;	/* better fill one in anyway */
-
-	return -dev->hard_header_len;
-}
-
-
-/* Rebuild the ARCnet ClientData header. This is called after an ARP
- * (or in future other address resolution) has completed on this
- * sk_buff. We now let ARP fill in the other fields.
- */
-static int arcnetS_rebuild_header(struct sk_buff *skb)
-{
-	struct net_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;
-#else
-	return 0;
-#endif
-}
-
-
-/* Determine a packet's protocol ID.
-
- * With ARCnet we have to convert everything to Ethernet-style stuff.
- */
-unsigned short arcnetS_type_trans(struct sk_buff *skb, struct net_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);
-}
-
-#endif				/* CONFIG_ARCNET_1051 */
-
-
-/****************************************************************************
- *                                                                          *
- * Kernel Loadable Module Support                                           *
- *                                                                          *
- ****************************************************************************/
-
-#ifdef MODULE
-
-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)
-{
-}
-
-struct net_device arcnet_devs[MAX_ARCNET_DEVS];
-int arcnet_num_devs = 0;
-char arcnet_dev_names[MAX_ARCNET_DEVS][10];
-
-int __init arcnet_init(void)
-{
-	int c;
-
-	init_module();
-
-	/* 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
-
-	if (!arcnet_num_devs) {
-		printk("Don't forget to load the chipset driver.\n");
-		return 0;
-	}
-	/* Link into the device chain */
-
-	/* Q: Should we put ourselves at the beginning or the end of the chain? */
-	/* Probably the end, because we're not so fast, but... */
-
-	for (c = 0; c < (arcnet_num_devs - 1); c++)
-		arcnet_devs[c].next = &arcnet_devs[c + 1];
-
-	write_lock_bh(&dev_base_lock);
-	arcnet_devs[c].next = dev_base;
-	dev_base = &arcnet_devs[0];
-	write_unlock_bh(&dev_base_lock);
-
-	/* 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]);
-	return 0;
-}
-
-#endif				/* MODULE */
-
-
-#ifdef MODULE
-int init_module(void)
-#else
-static int __init init_module(void)
-#endif
-{
-#ifdef ALPHA_WARNING
-	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("%sAvailable 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;
-}
-
-
-void arcnet_makename(char *device)
-{
-	struct net_device *dev;
-	int arcnum;
-
-	arcnum = 0;
-	for (;;) {
-		sprintf(device, "arc%d", arcnum);
-		read_lock_bh(&dev_base_lock);
-		for (dev = dev_base; dev; dev = dev->next)
-			if (dev->name != device && !strcmp(dev->name, device))
-				break;
-		read_unlock_bh(&dev_base_lock);
-		if (!dev)
-			return;
-		arcnum++;
-	}
-}

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