v4.19.13 snapshot.
diff --git a/drivers/net/arcnet/Kconfig b/drivers/net/arcnet/Kconfig
new file mode 100644
index 0000000..39bd16f
--- /dev/null
+++ b/drivers/net/arcnet/Kconfig
@@ -0,0 +1,133 @@
+#
+# Arcnet configuration
+#
+
+menuconfig ARCNET
+	depends on NETDEVICES && (ISA || PCI || PCMCIA)
+	tristate "ARCnet support"
+	---help---
+	  If you have a network card of this type, say Y and check out the
+	  (arguably) beautiful poetry in
+	  <file:Documentation/networking/arcnet.txt>.
+
+	  You need both this driver, and the driver for the particular ARCnet
+	  chipset of your card. If you don't know, then it's probably a
+	  COM90xx type card, so say Y (or M) to "ARCnet COM90xx chipset
+	  support" below.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called arcnet.
+
+if ARCNET
+
+config ARCNET_1201
+	tristate "Enable standard ARCNet packet format (RFC 1201)"
+	help
+	  This allows you to use RFC1201 with your ARCnet card via the virtual
+	  arc0 device.  You need to say Y here to communicate with
+	  industry-standard RFC1201 implementations, like the arcether.com
+	  packet driver or most DOS/Windows ODI drivers.  Please read the
+	  ARCnet documentation in <file:Documentation/networking/arcnet.txt>
+	  for more information about using arc0.
+
+config ARCNET_1051
+	tristate "Enable old ARCNet packet format (RFC 1051)"
+	---help---
+	  This allows you to use RFC1051 with your ARCnet card via the virtual
+	  arc0s device. You only need arc0s if you want to talk to ARCnet
+	  software complying with the "old" standard, specifically, the DOS
+	  arcnet.com packet driver, Amigas running AmiTCP, and some variants
+	  of NetBSD. You do not need to say Y here to communicate with
+	  industry-standard RFC1201 implementations, like the arcether.com
+	  packet driver or most DOS/Windows ODI drivers. RFC1201 is included
+	  automatically as the arc0 device. Please read the ARCnet
+	  documentation in <file:Documentation/networking/arcnet.txt> for more
+	  information about using arc0e and arc0s.
+
+config ARCNET_RAW
+	tristate "Enable raw mode packet interface"
+	help
+	  ARCnet "raw mode" packet encapsulation, no soft headers.  Unlikely
+	  to work unless talking to a copy of the same Linux arcnet driver,
+	  but perhaps marginally faster in that case.
+
+config ARCNET_CAP
+	tristate "Enable CAP mode packet interface"
+	help
+	  ARCnet "cap mode" packet encapsulation. Used to get the hardware
+          acknowledge back to userspace. After the initial protocol byte every
+          packet is stuffed with an extra 4 byte "cookie" which doesn't
+          actually appear on the network. After transmit the driver will send
+          back a packet with protocol byte 0 containing the status of the
+          transmission:
+             0=no hardware acknowledge
+             1=excessive nak
+             2=transmission accepted by the receiver hardware
+
+          Received packets are also stuffed with the extra 4 bytes but it will
+          be random data.
+
+          Cap only listens to protocol 1-8.
+
+config ARCNET_COM90xx
+	tristate "ARCnet COM90xx (normal) chipset driver"
+	help
+	  This is the chipset driver for the standard COM90xx cards. If you
+	  have always used the old ARCnet driver without knowing what type of
+	  card you had, this is probably the one for you.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called com90xx.
+
+config ARCNET_COM90xxIO
+	tristate "ARCnet COM90xx (IO mapped) chipset driver"
+	---help---
+	  This is the chipset driver for the COM90xx cards, using them in
+	  IO-mapped mode instead of memory-mapped mode. This is slower than
+	  the normal driver. Only use it if your card doesn't support shared
+	  memory.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called com90io.
+
+config ARCNET_RIM_I
+	tristate "ARCnet COM90xx (RIM I) chipset driver"
+	---help---
+	  This is yet another chipset driver for the COM90xx cards, but this
+	  time only using memory-mapped mode, and no IO ports at all. This
+	  driver is completely untested, so if you have one of these cards,
+	  please mail <dwmw2@infradead.org>, especially if it works!
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called arc-rimi.
+
+config ARCNET_COM20020
+	tristate "ARCnet COM20020 chipset driver"
+	depends on LEDS_CLASS
+	help
+	  This is the driver for the new COM20020 chipset. It supports such
+	  things as promiscuous mode, so packet sniffing is possible, and
+	  extra diagnostic information.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called com20020.
+
+config ARCNET_COM20020_ISA
+	tristate "Support for COM20020 on ISA"
+	depends on ARCNET_COM20020 && ISA
+
+config ARCNET_COM20020_PCI
+	tristate "Support for COM20020 on PCI"
+	depends on ARCNET_COM20020 && PCI
+
+config ARCNET_COM20020_CS
+	tristate "COM20020 ARCnet PCMCIA support"
+	depends on ARCNET_COM20020 && PCMCIA
+	help
+	  Say Y here if you intend to attach this type of ARCnet PCMCIA card
+	  to your computer.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called com20020_cs.  If unsure, say N.
+
+endif # ARCNET
diff --git a/drivers/net/arcnet/Makefile b/drivers/net/arcnet/Makefile
new file mode 100644
index 0000000..53525e8
--- /dev/null
+++ b/drivers/net/arcnet/Makefile
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for linux/drivers/net/arcnet
+#
+
+obj-$(CONFIG_ARCNET) += arcnet.o
+obj-$(CONFIG_ARCNET_1201) += rfc1201.o
+obj-$(CONFIG_ARCNET_1051) += rfc1051.o
+obj-$(CONFIG_ARCNET_RAW) += arc-rawmode.o
+obj-$(CONFIG_ARCNET_CAP) += capmode.o
+obj-$(CONFIG_ARCNET_COM90xx) += com90xx.o
+obj-$(CONFIG_ARCNET_COM90xxIO) += com90io.o
+obj-$(CONFIG_ARCNET_RIM_I) += arc-rimi.o
+obj-$(CONFIG_ARCNET_COM20020) += com20020.o
+obj-$(CONFIG_ARCNET_COM20020_ISA) += com20020-isa.o
+obj-$(CONFIG_ARCNET_COM20020_PCI) += com20020-pci.o
+obj-$(CONFIG_ARCNET_COM20020_CS) += com20020_cs.o
diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c
new file mode 100644
index 0000000..8c651fd
--- /dev/null
+++ b/drivers/net/arcnet/arc-rawmode.c
@@ -0,0 +1,189 @@
+/*
+ * Linux ARCnet driver - "raw mode" packet encapsulation (no soft headers)
+ *
+ * Written 1994-1999 by Avery Pennarun.
+ * Derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+
+#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <net/arp.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include "arcdevice.h"
+
+/* packet receiver */
+static void rx(struct net_device *dev, int bufnum,
+	       struct archdr *pkthdr, int length)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct sk_buff *skb;
+	struct archdr *pkt = pkthdr;
+	int ofs;
+
+	arc_printk(D_DURING, dev, "it's a raw packet (length=%d)\n", length);
+
+	if (length > MTU)
+		ofs = 512 - length;
+	else
+		ofs = 256 - length;
+
+	skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
+	if (!skb) {
+		dev->stats.rx_dropped++;
+		return;
+	}
+	skb_put(skb, length + ARC_HDR_SIZE);
+	skb->dev = dev;
+
+	pkt = (struct archdr *)skb->data;
+
+	skb_reset_mac_header(skb);
+	skb_pull(skb, ARC_HDR_SIZE);
+
+	/* up to sizeof(pkt->soft) has already been copied from the card */
+	memcpy(pkt, pkthdr, sizeof(struct archdr));
+	if (length > sizeof(pkt->soft))
+		lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft),
+				      pkt->soft.raw + sizeof(pkt->soft),
+				      length - sizeof(pkt->soft));
+
+	if (BUGLVL(D_SKB))
+		arcnet_dump_skb(dev, skb, "rx");
+
+	skb->protocol = cpu_to_be16(ETH_P_ARCNET);
+	netif_rx(skb);
+}
+
+/* Create the ARCnet hard/soft headers for raw mode.
+ * There aren't any soft headers in raw mode - not even the protocol id.
+ */
+static int build_header(struct sk_buff *skb, struct net_device *dev,
+			unsigned short type, uint8_t daddr)
+{
+	int hdr_size = ARC_HDR_SIZE;
+	struct archdr *pkt = skb_push(skb, hdr_size);
+
+	/* Set the source hardware address.
+	 *
+	 * This is pretty pointless for most purposes, but it can help in
+	 * debugging.  ARCnet does not allow us to change the source address
+	 * in the actual packet sent.
+	 */
+	pkt->hard.source = *dev->dev_addr;
+
+	/* see linux/net/ethernet/eth.c to see where I got the following */
+
+	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
+		/* FIXME: fill in the last byte of the dest ipaddr here
+		 * to better comply with RFC1051 in "noarp" mode.
+		 */
+		pkt->hard.dest = 0;
+		return hdr_size;
+	}
+	/* otherwise, just fill it in and go! */
+	pkt->hard.dest = daddr;
+
+	return hdr_size;	/* success */
+}
+
+static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
+		      int bufnum)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct arc_hardware *hard = &pkt->hard;
+	int ofs;
+
+	arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",
+		   lp->next_tx, lp->cur_tx, bufnum);
+
+	/* hard header is not included in packet length */
+	length -= ARC_HDR_SIZE;
+
+	if (length > XMTU) {
+		/* should never happen! other people already check for this. */
+		arc_printk(D_NORMAL, dev, "Bug!  prepare_tx with size %d (> %d)\n",
+			   length, XMTU);
+		length = XMTU;
+	}
+	if (length >= MinTU) {
+		hard->offset[0] = 0;
+		hard->offset[1] = ofs = 512 - length;
+	} else if (length > MTU) {
+		hard->offset[0] = 0;
+		hard->offset[1] = ofs = 512 - length - 3;
+	} else {
+		hard->offset[0] = ofs = 256 - length;
+	}
+
+	arc_printk(D_DURING, dev, "prepare_tx: length=%d ofs=%d\n",
+		   length, ofs);
+
+	lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
+	lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length);
+
+	lp->lastload_dest = hard->dest;
+
+	return 1;		/* done */
+}
+
+static struct ArcProto rawmode_proto = {
+	.suffix		= 'r',
+	.mtu		= XMTU,
+	.rx		= rx,
+	.build_header	= build_header,
+	.prepare_tx	= prepare_tx,
+	.continue_tx    = NULL,
+	.ack_tx         = NULL
+};
+
+static int __init arcnet_raw_init(void)
+{
+	int count;
+
+	pr_info("raw mode (`r') encapsulation support loaded\n");
+
+	for (count = 0; count < 256; count++)
+		if (arc_proto_map[count] == arc_proto_default)
+			arc_proto_map[count] = &rawmode_proto;
+
+	/* for raw mode, we only set the bcast proto if there's no better one */
+	if (arc_bcast_proto == arc_proto_default)
+		arc_bcast_proto = &rawmode_proto;
+
+	arc_proto_default = &rawmode_proto;
+	return 0;
+}
+
+static void __exit arcnet_raw_exit(void)
+{
+	arcnet_unregister_proto(&rawmode_proto);
+}
+
+module_init(arcnet_raw_init);
+module_exit(arcnet_raw_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c
new file mode 100644
index 0000000..a07e249
--- /dev/null
+++ b/drivers/net/arcnet/arc-rimi.c
@@ -0,0 +1,381 @@
+/*
+ * Linux ARCnet driver - "RIM I" (entirely mem-mapped) cards
+ *
+ * Written 1994-1999 by Avery Pennarun.
+ * Written 1999-2000 by Martin Mares <mj@ucw.cz>.
+ * Derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+
+#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/bootmem.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include "arcdevice.h"
+#include "com9026.h"
+
+/* Internal function declarations */
+
+static int arcrimi_probe(struct net_device *dev);
+static int arcrimi_found(struct net_device *dev);
+static void arcrimi_command(struct net_device *dev, int command);
+static int arcrimi_status(struct net_device *dev);
+static void arcrimi_setmask(struct net_device *dev, int mask);
+static int arcrimi_reset(struct net_device *dev, int really_reset);
+static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset,
+				 void *buf, int count);
+static void arcrimi_copy_from_card(struct net_device *dev, int bufnum,
+				   int offset, void *buf, int count);
+
+/* Handy defines for ARCnet specific stuff */
+
+/* Amount of I/O memory used by the card */
+#define BUFFER_SIZE	(512)
+#define MIRROR_SIZE	(BUFFER_SIZE * 4)
+
+/* 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.
+ */
+static int __init arcrimi_probe(struct net_device *dev)
+{
+	if (BUGLVL(D_NORMAL)) {
+		pr_info("%s\n", "RIM I (entirely mem-mapped) support");
+		pr_info("E-mail me if you actually test the RIM I driver, please!\n");
+		pr_info("Given: node %02Xh, shmem %lXh, irq %d\n",
+			dev->dev_addr[0], dev->mem_start, dev->irq);
+	}
+
+	if (dev->mem_start <= 0 || dev->irq <= 0) {
+		if (BUGLVL(D_NORMAL))
+			pr_err("No autoprobe for RIM I; you must specify the shmem and irq!\n");
+		return -ENODEV;
+	}
+	if (dev->dev_addr[0] == 0) {
+		if (BUGLVL(D_NORMAL))
+			pr_err("You need to specify your card's station ID!\n");
+		return -ENODEV;
+	}
+	/* Grab the memory region at mem_start for MIRROR_SIZE bytes.
+	 * Later in arcrimi_found() the real size will be determined
+	 * and this reserve will be released and the correct size
+	 * will be taken.
+	 */
+	if (!request_mem_region(dev->mem_start, MIRROR_SIZE, "arcnet (90xx)")) {
+		if (BUGLVL(D_NORMAL))
+			pr_notice("Card memory already allocated\n");
+		return -ENODEV;
+	}
+	return arcrimi_found(dev);
+}
+
+static int check_mirror(unsigned long addr, size_t size)
+{
+	void __iomem *p;
+	int res = -1;
+
+	if (!request_mem_region(addr, size, "arcnet (90xx)"))
+		return -1;
+
+	p = ioremap(addr, size);
+	if (p) {
+		if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue)
+			res = 1;
+		else
+			res = 0;
+		iounmap(p);
+	}
+
+	release_mem_region(addr, size);
+	return res;
+}
+
+/* Set up the struct net_device associated with this card.
+ * Called after probing succeeds.
+ */
+static int __init arcrimi_found(struct net_device *dev)
+{
+	struct arcnet_local *lp;
+	unsigned long first_mirror, last_mirror, shmem;
+	void __iomem *p;
+	int mirror_size;
+	int err;
+
+	p = ioremap(dev->mem_start, MIRROR_SIZE);
+	if (!p) {
+		release_mem_region(dev->mem_start, MIRROR_SIZE);
+		arc_printk(D_NORMAL, dev, "Can't ioremap\n");
+		return -ENODEV;
+	}
+
+	/* reserve the irq */
+	if (request_irq(dev->irq, arcnet_interrupt, 0, "arcnet (RIM I)", dev)) {
+		iounmap(p);
+		release_mem_region(dev->mem_start, MIRROR_SIZE);
+		arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", dev->irq);
+		return -ENODEV;
+	}
+
+	shmem = dev->mem_start;
+	arcnet_writeb(TESTvalue, p, COM9026_REG_W_INTMASK);
+	arcnet_writeb(TESTvalue, p, COM9026_REG_W_COMMAND);
+					/* actually the station/node ID */
+
+	/* find the real shared memory start/end points, including mirrors */
+
+	/* 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 (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue &&
+	    check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 &&
+	    check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1)
+		mirror_size = 2 * MIRROR_SIZE;
+
+	first_mirror = shmem - mirror_size;
+	while (check_mirror(first_mirror, mirror_size) == 1)
+		first_mirror -= mirror_size;
+	first_mirror += mirror_size;
+
+	last_mirror = shmem + mirror_size;
+	while (check_mirror(last_mirror, mirror_size) == 1)
+		last_mirror += mirror_size;
+	last_mirror -= mirror_size;
+
+	dev->mem_start = first_mirror;
+	dev->mem_end = last_mirror + MIRROR_SIZE - 1;
+
+	/* initialize the rest of the device structure. */
+
+	lp = netdev_priv(dev);
+	lp->card_name = "RIM I";
+	lp->hw.command = arcrimi_command;
+	lp->hw.status = arcrimi_status;
+	lp->hw.intmask = arcrimi_setmask;
+	lp->hw.reset = arcrimi_reset;
+	lp->hw.owner = THIS_MODULE;
+	lp->hw.copy_to_card = arcrimi_copy_to_card;
+	lp->hw.copy_from_card = arcrimi_copy_from_card;
+
+	/* re-reserve the memory region - arcrimi_probe() alloced this reqion
+	 * but didn't know the real size.  Free that region and then re-get
+	 * with the correct size.  There is a VERY slim chance this could
+	 * fail.
+	 */
+	iounmap(p);
+	release_mem_region(shmem, MIRROR_SIZE);
+	if (!request_mem_region(dev->mem_start,
+				dev->mem_end - dev->mem_start + 1,
+				"arcnet (90xx)")) {
+		arc_printk(D_NORMAL, dev, "Card memory already allocated\n");
+		goto err_free_irq;
+	}
+
+	lp->mem_start = ioremap(dev->mem_start,
+				dev->mem_end - dev->mem_start + 1);
+	if (!lp->mem_start) {
+		arc_printk(D_NORMAL, dev, "Can't remap device memory!\n");
+		goto err_release_mem;
+	}
+
+	/* get and check the station ID from offset 1 in shmem */
+	dev->dev_addr[0] = arcnet_readb(lp->mem_start, COM9026_REG_R_STATION);
+
+	arc_printk(D_NORMAL, dev, "ARCnet RIM I: station %02Xh found at IRQ %d, ShMem %lXh (%ld*%d bytes)\n",
+		   dev->dev_addr[0],
+		   dev->irq, dev->mem_start,
+		   (dev->mem_end - dev->mem_start + 1) / mirror_size,
+		   mirror_size);
+
+	err = register_netdev(dev);
+	if (err)
+		goto err_unmap;
+
+	return 0;
+
+err_unmap:
+	iounmap(lp->mem_start);
+err_release_mem:
+	release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
+err_free_irq:
+	free_irq(dev->irq, dev);
+	return -EIO;
+}
+
+/* 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.
+ */
+static int arcrimi_reset(struct net_device *dev, int really_reset)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->mem_start + 0x800;
+
+	arc_printk(D_INIT, dev, "Resetting %s (status=%02Xh)\n",
+		   dev->name, arcnet_readb(ioaddr, COM9026_REG_R_STATUS));
+
+	if (really_reset) {
+		arcnet_writeb(TESTvalue, ioaddr, -0x800);	/* fake reset */
+		return 0;
+	}
+	/* clear flags & end reset */
+	arcnet_writeb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND);
+	arcnet_writeb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND);
+
+	/* enable extended (512-byte) packets */
+	arcnet_writeb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND);
+
+	/* done!  return success. */
+	return 0;
+}
+
+static void arcrimi_setmask(struct net_device *dev, int mask)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->mem_start + 0x800;
+
+	arcnet_writeb(mask, ioaddr, COM9026_REG_W_INTMASK);
+}
+
+static int arcrimi_status(struct net_device *dev)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->mem_start + 0x800;
+
+	return arcnet_readb(ioaddr, COM9026_REG_R_STATUS);
+}
+
+static void arcrimi_command(struct net_device *dev, int cmd)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->mem_start + 0x800;
+
+	arcnet_writeb(cmd, ioaddr, COM9026_REG_W_COMMAND);
+}
+
+static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset,
+				 void *buf, int count)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
+
+	TIME(dev, "memcpy_toio", count, memcpy_toio(memaddr, buf, count));
+}
+
+static void arcrimi_copy_from_card(struct net_device *dev, int bufnum,
+				   int offset, void *buf, int count)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
+
+	TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
+}
+
+static int node;
+static int io;			/* use the insmod io= irq= node= options */
+static int irq;
+static char device[9];		/* use eg. device=arc1 to change name */
+
+module_param(node, int, 0);
+module_param(io, int, 0);
+module_param(irq, int, 0);
+module_param_string(device, device, sizeof(device), 0);
+MODULE_LICENSE("GPL");
+
+static struct net_device *my_dev;
+
+static int __init arc_rimi_init(void)
+{
+	struct net_device *dev;
+
+	dev = alloc_arcdev(device);
+	if (!dev)
+		return -ENOMEM;
+
+	if (node && node != 0xff)
+		dev->dev_addr[0] = node;
+
+	dev->mem_start = io;
+	dev->irq = irq;
+	if (dev->irq == 2)
+		dev->irq = 9;
+
+	if (arcrimi_probe(dev)) {
+		free_netdev(dev);
+		return -EIO;
+	}
+
+	my_dev = dev;
+	return 0;
+}
+
+static void __exit arc_rimi_exit(void)
+{
+	struct net_device *dev = my_dev;
+	struct arcnet_local *lp = netdev_priv(dev);
+
+	unregister_netdev(dev);
+	iounmap(lp->mem_start);
+	release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
+	free_irq(dev->irq, dev);
+	free_netdev(dev);
+}
+
+#ifndef MODULE
+static int __init arcrimi_setup(char *s)
+{
+	int ints[8];
+
+	s = get_options(s, 8, ints);
+	if (!ints[0])
+		return 1;
+	switch (ints[0]) {
+	default:		/* ERROR */
+		pr_err("Too many arguments\n");
+	case 3:		/* Node ID */
+		node = ints[3];
+	case 2:		/* IRQ */
+		irq = ints[2];
+	case 1:		/* IO address */
+		io = ints[1];
+	}
+	if (*s)
+		snprintf(device, sizeof(device), "%s", s);
+	return 1;
+}
+__setup("arcrimi=", arcrimi_setup);
+#endif				/* MODULE */
+
+module_init(arc_rimi_init)
+module_exit(arc_rimi_exit)
diff --git a/drivers/net/arcnet/arcdevice.h b/drivers/net/arcnet/arcdevice.h
new file mode 100644
index 0000000..d09b2b4
--- /dev/null
+++ b/drivers/net/arcnet/arcdevice.h
@@ -0,0 +1,393 @@
+/*
+ * INET         An implementation of the TCP/IP protocol suite for the LINUX
+ *              operating system.  NET  is implemented using the  BSD Socket
+ *              interface as the means of communication with the user level.
+ *
+ *              Definitions used by the ARCnet driver.
+ *
+ * Authors:     Avery Pennarun and David Woodhouse
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ */
+#ifndef _LINUX_ARCDEVICE_H
+#define _LINUX_ARCDEVICE_H
+
+#include <asm/timex.h>
+#include <linux/if_arcnet.h>
+
+#ifdef __KERNEL__
+#include <linux/interrupt.h>
+
+/*
+ * RECON_THRESHOLD is the maximum number of RECON messages to receive
+ * within one minute before printing a "cabling problem" warning. 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 high.
+ */
+#define TX_TIMEOUT (HZ * 200 / 1000)
+
+/* Display warnings about the driver being an ALPHA version. */
+#undef ALPHA_WARNING
+
+/*
+ * Debugging bitflags: each option can be enabled individually.
+ *
+ * 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     */
+#define D_RECON		32	/* print a message whenever token is lost */
+#define D_PROTO		64	/* debug auto-protocol support            */
+/* debug levels below give LOTS of output during normal operation! */
+#define D_DURING	128	/* trace operations (including irq's)     */
+#define D_TX	        256	/* show tx packets                        */
+#define D_RX		512	/* show rx packets                        */
+#define D_SKB		1024	/* show skb's                             */
+#define D_SKB_SIZE	2048	/* show skb sizes			  */
+#define D_TIMING	4096	/* show time needed to copy buffers to card */
+#define D_DEBUG         8192    /* Very detailed debug line for line */
+
+#ifndef ARCNET_DEBUG_MAX
+#define ARCNET_DEBUG_MAX (127)	/* change to ~0 if you want detailed debugging */
+#endif
+
+#ifndef ARCNET_DEBUG
+#define ARCNET_DEBUG (D_NORMAL | D_EXTRA)
+#endif
+extern int arcnet_debug;
+
+#define BUGLVL(x)	((x) & ARCNET_DEBUG_MAX & arcnet_debug)
+
+/* macros to simplify debug checking */
+#define arc_printk(x, dev, fmt, ...)					\
+do {									\
+	if (BUGLVL(x)) {						\
+		if ((x) == D_NORMAL)					\
+			netdev_warn(dev, fmt, ##__VA_ARGS__);		\
+		else if ((x) < D_DURING)				\
+			netdev_info(dev, fmt, ##__VA_ARGS__);		\
+		else							\
+			netdev_dbg(dev, fmt, ##__VA_ARGS__);		\
+	}								\
+} while (0)
+
+#define arc_cont(x, fmt, ...)						\
+do {									\
+	if (BUGLVL(x))							\
+		pr_cont(fmt, ##__VA_ARGS__);				\
+} while (0)
+
+/* see how long a function call takes to run, expressed in CPU cycles */
+#define TIME(dev, name, bytes, call)					\
+do {									\
+	if (BUGLVL(D_TIMING)) {						\
+		unsigned long _x, _y;					\
+		_x = get_cycles();					\
+		call;							\
+		_y = get_cycles();					\
+		arc_printk(D_TIMING, dev,				\
+			   "%s: %d bytes in %lu cycles == %lu Kbytes/100Mcycle\n", \
+			   name, bytes, _y - _x,			\
+			   100000000 / 1024 * bytes / (_y - _x + 1));	\
+	} else {							\
+		call;							\
+	}								\
+} while (0)
+
+/*
+ * Time needed to reset the card - in ms (milliseconds).  This works on my
+ * SMC PC100.  I can't find a reference that tells me just how long I
+ * should wait.
+ */
+#define RESETtime (300)
+
+/*
+ * These are the max/min lengths of packet payload, not including the
+ * arc_hardware header, but definitely including the soft header.
+ *
+ * Note: packet sizes 254, 255, 256 are impossible because of the way
+ * ARCnet registers work  That's why RFC1201 defines "exception" packets.
+ * In non-RFC1201 protocols, we have to just tack some extra bytes on the
+ * end.
+ */
+#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	/* network reconfigured */
+#define TESTflag        0x08	/* test flag */
+#define EXCNAKflag      0x08    /* excesive nak 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 */
+
+/* Flags used for IO-mapped memory operations */
+#define AUTOINCflag     0x40	/* Increase location with each access */
+#define IOMAPflag       0x02	/* (for 90xx) Use IO mapped memory, not mmap */
+#define ENABLE16flag    0x80	/* (for 90xx) Enable 16-bit mode */
+
+/* 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 */
+#define STARTIOcmd      0x18	/* start internal operation */
+
+/* flags for "clear flags" command */
+#define RESETclear      0x08	/* power-on-reset */
+#define CONFIGclear     0x10	/* system reconfigured */
+
+#define EXCNAKclear     0x0E    /* Clear and acknowledge the excive nak bit */
+
+/* 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 */
+
+/* card feature flags, set during auto-detection.
+ * (currently only used by com20020pci)
+ */
+#define ARC_IS_5MBIT    1   /* card default speed is 5MBit */
+#define ARC_CAN_10MBIT  2   /* card uses COM20022, supporting 10MBit,
+				 but default is 2.5MBit. */
+
+/* information needed to define an encapsulation driver */
+struct ArcProto {
+	char suffix;		/* a for RFC1201, e for ether-encap, etc. */
+	int mtu;		/* largest possible packet */
+	int is_ip;              /* This is a ip plugin - not a raw thing */
+
+	void (*rx)(struct net_device *dev, int bufnum,
+		   struct archdr *pkthdr, int length);
+	int (*build_header)(struct sk_buff *skb, struct net_device *dev,
+			    unsigned short ethproto, uint8_t daddr);
+
+	/* these functions return '1' if the skb can now be freed */
+	int (*prepare_tx)(struct net_device *dev, struct archdr *pkt,
+			  int length, int bufnum);
+	int (*continue_tx)(struct net_device *dev, int bufnum);
+	int (*ack_tx)(struct net_device *dev, int acked);
+};
+
+extern struct ArcProto *arc_proto_map[256], *arc_proto_default,
+	*arc_bcast_proto, *arc_raw_proto;
+
+/*
+ * "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             */
+	__be16 sequence;	/* sequence number of assembly    */
+	uint8_t lastpacket,	/* number of last packet (from 1) */
+		numpackets;	/* number of packets in split     */
+};
+
+/* only needed for RFC1201 */
+struct Outgoing {
+	struct ArcProto *proto;	/* protocol driver that owns this:
+				 *   if NULL, no packet is pending.
+				 */
+	struct sk_buff *skb;	/* buffer from upper levels */
+	struct archdr *pkt;	/* a pointer into the skb */
+	uint16_t length,	/* bytes total */
+		dataleft,	/* bytes left */
+		segnum,		/* segment being sent */
+		numsegs;	/* number of segments */
+};
+
+#define ARCNET_LED_NAME_SZ (IFNAMSIZ + 6)
+
+struct arcnet_local {
+	uint8_t config,		/* current value of CONFIG register */
+		timeout,	/* Extended timeout for COM20020 */
+		backplane,	/* Backplane flag for COM20020 */
+		clockp,		/* COM20020 clock divider */
+		clockm,		/* COM20020 clock multiplier flag */
+		setup,		/* Contents of setup1 register */
+		setup2,		/* Contents of setup2 register */
+		intmask;	/* current value of INTMASK register */
+	uint8_t default_proto[256];	/* default encap to use for each host */
+	int	cur_tx,		/* buffer used by current transmit, or -1 */
+		next_tx,	/* buffer where a packet is ready to send */
+		cur_rx;		/* current receive buffer */
+	int	lastload_dest,	/* can last loaded packet be acked? */
+		lasttrans_dest;	/* can last TX'd packet be acked? */
+	int	timed_out;	/* need to process TX timeout and drop packet */
+	unsigned long last_timeout;	/* time of last reported timeout */
+	char *card_name;	/* card ident string */
+	int card_flags;		/* special card features */
+
+	/* On preemtive and SMB a lock is needed */
+	spinlock_t lock;
+
+	struct led_trigger *tx_led_trig;
+	char tx_led_trig_name[ARCNET_LED_NAME_SZ];
+	struct led_trigger *recon_led_trig;
+	char recon_led_trig_name[ARCNET_LED_NAME_SZ];
+
+	struct timer_list	timer;
+
+	struct net_device *dev;
+	int reply_status;
+	struct tasklet_struct reply_tasklet;
+
+	/*
+	 * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of
+	 * which can be used for either sending or receiving.  The new dynamic
+	 * buffer management routines use a simple circular queue of available
+	 * buffers, and take them as they're needed.  This way, we simplify
+	 * situations in which we (for example) want to pre-load a transmit
+	 * buffer, or start receiving while we copy a received packet to
+	 * memory.
+	 *
+	 * The rules: only the interrupt handler is allowed to _add_ buffers to
+	 * the queue; thus, this doesn't require a lock.  Both the interrupt
+	 * handler and the transmit function will want to _remove_ buffers, so
+	 * we need to handle the situation where they try to do it at the same
+	 * time.
+	 *
+	 * If next_buf == first_free_buf, the queue is empty.  Since there are
+	 * only four possible buffers, the queue should never be full.
+	 */
+	atomic_t buf_lock;
+	int buf_queue[5];
+	int next_buf, first_free_buf;
+
+	/* network "reconfiguration" handling */
+	unsigned long first_recon; /* time of "first" RECON message to count */
+	unsigned long last_recon;  /* time of most recent RECON */
+	int num_recons;		/* number of RECONs between first and last. */
+	int network_down;	/* do we think the network is down? */
+
+	int excnak_pending;    /* We just got an excesive nak interrupt */
+
+	struct {
+		uint16_t sequence;	/* sequence number (incs with each packet) */
+		__be16 aborted_seq;
+
+		struct Incoming incoming[256];	/* one from each address */
+	} rfc1201;
+
+	/* really only used by rfc1201, but we'll pretend it's not */
+	struct Outgoing outgoing;	/* packet currently being sent */
+
+	/* hardware-specific functions */
+	struct {
+		struct module *owner;
+		void (*command)(struct net_device *dev, int cmd);
+		int (*status)(struct net_device *dev);
+		void (*intmask)(struct net_device *dev, int mask);
+		int (*reset)(struct net_device *dev, int really_reset);
+		void (*open)(struct net_device *dev);
+		void (*close)(struct net_device *dev);
+		void (*datatrigger) (struct net_device * dev, int enable);
+		void (*recontrigger) (struct net_device * dev, int enable);
+
+		void (*copy_to_card)(struct net_device *dev, int bufnum,
+				     int offset, void *buf, int count);
+		void (*copy_from_card)(struct net_device *dev, int bufnum,
+				       int offset, void *buf, int count);
+	} hw;
+
+	void __iomem *mem_start;	/* pointer to ioremap'ed MMIO */
+};
+
+enum arcnet_led_event {
+	ARCNET_LED_EVENT_RECON,
+	ARCNET_LED_EVENT_OPEN,
+	ARCNET_LED_EVENT_STOP,
+	ARCNET_LED_EVENT_TX,
+};
+
+void arcnet_led_event(struct net_device *netdev, enum arcnet_led_event event);
+void devm_arcnet_led_init(struct net_device *netdev, int index, int subid);
+
+#if ARCNET_DEBUG_MAX & D_SKB
+void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc);
+#else
+static inline
+void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc)
+{
+}
+#endif
+
+void arcnet_unregister_proto(struct ArcProto *proto);
+irqreturn_t arcnet_interrupt(int irq, void *dev_id);
+struct net_device *alloc_arcdev(const char *name);
+
+int arcnet_open(struct net_device *dev);
+int arcnet_close(struct net_device *dev);
+netdev_tx_t arcnet_send_packet(struct sk_buff *skb,
+			       struct net_device *dev);
+void arcnet_timeout(struct net_device *dev);
+
+/* I/O equivalents */
+
+#ifdef CONFIG_SA1100_CT6001
+#define BUS_ALIGN  2  /* 8 bit device on a 16 bit bus - needs padding */
+#else
+#define BUS_ALIGN  1
+#endif
+
+/* addr and offset allow register like names to define the actual IO  address.
+ * A configuration option multiplies the offset for alignment.
+ */
+#define arcnet_inb(addr, offset)					\
+	inb((addr) + BUS_ALIGN * (offset))
+#define arcnet_outb(value, addr, offset)				\
+	outb(value, (addr) + BUS_ALIGN * (offset))
+
+#define arcnet_insb(addr, offset, buffer, count)			\
+	insb((addr) + BUS_ALIGN * (offset), buffer, count)
+#define arcnet_outsb(addr, offset, buffer, count)			\
+	outsb((addr) + BUS_ALIGN * (offset), buffer, count)
+
+#define arcnet_readb(addr, offset)					\
+	readb((addr) + (offset))
+#define arcnet_writeb(value, addr, offset)				\
+	writeb(value, (addr) + (offset))
+
+#endif				/* __KERNEL__ */
+#endif				/* _LINUX_ARCDEVICE_H */
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
new file mode 100644
index 0000000..8459115
--- /dev/null
+++ b/drivers/net/arcnet/arcnet.c
@@ -0,0 +1,1159 @@
+/*
+ * Linux ARCnet driver - device-independent routines
+ *
+ * Written 1997 by David Woodhouse.
+ * Written 1994-1999 by Avery Pennarun.
+ * Written 1999-2000 by Martin Mares <mj@ucw.cz>.
+ * Derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * The change log is now in a file called ChangeLog in this directory.
+ *
+ * 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 SMSC.
+ *  - 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>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <net/arp.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/errqueue.h>
+
+#include <linux/leds.h>
+
+#include "arcdevice.h"
+#include "com9026.h"
+
+/* "do nothing" functions for protocol drivers */
+static void null_rx(struct net_device *dev, int bufnum,
+		    struct archdr *pkthdr, int length);
+static int null_build_header(struct sk_buff *skb, struct net_device *dev,
+			     unsigned short type, uint8_t daddr);
+static int null_prepare_tx(struct net_device *dev, struct archdr *pkt,
+			   int length, int bufnum);
+
+static void arcnet_rx(struct net_device *dev, int bufnum);
+
+/* one ArcProto per possible proto ID.  None of the elements of
+ * arc_proto_map are allowed to be NULL; they will get set to
+ * arc_proto_default instead.  It also must not be NULL; if you would like
+ * to set it to NULL, set it to &arc_proto_null instead.
+ */
+struct ArcProto *arc_proto_map[256];
+EXPORT_SYMBOL(arc_proto_map);
+
+struct ArcProto *arc_proto_default;
+EXPORT_SYMBOL(arc_proto_default);
+
+struct ArcProto *arc_bcast_proto;
+EXPORT_SYMBOL(arc_bcast_proto);
+
+struct ArcProto *arc_raw_proto;
+EXPORT_SYMBOL(arc_raw_proto);
+
+static struct ArcProto arc_proto_null = {
+	.suffix		= '?',
+	.mtu		= XMTU,
+	.is_ip          = 0,
+	.rx		= null_rx,
+	.build_header	= null_build_header,
+	.prepare_tx	= null_prepare_tx,
+	.continue_tx    = NULL,
+	.ack_tx         = NULL
+};
+
+/* Exported function prototypes */
+int arcnet_debug = ARCNET_DEBUG;
+EXPORT_SYMBOL(arcnet_debug);
+
+/* Internal function prototypes */
+static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
+			 unsigned short type, const void *daddr,
+			 const void *saddr, unsigned len);
+static int go_tx(struct net_device *dev);
+
+static int debug = ARCNET_DEBUG;
+module_param(debug, int, 0);
+MODULE_LICENSE("GPL");
+
+static int __init arcnet_init(void)
+{
+	int count;
+
+	arcnet_debug = debug;
+
+	pr_info("arcnet loaded\n");
+
+	/* initialize the protocol map */
+	arc_raw_proto = arc_proto_default = arc_bcast_proto = &arc_proto_null;
+	for (count = 0; count < 256; count++)
+		arc_proto_map[count] = arc_proto_default;
+
+	if (BUGLVL(D_DURING))
+		pr_info("struct sizes: %zd %zd %zd %zd %zd\n",
+			sizeof(struct arc_hardware),
+			sizeof(struct arc_rfc1201),
+			sizeof(struct arc_rfc1051),
+			sizeof(struct arc_eth_encap),
+			sizeof(struct archdr));
+
+	return 0;
+}
+
+static void __exit arcnet_exit(void)
+{
+}
+
+module_init(arcnet_init);
+module_exit(arcnet_exit);
+
+/* 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)
+{
+	char hdr[32];
+
+	/* dump the packet */
+	snprintf(hdr, sizeof(hdr), "%6s:%s skb->data:", dev->name, desc);
+	print_hex_dump(KERN_DEBUG, hdr, DUMP_PREFIX_OFFSET,
+		       16, 1, skb->data, skb->len, true);
+}
+EXPORT_SYMBOL(arcnet_dump_skb);
+#endif
+
+/* Dump the contents of an ARCnet buffer */
+#if (ARCNET_DEBUG_MAX & (D_RX | D_TX))
+static void arcnet_dump_packet(struct net_device *dev, int bufnum,
+			       char *desc, int take_arcnet_lock)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	int i, length;
+	unsigned long flags = 0;
+	static uint8_t buf[512];
+	char hdr[32];
+
+	/* hw.copy_from_card expects IRQ context so take the IRQ lock
+	 * to keep it single threaded
+	 */
+	if (take_arcnet_lock)
+		spin_lock_irqsave(&lp->lock, flags);
+
+	lp->hw.copy_from_card(dev, bufnum, 0, buf, 512);
+	if (take_arcnet_lock)
+		spin_unlock_irqrestore(&lp->lock, flags);
+
+	/* if the offset[0] byte is nonzero, this is a 256-byte packet */
+	length = (buf[2] ? 256 : 512);
+
+	/* dump the packet */
+	snprintf(hdr, sizeof(hdr), "%6s:%s packet dump:", dev->name, desc);
+	print_hex_dump(KERN_DEBUG, hdr, DUMP_PREFIX_OFFSET,
+		       16, 1, buf, length, true);
+}
+
+#else
+
+#define arcnet_dump_packet(dev, bufnum, desc, take_arcnet_lock) do { } while (0)
+
+#endif
+
+/* Trigger a LED event in response to a ARCNET device event */
+void arcnet_led_event(struct net_device *dev, enum arcnet_led_event event)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	unsigned long led_delay = 350;
+	unsigned long tx_delay = 50;
+
+	switch (event) {
+	case ARCNET_LED_EVENT_RECON:
+		led_trigger_blink_oneshot(lp->recon_led_trig,
+					  &led_delay, &led_delay, 0);
+		break;
+	case ARCNET_LED_EVENT_OPEN:
+		led_trigger_event(lp->tx_led_trig, LED_OFF);
+		led_trigger_event(lp->recon_led_trig, LED_OFF);
+		break;
+	case ARCNET_LED_EVENT_STOP:
+		led_trigger_event(lp->tx_led_trig, LED_OFF);
+		led_trigger_event(lp->recon_led_trig, LED_OFF);
+		break;
+	case ARCNET_LED_EVENT_TX:
+		led_trigger_blink_oneshot(lp->tx_led_trig,
+					  &tx_delay, &tx_delay, 0);
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(arcnet_led_event);
+
+static void arcnet_led_release(struct device *gendev, void *res)
+{
+	struct arcnet_local *lp = netdev_priv(to_net_dev(gendev));
+
+	led_trigger_unregister_simple(lp->tx_led_trig);
+	led_trigger_unregister_simple(lp->recon_led_trig);
+}
+
+/* Register ARCNET LED triggers for a arcnet device
+ *
+ * This is normally called from a driver's probe function
+ */
+void devm_arcnet_led_init(struct net_device *netdev, int index, int subid)
+{
+	struct arcnet_local *lp = netdev_priv(netdev);
+	void *res;
+
+	res = devres_alloc(arcnet_led_release, 0, GFP_KERNEL);
+	if (!res) {
+		netdev_err(netdev, "cannot register LED triggers\n");
+		return;
+	}
+
+	snprintf(lp->tx_led_trig_name, sizeof(lp->tx_led_trig_name),
+		 "arc%d-%d-tx", index, subid);
+	snprintf(lp->recon_led_trig_name, sizeof(lp->recon_led_trig_name),
+		 "arc%d-%d-recon", index, subid);
+
+	led_trigger_register_simple(lp->tx_led_trig_name,
+				    &lp->tx_led_trig);
+	led_trigger_register_simple(lp->recon_led_trig_name,
+				    &lp->recon_led_trig);
+
+	devres_add(&netdev->dev, res);
+}
+EXPORT_SYMBOL_GPL(devm_arcnet_led_init);
+
+/* Unregister a protocol driver from the arc_proto_map.  Protocol drivers
+ * are responsible for registering themselves, but the unregister routine
+ * is pretty generic so we'll do it here.
+ */
+void arcnet_unregister_proto(struct ArcProto *proto)
+{
+	int count;
+
+	if (arc_proto_default == proto)
+		arc_proto_default = &arc_proto_null;
+	if (arc_bcast_proto == proto)
+		arc_bcast_proto = arc_proto_default;
+	if (arc_raw_proto == proto)
+		arc_raw_proto = arc_proto_default;
+
+	for (count = 0; count < 256; count++) {
+		if (arc_proto_map[count] == proto)
+			arc_proto_map[count] = arc_proto_default;
+	}
+}
+EXPORT_SYMBOL(arcnet_unregister_proto);
+
+/* Add a buffer to the queue.  Only the interrupt handler is allowed to do
+ * this, unless interrupts are disabled.
+ *
+ * Note: we don't check for a full queue, since there aren't enough buffers
+ * to more than fill it.
+ */
+static void release_arcbuf(struct net_device *dev, int bufnum)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	int i;
+
+	lp->buf_queue[lp->first_free_buf++] = bufnum;
+	lp->first_free_buf %= 5;
+
+	if (BUGLVL(D_DURING)) {
+		arc_printk(D_DURING, dev, "release_arcbuf: freed #%d; buffer queue is now: ",
+			   bufnum);
+		for (i = lp->next_buf; i != lp->first_free_buf; i = (i + 1) % 5)
+			arc_cont(D_DURING, "#%d ", lp->buf_queue[i]);
+		arc_cont(D_DURING, "\n");
+	}
+}
+
+/* Get a buffer from the queue.
+ * If this returns -1, there are no buffers available.
+ */
+static int get_arcbuf(struct net_device *dev)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	int buf = -1, i;
+
+	if (!atomic_dec_and_test(&lp->buf_lock)) {
+		/* already in this function */
+		arc_printk(D_NORMAL, dev, "get_arcbuf: overlap (%d)!\n",
+			   lp->buf_lock.counter);
+	} else {			/* we can continue */
+		if (lp->next_buf >= 5)
+			lp->next_buf -= 5;
+
+		if (lp->next_buf == lp->first_free_buf) {
+			arc_printk(D_NORMAL, dev, "get_arcbuf: BUG: no buffers are available??\n");
+		} else {
+			buf = lp->buf_queue[lp->next_buf++];
+			lp->next_buf %= 5;
+		}
+	}
+
+	if (BUGLVL(D_DURING)) {
+		arc_printk(D_DURING, dev, "get_arcbuf: got #%d; buffer queue is now: ",
+			   buf);
+		for (i = lp->next_buf; i != lp->first_free_buf; i = (i + 1) % 5)
+			arc_cont(D_DURING, "#%d ", lp->buf_queue[i]);
+		arc_cont(D_DURING, "\n");
+	}
+
+	atomic_inc(&lp->buf_lock);
+	return buf;
+}
+
+static int choose_mtu(void)
+{
+	int count, mtu = 65535;
+
+	/* choose the smallest MTU of all available encaps */
+	for (count = 0; count < 256; count++) {
+		if (arc_proto_map[count] != &arc_proto_null &&
+		    arc_proto_map[count]->mtu < mtu) {
+			mtu = arc_proto_map[count]->mtu;
+		}
+	}
+
+	return mtu == 65535 ? XMTU : mtu;
+}
+
+static const struct header_ops arcnet_header_ops = {
+	.create = arcnet_header,
+};
+
+static const struct net_device_ops arcnet_netdev_ops = {
+	.ndo_open	= arcnet_open,
+	.ndo_stop	= arcnet_close,
+	.ndo_start_xmit = arcnet_send_packet,
+	.ndo_tx_timeout = arcnet_timeout,
+};
+
+/* Setup a struct device for ARCnet. */
+static void arcdev_setup(struct net_device *dev)
+{
+	dev->type = ARPHRD_ARCNET;
+	dev->netdev_ops = &arcnet_netdev_ops;
+	dev->header_ops = &arcnet_header_ops;
+	dev->hard_header_len = sizeof(struct arc_hardware);
+	dev->mtu = choose_mtu();
+
+	dev->addr_len = ARCNET_ALEN;
+	dev->tx_queue_len = 100;
+	dev->broadcast[0] = 0x00;	/* for us, broadcasts are address 0 */
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	/* New-style flags. */
+	dev->flags = IFF_BROADCAST;
+}
+
+static void arcnet_timer(struct timer_list *t)
+{
+	struct arcnet_local *lp = from_timer(lp, t, timer);
+	struct net_device *dev = lp->dev;
+
+	if (!netif_carrier_ok(dev)) {
+		netif_carrier_on(dev);
+		netdev_info(dev, "link up\n");
+	}
+}
+
+static void arcnet_reply_tasklet(unsigned long data)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)data;
+
+	struct sk_buff *ackskb, *skb;
+	struct sock_exterr_skb *serr;
+	struct sock *sk;
+	int ret;
+
+	local_irq_disable();
+	skb = lp->outgoing.skb;
+	if (!skb || !skb->sk) {
+		local_irq_enable();
+		return;
+	}
+
+	sock_hold(skb->sk);
+	sk = skb->sk;
+	ackskb = skb_clone_sk(skb);
+	sock_put(skb->sk);
+
+	if (!ackskb) {
+		local_irq_enable();
+		return;
+	}
+
+	serr = SKB_EXT_ERR(ackskb);
+	memset(serr, 0, sizeof(*serr));
+	serr->ee.ee_errno = ENOMSG;
+	serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS;
+	serr->ee.ee_data = skb_shinfo(skb)->tskey;
+	serr->ee.ee_info = lp->reply_status;
+
+	/* finally erasing outgoing skb */
+	dev_kfree_skb(lp->outgoing.skb);
+	lp->outgoing.skb = NULL;
+
+	ackskb->dev = lp->dev;
+
+	ret = sock_queue_err_skb(sk, ackskb);
+	if (ret)
+		kfree_skb(ackskb);
+
+	local_irq_enable();
+};
+
+struct net_device *alloc_arcdev(const char *name)
+{
+	struct net_device *dev;
+
+	dev = alloc_netdev(sizeof(struct arcnet_local),
+			   name && *name ? name : "arc%d", NET_NAME_UNKNOWN,
+			   arcdev_setup);
+	if (dev) {
+		struct arcnet_local *lp = netdev_priv(dev);
+
+		lp->dev = dev;
+		spin_lock_init(&lp->lock);
+		timer_setup(&lp->timer, arcnet_timer, 0);
+	}
+
+	return dev;
+}
+EXPORT_SYMBOL(alloc_arcdev);
+
+/* 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.
+ */
+int arcnet_open(struct net_device *dev)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	int count, newmtu, error;
+
+	arc_printk(D_INIT, dev, "opened.");
+
+	if (!try_module_get(lp->hw.owner))
+		return -ENODEV;
+
+	if (BUGLVL(D_PROTO)) {
+		arc_printk(D_PROTO, dev, "protocol map (default is '%c'): ",
+			   arc_proto_default->suffix);
+		for (count = 0; count < 256; count++)
+			arc_cont(D_PROTO, "%c", arc_proto_map[count]->suffix);
+		arc_cont(D_PROTO, "\n");
+	}
+
+	tasklet_init(&lp->reply_tasklet, arcnet_reply_tasklet,
+		     (unsigned long)lp);
+
+	arc_printk(D_INIT, dev, "arcnet_open: resetting card.\n");
+
+	/* try to put the card in a defined state - if it fails the first
+	 * time, actually reset it.
+	 */
+	error = -ENODEV;
+	if (lp->hw.reset(dev, 0) && lp->hw.reset(dev, 1))
+		goto out_module_put;
+
+	newmtu = choose_mtu();
+	if (newmtu < dev->mtu)
+		dev->mtu = newmtu;
+
+	arc_printk(D_INIT, dev, "arcnet_open: mtu: %d.\n", dev->mtu);
+
+	/* autodetect the encapsulation for each host. */
+	memset(lp->default_proto, 0, sizeof(lp->default_proto));
+
+	/* the broadcast address is special - use the 'bcast' protocol */
+	for (count = 0; count < 256; count++) {
+		if (arc_proto_map[count] == arc_bcast_proto) {
+			lp->default_proto[0] = count;
+			break;
+		}
+	}
+
+	/* initialize buffers */
+	atomic_set(&lp->buf_lock, 1);
+
+	lp->next_buf = lp->first_free_buf = 0;
+	release_arcbuf(dev, 0);
+	release_arcbuf(dev, 1);
+	release_arcbuf(dev, 2);
+	release_arcbuf(dev, 3);
+	lp->cur_tx = lp->next_tx = -1;
+	lp->cur_rx = -1;
+
+	lp->rfc1201.sequence = 1;
+
+	/* bring up the hardware driver */
+	if (lp->hw.open)
+		lp->hw.open(dev);
+
+	if (dev->dev_addr[0] == 0)
+		arc_printk(D_NORMAL, dev, "WARNING!  Station address 00 is reserved for broadcasts!\n");
+	else if (dev->dev_addr[0] == 255)
+		arc_printk(D_NORMAL, dev, "WARNING!  Station address FF may confuse DOS networking programs!\n");
+
+	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
+	if (lp->hw.status(dev) & RESETflag) {
+		arc_printk(D_DEBUG, dev, "%s: %d: %s\n",
+			   __FILE__, __LINE__, __func__);
+		lp->hw.command(dev, CFLAGScmd | RESETclear);
+	}
+
+	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
+	/* make sure we're ready to receive IRQ's. */
+	lp->hw.intmask(dev, 0);
+	udelay(1);		/* give it time to set the mask before
+				 * we reset it again. (may not even be
+				 * necessary)
+				 */
+	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
+	lp->intmask = NORXflag | RECONflag;
+	lp->hw.intmask(dev, lp->intmask);
+	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
+
+	netif_carrier_off(dev);
+	netif_start_queue(dev);
+	mod_timer(&lp->timer, jiffies + msecs_to_jiffies(1000));
+
+	arcnet_led_event(dev, ARCNET_LED_EVENT_OPEN);
+	return 0;
+
+ out_module_put:
+	module_put(lp->hw.owner);
+	return error;
+}
+EXPORT_SYMBOL(arcnet_open);
+
+/* The inverse routine to arcnet_open - shuts down the card. */
+int arcnet_close(struct net_device *dev)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+
+	arcnet_led_event(dev, ARCNET_LED_EVENT_STOP);
+	del_timer_sync(&lp->timer);
+
+	netif_stop_queue(dev);
+	netif_carrier_off(dev);
+
+	tasklet_kill(&lp->reply_tasklet);
+
+	/* flush TX and disable RX */
+	lp->hw.intmask(dev, 0);
+	lp->hw.command(dev, NOTXcmd);	/* stop transmit */
+	lp->hw.command(dev, NORXcmd);	/* disable receive */
+	mdelay(1);
+
+	/* shut down the card */
+	lp->hw.close(dev);
+	module_put(lp->hw.owner);
+	return 0;
+}
+EXPORT_SYMBOL(arcnet_close);
+
+static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
+			 unsigned short type, const void *daddr,
+			 const void *saddr, unsigned len)
+{
+	const struct arcnet_local *lp = netdev_priv(dev);
+	uint8_t _daddr, proto_num;
+	struct ArcProto *proto;
+
+	arc_printk(D_DURING, dev,
+		   "create header from %d to %d; protocol %d (%Xh); size %u.\n",
+		   saddr ? *(uint8_t *)saddr : -1,
+		   daddr ? *(uint8_t *)daddr : -1,
+		   type, type, len);
+
+	if (skb->len != 0 && len != skb->len)
+		arc_printk(D_NORMAL, dev, "arcnet_header: Yikes!  skb->len(%d) != len(%d)!\n",
+			   skb->len, len);
+
+	/* Type is host order - ? */
+	if (type == ETH_P_ARCNET) {
+		proto = arc_raw_proto;
+		arc_printk(D_DEBUG, dev, "arc_raw_proto used. proto='%c'\n",
+			   proto->suffix);
+		_daddr = daddr ? *(uint8_t *)daddr : 0;
+	} else if (!daddr) {
+		/* if the dest addr isn't provided, we can't choose an
+		 * encapsulation!  Store the packet type (eg. ETH_P_IP)
+		 * for now, and we'll push on a real header when we do
+		 * rebuild_header.
+		 */
+		*(uint16_t *)skb_push(skb, 2) = type;
+		/* XXX: Why not use skb->mac_len? */
+		if (skb->network_header - skb->mac_header != 2)
+			arc_printk(D_NORMAL, dev, "arcnet_header: Yikes!  diff (%u) is not 2!\n",
+				   skb->network_header - skb->mac_header);
+		return -2;	/* return error -- can't transmit yet! */
+	} else {
+		/* otherwise, we can just add the header as usual. */
+		_daddr = *(uint8_t *)daddr;
+		proto_num = lp->default_proto[_daddr];
+		proto = arc_proto_map[proto_num];
+		arc_printk(D_DURING, dev, "building header for %02Xh using protocol '%c'\n",
+			   proto_num, proto->suffix);
+		if (proto == &arc_proto_null && arc_bcast_proto != proto) {
+			arc_printk(D_DURING, dev, "actually, let's use '%c' instead.\n",
+				   arc_bcast_proto->suffix);
+			proto = arc_bcast_proto;
+		}
+	}
+	return proto->build_header(skb, dev, type, _daddr);
+}
+
+/* Called by the kernel in order to transmit a packet. */
+netdev_tx_t arcnet_send_packet(struct sk_buff *skb,
+			       struct net_device *dev)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct archdr *pkt;
+	struct arc_rfc1201 *soft;
+	struct ArcProto *proto;
+	int txbuf;
+	unsigned long flags;
+	int retval;
+
+	arc_printk(D_DURING, dev,
+		   "transmit requested (status=%Xh, txbufs=%d/%d, len=%d, protocol %x)\n",
+		   lp->hw.status(dev), lp->cur_tx, lp->next_tx, skb->len, skb->protocol);
+
+	pkt = (struct archdr *)skb->data;
+	soft = &pkt->soft.rfc1201;
+	proto = arc_proto_map[soft->proto];
+
+	arc_printk(D_SKB_SIZE, dev, "skb: transmitting %d bytes to %02X\n",
+		   skb->len, pkt->hard.dest);
+	if (BUGLVL(D_SKB))
+		arcnet_dump_skb(dev, skb, "tx");
+
+	/* fits in one packet? */
+	if (skb->len - ARC_HDR_SIZE > XMTU && !proto->continue_tx) {
+		arc_printk(D_NORMAL, dev, "fixme: packet too large: compensating badly!\n");
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;	/* don't try again */
+	}
+
+	/* We're busy transmitting a packet... */
+	netif_stop_queue(dev);
+
+	spin_lock_irqsave(&lp->lock, flags);
+	lp->hw.intmask(dev, 0);
+	if (lp->next_tx == -1)
+		txbuf = get_arcbuf(dev);
+	else
+		txbuf = -1;
+
+	if (txbuf != -1) {
+		lp->outgoing.skb = skb;
+		if (proto->prepare_tx(dev, pkt, skb->len, txbuf) &&
+		    !proto->ack_tx) {
+			/* done right away and we don't want to acknowledge
+			 *  the package later - forget about it now
+			 */
+			dev->stats.tx_bytes += skb->len;
+		} else {
+			/* do it the 'split' way */
+			lp->outgoing.proto = proto;
+			lp->outgoing.skb = skb;
+			lp->outgoing.pkt = pkt;
+
+			if (proto->continue_tx &&
+			    proto->continue_tx(dev, txbuf)) {
+				arc_printk(D_NORMAL, dev,
+					   "bug! continue_tx finished the first time! (proto='%c')\n",
+					   proto->suffix);
+			}
+		}
+		retval = NETDEV_TX_OK;
+		lp->next_tx = txbuf;
+	} else {
+		retval = NETDEV_TX_BUSY;
+	}
+
+	arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x\n",
+		   __FILE__, __LINE__, __func__, lp->hw.status(dev));
+	/* make sure we didn't ignore a TX IRQ while we were in here */
+	lp->hw.intmask(dev, 0);
+
+	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
+	lp->intmask |= TXFREEflag | EXCNAKflag;
+	lp->hw.intmask(dev, lp->intmask);
+	arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x\n",
+		   __FILE__, __LINE__, __func__, lp->hw.status(dev));
+
+	arcnet_led_event(dev, ARCNET_LED_EVENT_TX);
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+	return retval;		/* no need to try again */
+}
+EXPORT_SYMBOL(arcnet_send_packet);
+
+/* Actually start transmitting a packet that was loaded into a buffer
+ * by prepare_tx.  This should _only_ be called by the interrupt handler.
+ */
+static int go_tx(struct net_device *dev)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+
+	arc_printk(D_DURING, dev, "go_tx: status=%Xh, intmask=%Xh, next_tx=%d, cur_tx=%d\n",
+		   lp->hw.status(dev), lp->intmask, lp->next_tx, lp->cur_tx);
+
+	if (lp->cur_tx != -1 || lp->next_tx == -1)
+		return 0;
+
+	if (BUGLVL(D_TX))
+		arcnet_dump_packet(dev, lp->next_tx, "go_tx", 0);
+
+	lp->cur_tx = lp->next_tx;
+	lp->next_tx = -1;
+
+	/* start sending */
+	lp->hw.command(dev, TXcmd | (lp->cur_tx << 3));
+
+	dev->stats.tx_packets++;
+	lp->lasttrans_dest = lp->lastload_dest;
+	lp->lastload_dest = 0;
+	lp->excnak_pending = 0;
+	lp->intmask |= TXFREEflag | EXCNAKflag;
+
+	return 1;
+}
+
+/* Called by the kernel when transmit times out */
+void arcnet_timeout(struct net_device *dev)
+{
+	unsigned long flags;
+	struct arcnet_local *lp = netdev_priv(dev);
+	int status = lp->hw.status(dev);
+	char *msg;
+
+	spin_lock_irqsave(&lp->lock, flags);
+	if (status & TXFREEflag) {	/* transmit _DID_ finish */
+		msg = " - missed IRQ?";
+	} else {
+		msg = "";
+		dev->stats.tx_aborted_errors++;
+		lp->timed_out = 1;
+		lp->hw.command(dev, NOTXcmd | (lp->cur_tx << 3));
+	}
+	dev->stats.tx_errors++;
+
+	/* make sure we didn't miss a TX or a EXC NAK IRQ */
+	lp->hw.intmask(dev, 0);
+	lp->intmask |= TXFREEflag | EXCNAKflag;
+	lp->hw.intmask(dev, lp->intmask);
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	if (time_after(jiffies, lp->last_timeout + 10 * HZ)) {
+		arc_printk(D_EXTRA, dev, "tx timed out%s (status=%Xh, intmask=%Xh, dest=%02Xh)\n",
+			   msg, status, lp->intmask, lp->lasttrans_dest);
+		lp->last_timeout = jiffies;
+	}
+
+	if (lp->cur_tx == -1)
+		netif_wake_queue(dev);
+}
+EXPORT_SYMBOL(arcnet_timeout);
+
+/* The typical workload of the driver: Handle the network interface
+ * interrupts. Establish which device needs attention, and call the correct
+ * chipset interrupt handler.
+ */
+irqreturn_t arcnet_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct arcnet_local *lp;
+	int recbuf, status, diagstatus, didsomething, boguscount;
+	unsigned long flags;
+	int retval = IRQ_NONE;
+
+	arc_printk(D_DURING, dev, "\n");
+
+	arc_printk(D_DURING, dev, "in arcnet_interrupt\n");
+
+	lp = netdev_priv(dev);
+	BUG_ON(!lp);
+
+	spin_lock_irqsave(&lp->lock, flags);
+
+	/* RESET flag was enabled - if device is not running, we must
+	 * clear it right away (but nothing else).
+	 */
+	if (!netif_running(dev)) {
+		if (lp->hw.status(dev) & RESETflag)
+			lp->hw.command(dev, CFLAGScmd | RESETclear);
+		lp->hw.intmask(dev, 0);
+		spin_unlock_irqrestore(&lp->lock, flags);
+		return retval;
+	}
+
+	arc_printk(D_DURING, dev, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
+		   lp->hw.status(dev), lp->intmask);
+
+	boguscount = 5;
+	do {
+		status = lp->hw.status(dev);
+		diagstatus = (status >> 8) & 0xFF;
+
+		arc_printk(D_DEBUG, dev, "%s: %d: %s: status=%x\n",
+			   __FILE__, __LINE__, __func__, status);
+		didsomething = 0;
+
+		/* RESET flag was enabled - card is resetting and if RX is
+		 * disabled, it's NOT because we just got a packet.
+		 *
+		 * The card is in an undefined state.
+		 * Clear it out and start over.
+		 */
+		if (status & RESETflag) {
+			arc_printk(D_NORMAL, dev, "spurious reset (status=%Xh)\n",
+				   status);
+			arcnet_close(dev);
+			arcnet_open(dev);
+
+			/* get out of the interrupt handler! */
+			break;
+		}
+		/* RX is inhibited - we must have received something.
+		 * Prepare to receive into the next buffer.
+		 *
+		 * We don't actually copy the received packet from the card
+		 * until after the transmit handler runs (and possibly
+		 * launches the next tx); this should improve latency slightly
+		 * if we get both types of interrupts at once.
+		 */
+		recbuf = -1;
+		if (status & lp->intmask & NORXflag) {
+			recbuf = lp->cur_rx;
+			arc_printk(D_DURING, dev, "Buffer #%d: receive irq (status=%Xh)\n",
+				   recbuf, status);
+
+			lp->cur_rx = get_arcbuf(dev);
+			if (lp->cur_rx != -1) {
+				arc_printk(D_DURING, dev, "enabling receive to buffer #%d\n",
+					   lp->cur_rx);
+				lp->hw.command(dev, RXcmd | (lp->cur_rx << 3) | RXbcasts);
+			}
+			didsomething++;
+		}
+
+		if ((diagstatus & EXCNAKflag)) {
+			arc_printk(D_DURING, dev, "EXCNAK IRQ (diagstat=%Xh)\n",
+				   diagstatus);
+
+			lp->hw.command(dev, NOTXcmd);      /* disable transmit */
+			lp->excnak_pending = 1;
+
+			lp->hw.command(dev, EXCNAKclear);
+			lp->intmask &= ~(EXCNAKflag);
+			didsomething++;
+		}
+
+		/* a transmit finished, and we're interested in it. */
+		if ((status & lp->intmask & TXFREEflag) || lp->timed_out) {
+			int ackstatus;
+			lp->intmask &= ~(TXFREEflag | EXCNAKflag);
+
+			if (status & TXACKflag)
+				ackstatus = 2;
+			else if (lp->excnak_pending)
+				ackstatus = 1;
+			else
+				ackstatus = 0;
+
+			arc_printk(D_DURING, dev, "TX IRQ (stat=%Xh)\n",
+				   status);
+
+			if (lp->cur_tx != -1 && !lp->timed_out) {
+				if (!(status & TXACKflag)) {
+					if (lp->lasttrans_dest != 0) {
+						arc_printk(D_EXTRA, dev,
+							   "transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n",
+							   status,
+							   lp->lasttrans_dest);
+						dev->stats.tx_errors++;
+						dev->stats.tx_carrier_errors++;
+					} else {
+						arc_printk(D_DURING, dev,
+							   "broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n",
+							   status,
+							   lp->lasttrans_dest);
+					}
+				}
+
+				if (lp->outgoing.proto &&
+				    lp->outgoing.proto->ack_tx) {
+					lp->outgoing.proto
+						->ack_tx(dev, ackstatus);
+				}
+				lp->reply_status = ackstatus;
+				tasklet_hi_schedule(&lp->reply_tasklet);
+			}
+			if (lp->cur_tx != -1)
+				release_arcbuf(dev, lp->cur_tx);
+
+			lp->cur_tx = -1;
+			lp->timed_out = 0;
+			didsomething++;
+
+			/* send another packet if there is one */
+			go_tx(dev);
+
+			/* continue a split packet, if any */
+			if (lp->outgoing.proto &&
+			    lp->outgoing.proto->continue_tx) {
+				int txbuf = get_arcbuf(dev);
+
+				if (txbuf != -1) {
+					if (lp->outgoing.proto->continue_tx(dev, txbuf)) {
+						/* that was the last segment */
+						dev->stats.tx_bytes += lp->outgoing.skb->len;
+						if (!lp->outgoing.proto->ack_tx) {
+							dev_kfree_skb_irq(lp->outgoing.skb);
+							lp->outgoing.proto = NULL;
+						}
+					}
+					lp->next_tx = txbuf;
+				}
+			}
+			/* inform upper layers of idleness, if necessary */
+			if (lp->cur_tx == -1)
+				netif_wake_queue(dev);
+		}
+		/* now process the received packet, if any */
+		if (recbuf != -1) {
+			if (BUGLVL(D_RX))
+				arcnet_dump_packet(dev, recbuf, "rx irq", 0);
+
+			arcnet_rx(dev, recbuf);
+			release_arcbuf(dev, recbuf);
+
+			didsomething++;
+		}
+		if (status & lp->intmask & RECONflag) {
+			lp->hw.command(dev, CFLAGScmd | CONFIGclear);
+			dev->stats.tx_carrier_errors++;
+
+			arc_printk(D_RECON, dev, "Network reconfiguration detected (status=%Xh)\n",
+				   status);
+			if (netif_carrier_ok(dev)) {
+				netif_carrier_off(dev);
+				netdev_info(dev, "link down\n");
+			}
+			mod_timer(&lp->timer, jiffies + msecs_to_jiffies(1000));
+
+			arcnet_led_event(dev, ARCNET_LED_EVENT_RECON);
+			/* MYRECON bit is at bit 7 of diagstatus */
+			if (diagstatus & 0x80)
+				arc_printk(D_RECON, dev, "Put out that recon myself\n");
+
+			/* is the RECON info empty or old? */
+			if (!lp->first_recon || !lp->last_recon ||
+			    time_after(jiffies, lp->last_recon + HZ * 10)) {
+				if (lp->network_down)
+					arc_printk(D_NORMAL, dev, "reconfiguration detected: cabling restored?\n");
+				lp->first_recon = lp->last_recon = jiffies;
+				lp->num_recons = lp->network_down = 0;
+
+				arc_printk(D_DURING, dev, "recon: clearing counters.\n");
+			} else {	/* add to current RECON counter */
+				lp->last_recon = jiffies;
+				lp->num_recons++;
+
+				arc_printk(D_DURING, dev, "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+ 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;
+					arc_printk(D_NORMAL, dev, "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;
+				}
+			}
+		} else if (lp->network_down &&
+			   time_after(jiffies, lp->last_recon + HZ * 10)) {
+			if (lp->network_down)
+				arc_printk(D_NORMAL, dev, "cabling restored?\n");
+			lp->first_recon = lp->last_recon = 0;
+			lp->num_recons = lp->network_down = 0;
+
+			arc_printk(D_DURING, dev, "not recon: clearing counters anyway.\n");
+			netif_carrier_on(dev);
+		}
+
+		if (didsomething)
+			retval |= IRQ_HANDLED;
+	} while (--boguscount && didsomething);
+
+	arc_printk(D_DURING, dev, "arcnet_interrupt complete (status=%Xh, count=%d)\n",
+		   lp->hw.status(dev), boguscount);
+	arc_printk(D_DURING, dev, "\n");
+
+	lp->hw.intmask(dev, 0);
+	udelay(1);
+	lp->hw.intmask(dev, lp->intmask);
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+	return retval;
+}
+EXPORT_SYMBOL(arcnet_interrupt);
+
+/* This is a generic packet receiver that calls arcnet??_rx depending on the
+ * protocol ID found.
+ */
+static void arcnet_rx(struct net_device *dev, int bufnum)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct archdr pkt;
+	struct arc_rfc1201 *soft;
+	int length, ofs;
+
+	soft = &pkt.soft.rfc1201;
+
+	lp->hw.copy_from_card(dev, bufnum, 0, &pkt, ARC_HDR_SIZE);
+	if (pkt.hard.offset[0]) {
+		ofs = pkt.hard.offset[0];
+		length = 256 - ofs;
+	} else {
+		ofs = pkt.hard.offset[1];
+		length = 512 - ofs;
+	}
+
+	/* get the full header, if possible */
+	if (sizeof(pkt.soft) <= length) {
+		lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(pkt.soft));
+	} else {
+		memset(&pkt.soft, 0, sizeof(pkt.soft));
+		lp->hw.copy_from_card(dev, bufnum, ofs, soft, length);
+	}
+
+	arc_printk(D_DURING, dev, "Buffer #%d: received packet from %02Xh to %02Xh (%d+4 bytes)\n",
+		   bufnum, pkt.hard.source, pkt.hard.dest, length);
+
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += length + ARC_HDR_SIZE;
+
+	/* call the right receiver for the protocol */
+	if (arc_proto_map[soft->proto]->is_ip) {
+		if (BUGLVL(D_PROTO)) {
+			struct ArcProto
+			*oldp = arc_proto_map[lp->default_proto[pkt.hard.source]],
+			*newp = arc_proto_map[soft->proto];
+
+			if (oldp != newp) {
+				arc_printk(D_PROTO, dev,
+					   "got protocol %02Xh; encap for host %02Xh is now '%c' (was '%c')\n",
+					   soft->proto, pkt.hard.source,
+					   newp->suffix, oldp->suffix);
+			}
+		}
+
+		/* broadcasts will always be done with the last-used encap. */
+		lp->default_proto[0] = soft->proto;
+
+		/* in striking contrast, the following isn't a hack. */
+		lp->default_proto[pkt.hard.source] = soft->proto;
+	}
+	/* call the protocol-specific receiver. */
+	arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length);
+}
+
+static void null_rx(struct net_device *dev, int bufnum,
+		    struct archdr *pkthdr, int length)
+{
+	arc_printk(D_PROTO, dev,
+		   "rx: don't know how to deal with proto %02Xh from host %02Xh.\n",
+		   pkthdr->soft.rfc1201.proto, pkthdr->hard.source);
+}
+
+static int null_build_header(struct sk_buff *skb, struct net_device *dev,
+			     unsigned short type, uint8_t daddr)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+
+	arc_printk(D_PROTO, dev,
+		   "tx: can't build header for encap %02Xh; load a protocol driver.\n",
+		   lp->default_proto[daddr]);
+
+	/* always fails */
+	return 0;
+}
+
+/* the "do nothing" prepare_tx function warns that there's nothing to do. */
+static int null_prepare_tx(struct net_device *dev, struct archdr *pkt,
+			   int length, int bufnum)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct arc_hardware newpkt;
+
+	arc_printk(D_PROTO, dev, "tx: no encap for this host; load a protocol driver.\n");
+
+	/* send a packet to myself -- will never get received, of course */
+	newpkt.source = newpkt.dest = dev->dev_addr[0];
+
+	/* only one byte of actual data (and it's random) */
+	newpkt.offset[0] = 0xFF;
+
+	lp->hw.copy_to_card(dev, bufnum, 0, &newpkt, ARC_HDR_SIZE);
+
+	return 1;		/* done */
+}
diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c
new file mode 100644
index 0000000..b780be6
--- /dev/null
+++ b/drivers/net/arcnet/capmode.c
@@ -0,0 +1,268 @@
+/*
+ * Linux ARCnet driver - "cap mode" packet encapsulation.
+ * It adds sequence numbers to packets for communicating between a user space
+ * application and the driver. After a transmit it sends a packet with protocol
+ * byte 0 back up to the userspace containing the sequence number of the packet
+ * plus the transmit-status on the ArcNet.
+ *
+ * Written 2002-4 by Esben Nielsen, Vestas Wind Systems A/S
+ * Derived from arc-rawmode.c by Avery Pennarun.
+ * arc-rawmode was in turned based on skeleton.c, see below.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+
+#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <net/arp.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+#include "arcdevice.h"
+
+/* packet receiver */
+static void rx(struct net_device *dev, int bufnum,
+	       struct archdr *pkthdr, int length)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct sk_buff *skb;
+	struct archdr *pkt = pkthdr;
+	char *pktbuf, *pkthdrbuf;
+	int ofs;
+
+	arc_printk(D_DURING, dev, "it's a raw(cap) packet (length=%d)\n",
+		   length);
+
+	if (length >= MinTU)
+		ofs = 512 - length;
+	else
+		ofs = 256 - length;
+
+	skb = alloc_skb(length + ARC_HDR_SIZE + sizeof(int), GFP_ATOMIC);
+	if (!skb) {
+		dev->stats.rx_dropped++;
+		return;
+	}
+	skb_put(skb, length + ARC_HDR_SIZE + sizeof(int));
+	skb->dev = dev;
+	skb_reset_mac_header(skb);
+	pkt = (struct archdr *)skb_mac_header(skb);
+	skb_pull(skb, ARC_HDR_SIZE);
+
+	/* up to sizeof(pkt->soft) has already been copied from the card
+	 * squeeze in an int for the cap encapsulation
+	 * use these variables to be sure we count in bytes, not in
+	 * sizeof(struct archdr)
+	 */
+	pktbuf = (char *)pkt;
+	pkthdrbuf = (char *)pkthdr;
+	memcpy(pktbuf, pkthdrbuf, ARC_HDR_SIZE + sizeof(pkt->soft.cap.proto));
+	memcpy(pktbuf + ARC_HDR_SIZE + sizeof(pkt->soft.cap.proto) + sizeof(int),
+	       pkthdrbuf + ARC_HDR_SIZE + sizeof(pkt->soft.cap.proto),
+	       sizeof(struct archdr) - ARC_HDR_SIZE - sizeof(pkt->soft.cap.proto));
+
+	if (length > sizeof(pkt->soft))
+		lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft),
+				      pkt->soft.raw + sizeof(pkt->soft)
+				      + sizeof(int),
+				      length - sizeof(pkt->soft));
+
+	if (BUGLVL(D_SKB))
+		arcnet_dump_skb(dev, skb, "rx");
+
+	skb->protocol = cpu_to_be16(ETH_P_ARCNET);
+	netif_rx(skb);
+}
+
+/* Create the ARCnet hard/soft headers for cap mode.
+ * There aren't any soft headers in cap mode - not even the protocol id.
+ */
+static int build_header(struct sk_buff *skb,
+			struct net_device *dev,
+			unsigned short type,
+			uint8_t daddr)
+{
+	int hdr_size = ARC_HDR_SIZE;
+	struct archdr *pkt = skb_push(skb, hdr_size);
+
+	arc_printk(D_PROTO, dev, "Preparing header for cap packet %x.\n",
+		   *((int *)&pkt->soft.cap.cookie[0]));
+
+	/* Set the source hardware address.
+	 *
+	 * This is pretty pointless for most purposes, but it can help in
+	 * debugging.  ARCnet does not allow us to change the source address in
+	 * the actual packet sent)
+	 */
+	pkt->hard.source = *dev->dev_addr;
+
+	/* see linux/net/ethernet/eth.c to see where I got the following */
+
+	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
+		/* FIXME: fill in the last byte of the dest ipaddr here to
+		 * better comply with RFC1051 in "noarp" mode.
+		 */
+		pkt->hard.dest = 0;
+		return hdr_size;
+	}
+	/* otherwise, just fill it in and go! */
+	pkt->hard.dest = daddr;
+
+	return hdr_size;	/* success */
+}
+
+static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
+		      int bufnum)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct arc_hardware *hard = &pkt->hard;
+	int ofs;
+
+	/* hard header is not included in packet length */
+	length -= ARC_HDR_SIZE;
+	/* And neither is the cookie field */
+	length -= sizeof(int);
+
+	arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",
+		   lp->next_tx, lp->cur_tx, bufnum);
+
+	arc_printk(D_PROTO, dev, "Sending for cap packet %x.\n",
+		   *((int *)&pkt->soft.cap.cookie[0]));
+
+	if (length > XMTU) {
+		/* should never happen! other people already check for this. */
+		arc_printk(D_NORMAL, dev, "Bug!  prepare_tx with size %d (> %d)\n",
+			   length, XMTU);
+		length = XMTU;
+	}
+	if (length > MinTU) {
+		hard->offset[0] = 0;
+		hard->offset[1] = ofs = 512 - length;
+	} else if (length > MTU) {
+		hard->offset[0] = 0;
+		hard->offset[1] = ofs = 512 - length - 3;
+	} else {
+		hard->offset[0] = ofs = 256 - length;
+	}
+
+	arc_printk(D_DURING, dev, "prepare_tx: length=%d ofs=%d\n",
+		   length, ofs);
+
+	/* Copy the arcnet-header + the protocol byte down: */
+	lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
+	lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft.cap.proto,
+			    sizeof(pkt->soft.cap.proto));
+
+	/* Skip the extra integer we have written into it as a cookie
+	 * but write the rest of the message:
+	 */
+	lp->hw.copy_to_card(dev, bufnum, ofs + 1,
+			    ((unsigned char *)&pkt->soft.cap.mes), length - 1);
+
+	lp->lastload_dest = hard->dest;
+
+	return 1;	/* done */
+}
+
+static int ack_tx(struct net_device *dev, int acked)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct sk_buff *ackskb;
+	struct archdr *ackpkt;
+	int length = sizeof(struct arc_cap);
+
+	arc_printk(D_DURING, dev, "capmode: ack_tx: protocol: %x: result: %d\n",
+		   lp->outgoing.skb->protocol, acked);
+
+	if (BUGLVL(D_SKB))
+		arcnet_dump_skb(dev, lp->outgoing.skb, "ack_tx");
+
+	/* Now alloc a skb to send back up through the layers: */
+	ackskb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
+	if (!ackskb)
+		goto free_outskb;
+
+	skb_put(ackskb, length + ARC_HDR_SIZE);
+	ackskb->dev = dev;
+
+	skb_reset_mac_header(ackskb);
+	ackpkt = (struct archdr *)skb_mac_header(ackskb);
+	/* skb_pull(ackskb, ARC_HDR_SIZE); */
+
+	skb_copy_from_linear_data(lp->outgoing.skb, ackpkt,
+				  ARC_HDR_SIZE + sizeof(struct arc_cap));
+	ackpkt->soft.cap.proto = 0; /* using protocol 0 for acknowledge */
+	ackpkt->soft.cap.mes.ack = acked;
+
+	arc_printk(D_PROTO, dev, "Acknowledge for cap packet %x.\n",
+		   *((int *)&ackpkt->soft.cap.cookie[0]));
+
+	ackskb->protocol = cpu_to_be16(ETH_P_ARCNET);
+
+	if (BUGLVL(D_SKB))
+		arcnet_dump_skb(dev, ackskb, "ack_tx_recv");
+	netif_rx(ackskb);
+
+free_outskb:
+	dev_kfree_skb_irq(lp->outgoing.skb);
+	lp->outgoing.proto = NULL;
+			/* We are always finished when in this protocol */
+
+	return 0;
+}
+
+static struct ArcProto capmode_proto = {
+	.suffix		= 'r',
+	.mtu		= XMTU,
+	.rx		= rx,
+	.build_header	= build_header,
+	.prepare_tx	= prepare_tx,
+	.ack_tx		= ack_tx
+};
+
+static int __init capmode_module_init(void)
+{
+	int count;
+
+	pr_info("cap mode (`c') encapsulation support loaded\n");
+
+	for (count = 1; count <= 8; count++)
+		if (arc_proto_map[count] == arc_proto_default)
+			arc_proto_map[count] = &capmode_proto;
+
+	/* for cap mode, we only set the bcast proto if there's no better one */
+	if (arc_bcast_proto == arc_proto_default)
+		arc_bcast_proto = &capmode_proto;
+
+	arc_proto_default = &capmode_proto;
+	arc_raw_proto = &capmode_proto;
+
+	return 0;
+}
+
+static void __exit capmode_module_exit(void)
+{
+	arcnet_unregister_proto(&capmode_proto);
+}
+module_init(capmode_module_init);
+module_exit(capmode_module_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c
new file mode 100644
index 0000000..38fa60d
--- /dev/null
+++ b/drivers/net/arcnet/com20020-isa.c
@@ -0,0 +1,223 @@
+/*
+ * Linux ARCnet driver - COM20020 chipset support
+ *
+ * Written 1997 by David Woodhouse.
+ * Written 1994-1999 by Avery Pennarun.
+ * Written 1999-2000 by Martin Mares <mj@ucw.cz>.
+ * Derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+
+#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/bootmem.h>
+#include <linux/io.h>
+
+#include "arcdevice.h"
+#include "com20020.h"
+
+/* We cannot (yet) probe for an IO mapped card, although we can check that
+ * it's where we were told it was, and even do autoirq.
+ */
+static int __init com20020isa_probe(struct net_device *dev)
+{
+	int ioaddr;
+	unsigned long airqmask;
+	struct arcnet_local *lp = netdev_priv(dev);
+	int err;
+
+	if (BUGLVL(D_NORMAL))
+		pr_info("%s\n", "COM20020 ISA support (by David Woodhouse et al.)");
+
+	ioaddr = dev->base_addr;
+	if (!ioaddr) {
+		arc_printk(D_NORMAL, dev, "No autoprobe (yet) for IO mapped cards; you must specify the base address!\n");
+		return -ENODEV;
+	}
+	if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)")) {
+		arc_printk(D_NORMAL, dev, "IO region %xh-%xh already allocated.\n",
+			   ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
+		return -ENXIO;
+	}
+	if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
+		arc_printk(D_NORMAL, dev, "IO address %x empty\n", ioaddr);
+		err = -ENODEV;
+		goto out;
+	}
+	if (com20020_check(dev)) {
+		err = -ENODEV;
+		goto out;
+	}
+
+	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.
+		 */
+		arc_printk(D_INIT_REASONS, dev, "intmask was %02Xh\n",
+			   arcnet_inb(ioaddr, COM20020_REG_R_STATUS));
+		arcnet_outb(0, ioaddr, COM20020_REG_W_INTMASK);
+		airqmask = probe_irq_on();
+		arcnet_outb(NORXflag, ioaddr, COM20020_REG_W_INTMASK);
+		udelay(1);
+		arcnet_outb(0, ioaddr, COM20020_REG_W_INTMASK);
+		dev->irq = probe_irq_off(airqmask);
+
+		if ((int)dev->irq <= 0) {
+			arc_printk(D_INIT_REASONS, dev, "Autoprobe IRQ failed first time\n");
+			airqmask = probe_irq_on();
+			arcnet_outb(NORXflag, ioaddr, COM20020_REG_W_INTMASK);
+			udelay(5);
+			arcnet_outb(0, ioaddr, COM20020_REG_W_INTMASK);
+			dev->irq = probe_irq_off(airqmask);
+			if ((int)dev->irq <= 0) {
+				arc_printk(D_NORMAL, dev, "Autoprobe IRQ failed.\n");
+				err = -ENODEV;
+				goto out;
+			}
+		}
+	}
+
+	lp->card_name = "ISA COM20020";
+
+	err = com20020_found(dev, 0);
+	if (err != 0)
+		goto out;
+
+	return 0;
+
+out:
+	release_region(ioaddr, ARCNET_TOTAL_SIZE);
+	return err;
+}
+
+static int node = 0;
+static int io = 0x0;		/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
+static int irq = 0;		/* or use the insmod io= irq= shmem= options */
+static char device[9];		/* use eg. device="arc1" to change name */
+static int timeout = 3;
+static int backplane = 0;
+static int clockp = 0;
+static int clockm = 0;
+
+module_param(node, int, 0);
+module_param_hw(io, int, ioport, 0);
+module_param_hw(irq, int, irq, 0);
+module_param_string(device, device, sizeof(device), 0);
+module_param(timeout, int, 0);
+module_param(backplane, int, 0);
+module_param(clockp, int, 0);
+module_param(clockm, int, 0);
+
+MODULE_LICENSE("GPL");
+
+static struct net_device *my_dev;
+
+static int __init com20020_init(void)
+{
+	struct net_device *dev;
+	struct arcnet_local *lp;
+
+	dev = alloc_arcdev(device);
+	if (!dev)
+		return -ENOMEM;
+
+	if (node && node != 0xff)
+		dev->dev_addr[0] = node;
+
+	dev->netdev_ops = &com20020_netdev_ops;
+
+	lp = netdev_priv(dev);
+	lp->backplane = backplane;
+	lp->clockp = clockp & 7;
+	lp->clockm = clockm & 3;
+	lp->timeout = timeout & 3;
+	lp->hw.owner = THIS_MODULE;
+
+	dev->base_addr = io;
+	dev->irq = irq;
+
+	if (dev->irq == 2)
+		dev->irq = 9;
+
+	if (com20020isa_probe(dev)) {
+		free_netdev(dev);
+		return -EIO;
+	}
+
+	my_dev = dev;
+	return 0;
+}
+
+static void __exit com20020_exit(void)
+{
+	unregister_netdev(my_dev);
+	free_irq(my_dev->irq, my_dev);
+	release_region(my_dev->base_addr, ARCNET_TOTAL_SIZE);
+	free_netdev(my_dev);
+}
+
+#ifndef MODULE
+static int __init com20020isa_setup(char *s)
+{
+	int ints[8];
+
+	s = get_options(s, 8, ints);
+	if (!ints[0])
+		return 1;
+
+	switch (ints[0]) {
+	default:		/* ERROR */
+		pr_info("Too many arguments\n");
+	case 6:		/* Timeout */
+		timeout = ints[6];
+	case 5:		/* CKP value */
+		clockp = ints[5];
+	case 4:		/* Backplane flag */
+		backplane = ints[4];
+	case 3:		/* Node ID */
+		node = ints[3];
+	case 2:		/* IRQ */
+		irq = ints[2];
+	case 1:		/* IO address */
+		io = ints[1];
+	}
+	if (*s)
+		snprintf(device, sizeof(device), "%s", s);
+	return 1;
+}
+
+__setup("com20020=", com20020isa_setup);
+
+#endif				/* MODULE */
+
+module_init(com20020_init)
+module_exit(com20020_exit)
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c
new file mode 100644
index 0000000..eb7f767
--- /dev/null
+++ b/drivers/net/arcnet/com20020-pci.c
@@ -0,0 +1,608 @@
+/*
+ * Linux ARCnet driver - COM20020 PCI support
+ * Contemporary Controls PCI20 and SOHARD SH-ARC PCI
+ *
+ * Written 1994-1999 by Avery Pennarun,
+ *    based on an ISA version by David Woodhouse.
+ * Written 1999-2000 by Martin Mares <mj@ucw.cz>.
+ * Derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+
+#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+
+#include "arcdevice.h"
+#include "com20020.h"
+
+/* Module parameters */
+
+static int node;
+static char device[9];		/* use eg. device="arc1" to change name */
+static int timeout = 3;
+static int backplane;
+static int clockp;
+static int clockm;
+
+module_param(node, int, 0);
+module_param_string(device, device, sizeof(device), 0);
+module_param(timeout, int, 0);
+module_param(backplane, int, 0);
+module_param(clockp, int, 0);
+module_param(clockm, int, 0);
+MODULE_LICENSE("GPL");
+
+static void led_tx_set(struct led_classdev *led_cdev,
+			     enum led_brightness value)
+{
+	struct com20020_dev *card;
+	struct com20020_priv *priv;
+	struct com20020_pci_card_info *ci;
+
+	card = container_of(led_cdev, struct com20020_dev, tx_led);
+
+	priv = card->pci_priv;
+	ci = priv->ci;
+
+	outb(!!value, priv->misc + ci->leds[card->index].green);
+}
+
+static void led_recon_set(struct led_classdev *led_cdev,
+			     enum led_brightness value)
+{
+	struct com20020_dev *card;
+	struct com20020_priv *priv;
+	struct com20020_pci_card_info *ci;
+
+	card = container_of(led_cdev, struct com20020_dev, recon_led);
+
+	priv = card->pci_priv;
+	ci = priv->ci;
+
+	outb(!!value, priv->misc + ci->leds[card->index].red);
+}
+
+static ssize_t backplane_mode_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct net_device *net_dev = to_net_dev(dev);
+	struct arcnet_local *lp = netdev_priv(net_dev);
+
+	return sprintf(buf, "%s\n", lp->backplane ? "true" : "false");
+}
+static DEVICE_ATTR_RO(backplane_mode);
+
+static struct attribute *com20020_state_attrs[] = {
+	&dev_attr_backplane_mode.attr,
+	NULL,
+};
+
+static const struct attribute_group com20020_state_group = {
+	.name = NULL,
+	.attrs = com20020_state_attrs,
+};
+
+static void com20020pci_remove(struct pci_dev *pdev);
+
+static int com20020pci_probe(struct pci_dev *pdev,
+			     const struct pci_device_id *id)
+{
+	struct com20020_pci_card_info *ci;
+	struct com20020_pci_channel_map *mm;
+	struct net_device *dev;
+	struct arcnet_local *lp;
+	struct com20020_priv *priv;
+	int i, ioaddr, ret;
+	struct resource *r;
+
+	if (pci_enable_device(pdev))
+		return -EIO;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	ci = (struct com20020_pci_card_info *)id->driver_data;
+	priv->ci = ci;
+	mm = &ci->misc_map;
+
+	INIT_LIST_HEAD(&priv->list_dev);
+
+	if (mm->size) {
+		ioaddr = pci_resource_start(pdev, mm->bar) + mm->offset;
+		r = devm_request_region(&pdev->dev, ioaddr, mm->size,
+					"com20020-pci");
+		if (!r) {
+			pr_err("IO region %xh-%xh already allocated.\n",
+			       ioaddr, ioaddr + mm->size - 1);
+			return -EBUSY;
+		}
+		priv->misc = ioaddr;
+	}
+
+	for (i = 0; i < ci->devcount; i++) {
+		struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
+		struct com20020_dev *card;
+		int dev_id_mask = 0xf;
+
+		dev = alloc_arcdev(device);
+		if (!dev) {
+			ret = -ENOMEM;
+			goto out_port;
+		}
+		dev->dev_port = i;
+
+		dev->netdev_ops = &com20020_netdev_ops;
+
+		lp = netdev_priv(dev);
+
+		arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name);
+		ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
+
+		r = devm_request_region(&pdev->dev, ioaddr, cm->size,
+					"com20020-pci");
+		if (!r) {
+			pr_err("IO region %xh-%xh already allocated\n",
+			       ioaddr, ioaddr + cm->size - 1);
+			ret = -EBUSY;
+			goto out_port;
+		}
+
+		/* Dummy access after Reset
+		 * ARCNET controller needs
+		 * this access to detect bustype
+		 */
+		arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
+		arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
+
+		SET_NETDEV_DEV(dev, &pdev->dev);
+		dev->base_addr = ioaddr;
+		dev->dev_addr[0] = node;
+		dev->sysfs_groups[0] = &com20020_state_group;
+		dev->irq = pdev->irq;
+		lp->card_name = "PCI COM20020";
+		lp->card_flags = ci->flags;
+		lp->backplane = backplane;
+		lp->clockp = clockp & 7;
+		lp->clockm = clockm & 3;
+		lp->timeout = timeout;
+		lp->hw.owner = THIS_MODULE;
+
+		lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1;
+
+		if (!strncmp(ci->name, "EAE PLX-PCI FB2", 15))
+			lp->backplane = 1;
+
+		/* Get the dev_id from the PLX rotary coder */
+		if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
+			dev_id_mask = 0x3;
+		dev->dev_id = (inb(priv->misc + ci->rotary) >> 4) & dev_id_mask;
+
+		snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i);
+
+		if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
+			pr_err("IO address %Xh is empty!\n", ioaddr);
+			ret = -EIO;
+			goto out_port;
+		}
+		if (com20020_check(dev)) {
+			ret = -EIO;
+			goto out_port;
+		}
+
+		card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
+				    GFP_KERNEL);
+		if (!card) {
+			ret = -ENOMEM;
+			goto out_port;
+		}
+
+		card->index = i;
+		card->pci_priv = priv;
+		card->tx_led.brightness_set = led_tx_set;
+		card->tx_led.default_trigger = devm_kasprintf(&pdev->dev,
+						GFP_KERNEL, "arc%d-%d-tx",
+						dev->dev_id, i);
+		card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+						"pci:green:tx:%d-%d",
+						dev->dev_id, i);
+
+		card->tx_led.dev = &dev->dev;
+		card->recon_led.brightness_set = led_recon_set;
+		card->recon_led.default_trigger = devm_kasprintf(&pdev->dev,
+						GFP_KERNEL, "arc%d-%d-recon",
+						dev->dev_id, i);
+		card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+						"pci:red:recon:%d-%d",
+						dev->dev_id, i);
+		card->recon_led.dev = &dev->dev;
+		card->dev = dev;
+
+		ret = devm_led_classdev_register(&pdev->dev, &card->tx_led);
+		if (ret)
+			goto out_port;
+
+		ret = devm_led_classdev_register(&pdev->dev, &card->recon_led);
+		if (ret)
+			goto out_port;
+
+		dev_set_drvdata(&dev->dev, card);
+
+		ret = com20020_found(dev, IRQF_SHARED);
+		if (ret)
+			goto out_port;
+
+		devm_arcnet_led_init(dev, dev->dev_id, i);
+
+		list_add(&card->list, &priv->list_dev);
+	}
+
+	pci_set_drvdata(pdev, priv);
+
+	return 0;
+
+out_port:
+	com20020pci_remove(pdev);
+	return ret;
+}
+
+static void com20020pci_remove(struct pci_dev *pdev)
+{
+	struct com20020_dev *card, *tmpcard;
+	struct com20020_priv *priv;
+
+	priv = pci_get_drvdata(pdev);
+
+	list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) {
+		struct net_device *dev = card->dev;
+
+		unregister_netdev(dev);
+		free_irq(dev->irq, dev);
+		free_netdev(dev);
+	}
+}
+
+static struct com20020_pci_card_info card_info_10mbit = {
+	.name = "ARC-PCI",
+	.devcount = 1,
+	.chan_map_tbl = {
+		{
+			.bar = 2,
+			.offset = 0x00,
+			.size = 0x08,
+		},
+	},
+	.flags = ARC_CAN_10MBIT,
+};
+
+static struct com20020_pci_card_info card_info_5mbit = {
+	.name = "ARC-PCI",
+	.devcount = 1,
+	.chan_map_tbl = {
+		{
+			.bar = 2,
+			.offset = 0x00,
+			.size = 0x08,
+		},
+	},
+	.flags = ARC_IS_5MBIT,
+};
+
+static struct com20020_pci_card_info card_info_sohard = {
+	.name = "PLX-PCI",
+	.devcount = 1,
+	/* SOHARD needs PCI base addr 4 */
+	.chan_map_tbl = {
+		{
+			.bar = 4,
+			.offset = 0x00,
+			.size = 0x08
+		},
+	},
+	.flags = ARC_CAN_10MBIT,
+};
+
+static struct com20020_pci_card_info card_info_eae_arc1 = {
+	.name = "EAE PLX-PCI ARC1",
+	.devcount = 1,
+	.chan_map_tbl = {
+		{
+			.bar = 2,
+			.offset = 0x00,
+			.size = 0x08,
+		},
+	},
+	.misc_map = {
+		.bar = 2,
+		.offset = 0x10,
+		.size = 0x04,
+	},
+	.leds = {
+		{
+			.green = 0x0,
+			.red = 0x1,
+		},
+	},
+	.rotary = 0x0,
+	.flags = ARC_CAN_10MBIT,
+};
+
+static struct com20020_pci_card_info card_info_eae_ma1 = {
+	.name = "EAE PLX-PCI MA1",
+	.devcount = 2,
+	.chan_map_tbl = {
+		{
+			.bar = 2,
+			.offset = 0x00,
+			.size = 0x08,
+		}, {
+			.bar = 2,
+			.offset = 0x08,
+			.size = 0x08,
+		}
+	},
+	.misc_map = {
+		.bar = 2,
+		.offset = 0x10,
+		.size = 0x04,
+	},
+	.leds = {
+		{
+			.green = 0x0,
+			.red = 0x1,
+		}, {
+			.green = 0x2,
+			.red = 0x3,
+		},
+	},
+	.rotary = 0x0,
+	.flags = ARC_CAN_10MBIT,
+};
+
+static struct com20020_pci_card_info card_info_eae_fb2 = {
+	.name = "EAE PLX-PCI FB2",
+	.devcount = 1,
+	.chan_map_tbl = {
+		{
+			.bar = 2,
+			.offset = 0x00,
+			.size = 0x08,
+		},
+	},
+	.misc_map = {
+		.bar = 2,
+		.offset = 0x10,
+		.size = 0x04,
+	},
+	.leds = {
+		{
+			.green = 0x0,
+			.red = 0x1,
+		},
+	},
+	.rotary = 0x0,
+	.flags = ARC_CAN_10MBIT,
+};
+
+static const struct pci_device_id com20020pci_id_table[] = {
+	{
+		0x1571, 0xa001,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		0,
+	},
+	{
+		0x1571, 0xa002,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		0,
+	},
+	{
+		0x1571, 0xa003,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		0
+	},
+	{
+		0x1571, 0xa004,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		0,
+	},
+	{
+		0x1571, 0xa005,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		0
+	},
+	{
+		0x1571, 0xa006,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		0
+	},
+	{
+		0x1571, 0xa007,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		0
+	},
+	{
+		0x1571, 0xa008,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		0
+	},
+	{
+		0x1571, 0xa009,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_5mbit
+	},
+	{
+		0x1571, 0xa00a,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_5mbit
+	},
+	{
+		0x1571, 0xa00b,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_5mbit
+	},
+	{
+		0x1571, 0xa00c,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_5mbit
+	},
+	{
+		0x1571, 0xa00d,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_5mbit
+	},
+	{
+		0x1571, 0xa00e,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_5mbit
+	},
+	{
+		0x1571, 0xa201,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_10mbit
+	},
+	{
+		0x1571, 0xa202,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_10mbit
+	},
+	{
+		0x1571, 0xa203,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_10mbit
+	},
+	{
+		0x1571, 0xa204,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_10mbit
+	},
+	{
+		0x1571, 0xa205,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_10mbit
+	},
+	{
+		0x1571, 0xa206,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_10mbit
+	},
+	{
+		0x10B5, 0x9030,
+		0x10B5, 0x2978,
+		0, 0,
+		(kernel_ulong_t)&card_info_sohard
+	},
+	{
+		0x10B5, 0x9050,
+		0x10B5, 0x2273,
+		0, 0,
+		(kernel_ulong_t)&card_info_sohard
+	},
+	{
+		0x10B5, 0x9050,
+		0x10B5, 0x3263,
+		0, 0,
+		(kernel_ulong_t)&card_info_eae_arc1
+	},
+	{
+		0x10B5, 0x9050,
+		0x10B5, 0x3292,
+		0, 0,
+		(kernel_ulong_t)&card_info_eae_ma1
+	},
+	{
+		0x10B5, 0x9050,
+		0x10B5, 0x3294,
+		0, 0,
+		(kernel_ulong_t)&card_info_eae_fb2
+	},
+	{
+		0x14BA, 0x6000,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_10mbit
+	},
+	{
+		0x10B5, 0x2200,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&card_info_10mbit
+	},
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, com20020pci_id_table);
+
+static struct pci_driver com20020pci_driver = {
+	.name		= "com20020",
+	.id_table	= com20020pci_id_table,
+	.probe		= com20020pci_probe,
+	.remove		= com20020pci_remove,
+};
+
+static int __init com20020pci_init(void)
+{
+	if (BUGLVL(D_NORMAL))
+		pr_info("%s\n", "COM20020 PCI support");
+	return pci_register_driver(&com20020pci_driver);
+}
+
+static void __exit com20020pci_cleanup(void)
+{
+	pci_unregister_driver(&com20020pci_driver);
+}
+
+module_init(com20020pci_init)
+module_exit(com20020pci_cleanup)
diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c
new file mode 100644
index 0000000..78043a9
--- /dev/null
+++ b/drivers/net/arcnet/com20020.c
@@ -0,0 +1,418 @@
+/*
+ * Linux ARCnet driver - COM20020 chipset support
+ *
+ * Written 1997 by David Woodhouse.
+ * Written 1994-1999 by Avery Pennarun.
+ * Written 1999 by Martin Mares <mj@ucw.cz>.
+ * Derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+
+#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include "arcdevice.h"
+#include "com20020.h"
+
+static const char * const clockrates[] = {
+	"XXXXXXX", "XXXXXXXX", "XXXXXX", "2.5 Mb/s",
+	"1.25Mb/s", "625 Kb/s", "312.5 Kb/s", "156.25 Kb/s",
+	"Reserved", "Reserved", "Reserved"
+};
+
+static void com20020_command(struct net_device *dev, int command);
+static int com20020_status(struct net_device *dev);
+static void com20020_setmask(struct net_device *dev, int mask);
+static int com20020_reset(struct net_device *dev, int really_reset);
+static void com20020_copy_to_card(struct net_device *dev, int bufnum,
+				  int offset, void *buf, int count);
+static void com20020_copy_from_card(struct net_device *dev, int bufnum,
+				    int offset, void *buf, int count);
+static void com20020_set_mc_list(struct net_device *dev);
+static void com20020_close(struct net_device *);
+
+static void com20020_copy_from_card(struct net_device *dev, int bufnum,
+				    int offset, void *buf, int count)
+{
+	int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset;
+
+	/* set up the address register */
+	arcnet_outb((ofs >> 8) | RDDATAflag | AUTOINCflag,
+		    ioaddr, COM20020_REG_W_ADDR_HI);
+	arcnet_outb(ofs & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
+
+	/* copy the data */
+	TIME(dev, "insb", count,
+	     arcnet_insb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count));
+}
+
+static void com20020_copy_to_card(struct net_device *dev, int bufnum,
+				  int offset, void *buf, int count)
+{
+	int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset;
+
+	/* set up the address register */
+	arcnet_outb((ofs >> 8) | AUTOINCflag, ioaddr, COM20020_REG_W_ADDR_HI);
+	arcnet_outb(ofs & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
+
+	/* copy the data */
+	TIME(dev, "outsb", count,
+	     arcnet_outsb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count));
+}
+
+/* Reset the card and check some basic stuff during the detection stage. */
+int com20020_check(struct net_device *dev)
+{
+	int ioaddr = dev->base_addr, status;
+	struct arcnet_local *lp = netdev_priv(dev);
+
+	arcnet_outb(XTOcfg(3) | RESETcfg, ioaddr, COM20020_REG_W_CONFIG);
+	udelay(5);
+	arcnet_outb(XTOcfg(3), ioaddr, COM20020_REG_W_CONFIG);
+	mdelay(RESETtime);
+
+	lp->setup = lp->clockm ? 0 : (lp->clockp << 1);
+	lp->setup2 = (lp->clockm << 4) | 8;
+
+	/* CHECK: should we do this for SOHARD cards ? */
+	/* Enable P1Mode for backplane mode */
+	lp->setup = lp->setup | P1MODE;
+
+	com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
+	arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
+
+	if (lp->clockm != 0) {
+		com20020_set_subaddress(lp, ioaddr, SUB_SETUP2);
+		arcnet_outb(lp->setup2, ioaddr, COM20020_REG_W_XREG);
+
+		/* must now write the magic "restart operation" command */
+		mdelay(1);
+		arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND);
+	}
+
+	lp->config = (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE;
+	/* set node ID to 0x42 (but transmitter is disabled, so it's okay) */
+	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
+	arcnet_outb(0x42, ioaddr, COM20020_REG_W_XREG);
+
+	status = arcnet_inb(ioaddr, COM20020_REG_R_STATUS);
+
+	if ((status & 0x99) != (NORXflag | TXFREEflag | RESETflag)) {
+		arc_printk(D_NORMAL, dev, "status invalid (%Xh).\n", status);
+		return -ENODEV;
+	}
+	arc_printk(D_INIT_REASONS, dev, "status after reset: %X\n", status);
+
+	arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
+		    ioaddr, COM20020_REG_W_COMMAND);
+	status = arcnet_inb(ioaddr, COM20020_REG_R_STATUS);
+	arc_printk(D_INIT_REASONS, dev, "status after reset acknowledged: %X\n",
+		   status);
+
+	/* Read first location of memory */
+	arcnet_outb(0 | RDDATAflag | AUTOINCflag,
+		    ioaddr, COM20020_REG_W_ADDR_HI);
+	arcnet_outb(0, ioaddr, COM20020_REG_W_ADDR_LO);
+
+	status = arcnet_inb(ioaddr, COM20020_REG_RW_MEMDATA);
+	if (status != TESTvalue) {
+		arc_printk(D_NORMAL, dev, "Signature byte not found (%02Xh != D1h).\n",
+			   status);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int com20020_set_hwaddr(struct net_device *dev, void *addr)
+{
+	int ioaddr = dev->base_addr;
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct sockaddr *hwaddr = addr;
+
+	memcpy(dev->dev_addr, hwaddr->sa_data, 1);
+	com20020_set_subaddress(lp, ioaddr, SUB_NODE);
+	arcnet_outb(dev->dev_addr[0], ioaddr, COM20020_REG_W_XREG);
+
+	return 0;
+}
+
+static int com20020_netdev_open(struct net_device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct arcnet_local *lp = netdev_priv(dev);
+
+	lp->config |= TXENcfg;
+	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
+
+	return arcnet_open(dev);
+}
+
+static int com20020_netdev_close(struct net_device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct arcnet_local *lp = netdev_priv(dev);
+
+	arcnet_close(dev);
+
+	/* disable transmitter */
+	lp->config &= ~TXENcfg;
+	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
+	return 0;
+}
+
+const struct net_device_ops com20020_netdev_ops = {
+	.ndo_open	= com20020_netdev_open,
+	.ndo_stop	= com20020_netdev_close,
+	.ndo_start_xmit = arcnet_send_packet,
+	.ndo_tx_timeout = arcnet_timeout,
+	.ndo_set_mac_address = com20020_set_hwaddr,
+	.ndo_set_rx_mode = com20020_set_mc_list,
+};
+
+/* Set up the struct net_device associated with this card.  Called after
+ * probing succeeds.
+ */
+int com20020_found(struct net_device *dev, int shared)
+{
+	struct arcnet_local *lp;
+	int ioaddr = dev->base_addr;
+
+	/* Initialize the rest of the device structure. */
+
+	lp = netdev_priv(dev);
+
+	lp->hw.owner = THIS_MODULE;
+	lp->hw.command = com20020_command;
+	lp->hw.status = com20020_status;
+	lp->hw.intmask = com20020_setmask;
+	lp->hw.reset = com20020_reset;
+	lp->hw.copy_to_card = com20020_copy_to_card;
+	lp->hw.copy_from_card = com20020_copy_from_card;
+	lp->hw.close = com20020_close;
+
+	/* FIXME: do this some other way! */
+	if (!dev->dev_addr[0])
+		dev->dev_addr[0] = arcnet_inb(ioaddr, 8);
+
+	com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
+	arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
+
+	if (lp->card_flags & ARC_CAN_10MBIT) {
+		com20020_set_subaddress(lp, ioaddr, SUB_SETUP2);
+		arcnet_outb(lp->setup2, ioaddr, COM20020_REG_W_XREG);
+
+		/* must now write the magic "restart operation" command */
+		mdelay(1);
+		arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND);
+	}
+
+	lp->config = (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE;
+	/* Default 0x38 + register: Node ID */
+	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
+	arcnet_outb(dev->dev_addr[0], ioaddr, COM20020_REG_W_XREG);
+
+	/* reserve the irq */
+	if (request_irq(dev->irq, arcnet_interrupt, shared,
+			"arcnet (COM20020)", dev)) {
+		arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", dev->irq);
+		return -ENODEV;
+	}
+
+	arc_printk(D_NORMAL, dev, "%s: station %02Xh found at %03lXh, IRQ %d.\n",
+		   lp->card_name, dev->dev_addr[0], dev->base_addr, dev->irq);
+
+	if (lp->backplane)
+		arc_printk(D_NORMAL, dev, "Using backplane mode.\n");
+
+	if (lp->timeout != 3)
+		arc_printk(D_NORMAL, dev, "Using extended timeout value of %d\n",
+			   lp->timeout);
+
+	arc_printk(D_NORMAL, dev, "Using CKP %d - data rate %s\n",
+		   lp->setup >> 1,
+		   clockrates[3 -
+			      ((lp->setup2 & 0xF0) >> 4) +
+			      ((lp->setup & 0x0F) >> 1)]);
+			/* The clockrates array index looks very fragile.
+			 * It seems like it could have negative indexing.
+			 */
+
+	if (register_netdev(dev)) {
+		free_irq(dev->irq, dev);
+		return -EIO;
+	}
+	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.
+ */
+static int com20020_reset(struct net_device *dev, int really_reset)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	u_int ioaddr = dev->base_addr;
+	u_char inbyte;
+
+	arc_printk(D_DEBUG, dev, "%s: %d: %s: dev: %p, lp: %p, dev->name: %s\n",
+		   __FILE__, __LINE__, __func__, dev, lp, dev->name);
+	arc_printk(D_INIT, dev, "Resetting %s (status=%02Xh)\n",
+		   dev->name, arcnet_inb(ioaddr, COM20020_REG_R_STATUS));
+
+	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
+	lp->config |= (lp->timeout << 3) | (lp->backplane << 2);
+	/* power-up defaults */
+	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
+	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
+
+	if (really_reset) {
+		/* reset the card */
+		arcnet_outb(lp->config | RESETcfg, ioaddr, COM20020_REG_W_CONFIG);
+		udelay(5);
+		arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
+		mdelay(RESETtime * 2);
+				/* COM20020 seems to be slower sometimes */
+	}
+	/* clear flags & end reset */
+	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
+	arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
+		    ioaddr, COM20020_REG_W_COMMAND);
+
+	/* verify that the ARCnet signature byte is present */
+	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
+
+	com20020_copy_from_card(dev, 0, 0, &inbyte, 1);
+	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
+	if (inbyte != TESTvalue) {
+		arc_printk(D_DEBUG, dev, "%s: %d: %s\n",
+			   __FILE__, __LINE__, __func__);
+		arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n");
+		return 1;
+	}
+	/* enable extended (512-byte) packets */
+	arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM20020_REG_W_COMMAND);
+
+	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
+
+	/* done!  return success. */
+	return 0;
+}
+
+static void com20020_setmask(struct net_device *dev, int mask)
+{
+	u_int ioaddr = dev->base_addr;
+
+	arc_printk(D_DURING, dev, "Setting mask to %x at %x\n", mask, ioaddr);
+	arcnet_outb(mask, ioaddr, COM20020_REG_W_INTMASK);
+}
+
+static void com20020_command(struct net_device *dev, int cmd)
+{
+	u_int ioaddr = dev->base_addr;
+
+	arcnet_outb(cmd, ioaddr, COM20020_REG_W_COMMAND);
+}
+
+static int com20020_status(struct net_device *dev)
+{
+	u_int ioaddr = dev->base_addr;
+
+	return arcnet_inb(ioaddr, COM20020_REG_R_STATUS) +
+		(arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT) << 8);
+}
+
+static void com20020_close(struct net_device *dev)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	int ioaddr = dev->base_addr;
+
+	/* disable transmitter */
+	lp->config &= ~TXENcfg;
+	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
+}
+
+/* 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.
+ *      FIXME - do multicast stuff, not just promiscuous.
+ */
+static void com20020_set_mc_list(struct net_device *dev)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	int ioaddr = dev->base_addr;
+
+	if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) {
+		/* Enable promiscuous mode */
+		if (!(lp->setup & PROMISCset))
+			arc_printk(D_NORMAL, dev, "Setting promiscuous flag...\n");
+		com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
+		lp->setup |= PROMISCset;
+		arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
+	} else {
+		/* Disable promiscuous mode, use normal mode */
+		if ((lp->setup & PROMISCset))
+			arc_printk(D_NORMAL, dev, "Resetting promiscuous flag...\n");
+		com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
+		lp->setup &= ~PROMISCset;
+		arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
+	}
+}
+
+#if defined(CONFIG_ARCNET_COM20020_PCI_MODULE) || \
+    defined(CONFIG_ARCNET_COM20020_ISA_MODULE) || \
+    defined(CONFIG_ARCNET_COM20020_CS_MODULE)
+EXPORT_SYMBOL(com20020_check);
+EXPORT_SYMBOL(com20020_found);
+EXPORT_SYMBOL(com20020_netdev_ops);
+#endif
+
+MODULE_LICENSE("GPL");
+
+#ifdef MODULE
+
+static int __init com20020_module_init(void)
+{
+	if (BUGLVL(D_NORMAL))
+		pr_info("%s\n", "COM20020 chipset support (by David Woodhouse et al.)");
+	return 0;
+}
+
+static void __exit com20020_module_exit(void)
+{
+}
+module_init(com20020_module_init);
+module_exit(com20020_module_exit);
+#endif				/* MODULE */
diff --git a/drivers/net/arcnet/com20020.h b/drivers/net/arcnet/com20020.h
new file mode 100644
index 0000000..0bcc5d0
--- /dev/null
+++ b/drivers/net/arcnet/com20020.h
@@ -0,0 +1,132 @@
+/*
+ * Linux ARCnet driver - COM20020 chipset support - function declarations
+ *
+ * Written 1997 by David Woodhouse.
+ * Written 1994-1999 by Avery Pennarun.
+ * Derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+#ifndef __COM20020_H
+#define __COM20020_H
+#include <linux/leds.h>
+
+int com20020_check(struct net_device *dev);
+int com20020_found(struct net_device *dev, int shared);
+extern const struct net_device_ops com20020_netdev_ops;
+
+/* The number of low I/O ports used by the card. */
+#define ARCNET_TOTAL_SIZE 8
+
+#define PLX_PCI_MAX_CARDS 2
+
+struct ledoffsets {
+	int green;
+	int red;
+};
+
+struct com20020_pci_channel_map {
+	u32 bar;
+	u32 offset;
+	u32 size;               /* 0x00 - auto, e.g. length of entire bar */
+};
+
+struct com20020_pci_card_info {
+	const char *name;
+	int devcount;
+
+	struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS];
+	struct com20020_pci_channel_map misc_map;
+
+	struct ledoffsets leds[PLX_PCI_MAX_CARDS];
+	int rotary;
+
+	unsigned int flags;
+};
+
+struct com20020_priv {
+	struct com20020_pci_card_info *ci;
+	struct list_head list_dev;
+	resource_size_t misc;
+};
+
+struct com20020_dev {
+	struct list_head list;
+	struct net_device *dev;
+
+	struct led_classdev tx_led;
+	struct led_classdev recon_led;
+
+	struct com20020_priv *pci_priv;
+	int index;
+};
+
+#define COM20020_REG_W_INTMASK	0	/* writable */
+#define COM20020_REG_R_STATUS	0	/* readable */
+#define COM20020_REG_W_COMMAND	1	/* standard arcnet commands */
+#define COM20020_REG_R_DIAGSTAT	1	/* diagnostic status */
+#define COM20020_REG_W_ADDR_HI	2	/* control for IO-mapped memory */
+#define COM20020_REG_W_ADDR_LO	3
+#define COM20020_REG_RW_MEMDATA	4	/* data port for IO-mapped memory */
+#define COM20020_REG_W_SUBADR	5	/* the extended port _XREG refers to */
+#define COM20020_REG_W_CONFIG	6	/* configuration */
+#define COM20020_REG_W_XREG	7	/* extra
+					 * (indexed by _CONFIG or _SUBADDR)
+					 */
+
+/* in the ADDR_HI register */
+#define RDDATAflag	0x80	/* next access is a read (not a write) */
+
+/* in the DIAGSTAT register */
+#define NEWNXTIDflag	0x02	/* ID to which token is passed has changed */
+
+/* in the CONFIG register */
+#define RESETcfg	0x80	/* put card in reset state */
+#define TXENcfg		0x20	/* enable TX */
+#define XTOcfg(x)	((x) << 3)	/* extended timeout */
+
+/* in SETUP register */
+#define PROMISCset	0x10	/* enable RCV_ALL */
+#define P1MODE		0x80    /* enable P1-MODE for Backplane */
+#define SLOWARB		0x01    /* enable Slow Arbitration for >=5Mbps */
+
+/* COM2002x */
+#define SUB_TENTATIVE	0	/* tentative node ID */
+#define SUB_NODE	1	/* node ID */
+#define SUB_SETUP1	2	/* various options */
+#define SUB_TEST	3	/* test/diag register */
+
+/* COM20022 only */
+#define SUB_SETUP2	4	/* sundry options */
+#define SUB_BUSCTL	5	/* bus control options */
+#define SUB_DMACOUNT	6	/* DMA count options */
+
+static inline void com20020_set_subaddress(struct arcnet_local *lp,
+					   int ioaddr, int val)
+{
+	if (val < 4) {
+		lp->config = (lp->config & ~0x03) | val;
+		arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
+	} else {
+		arcnet_outb(val, ioaddr, COM20020_REG_W_SUBADR);
+	}
+}
+
+#endif /* __COM20020_H */
diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c
new file mode 100644
index 0000000..cf607ff
--- /dev/null
+++ b/drivers/net/arcnet/com20020_cs.c
@@ -0,0 +1,322 @@
+/*
+ * Linux ARCnet driver - COM20020 PCMCIA support
+ *
+ * Written 1994-1999 by Avery Pennarun,
+ *    based on an ISA version by David Woodhouse.
+ * Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4)
+ *    which was derived from pcnet_cs.c by David Hinds.
+ * Some additional portions derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ * Changes:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
+ * - reorganize kmallocs in com20020_attach, checking all for failure
+ *   and releasing the previous allocations if one fails
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+
+#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/io.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include "arcdevice.h"
+#include "com20020.h"
+
+static void regdump(struct net_device *dev)
+{
+#ifdef DEBUG
+	int ioaddr = dev->base_addr;
+	int count;
+
+	netdev_dbg(dev, "register dump:\n");
+	for (count = 0; count < 16; count++) {
+		if (!(count % 16))
+			pr_cont("%04X:", ioaddr + count);
+		pr_cont(" %02X", arcnet_inb(ioaddr, count));
+	}
+	pr_cont("\n");
+
+	netdev_dbg(dev, "buffer0 dump:\n");
+	/* set up the address register */
+	count = 0;
+	arcnet_outb((count >> 8) | RDDATAflag | AUTOINCflag,
+		    ioaddr, com20020_REG_W_ADDR_HI);
+	arcnet_outb(count & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
+
+	for (count = 0; count < 256 + 32; count++) {
+		if (!(count % 16))
+			pr_cont("%04X:", count);
+
+		/* copy the data */
+		pr_cont(" %02X", arcnet_inb(ioaddr, COM20020_REG_RW_MEMDATA));
+	}
+	pr_cont("\n");
+#endif
+}
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+static int node;
+static int timeout = 3;
+static int backplane;
+static int clockp;
+static int clockm;
+
+module_param(node, int, 0);
+module_param(timeout, int, 0);
+module_param(backplane, int, 0);
+module_param(clockp, int, 0);
+module_param(clockm, int, 0);
+
+MODULE_LICENSE("GPL");
+
+/*====================================================================*/
+
+static int com20020_config(struct pcmcia_device *link);
+static void com20020_release(struct pcmcia_device *link);
+
+static void com20020_detach(struct pcmcia_device *p_dev);
+
+/*====================================================================*/
+
+static int com20020_probe(struct pcmcia_device *p_dev)
+{
+	struct com20020_dev *info;
+	struct net_device *dev;
+	struct arcnet_local *lp;
+
+	dev_dbg(&p_dev->dev, "com20020_attach()\n");
+
+	/* Create new network device */
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		goto fail_alloc_info;
+
+	dev = alloc_arcdev("");
+	if (!dev)
+		goto fail_alloc_dev;
+
+	lp = netdev_priv(dev);
+	lp->timeout = timeout;
+	lp->backplane = backplane;
+	lp->clockp = clockp;
+	lp->clockm = clockm & 3;
+	lp->hw.owner = THIS_MODULE;
+
+	/* fill in our module parameters as defaults */
+	dev->dev_addr[0] = node;
+
+	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+	p_dev->resource[0]->end = 16;
+	p_dev->config_flags |= CONF_ENABLE_IRQ;
+
+	info->dev = dev;
+	p_dev->priv = info;
+
+	return com20020_config(p_dev);
+
+fail_alloc_dev:
+	kfree(info);
+fail_alloc_info:
+	return -ENOMEM;
+} /* com20020_attach */
+
+static void com20020_detach(struct pcmcia_device *link)
+{
+	struct com20020_dev *info = link->priv;
+	struct net_device *dev = info->dev;
+
+	dev_dbg(&link->dev, "detach...\n");
+
+	dev_dbg(&link->dev, "com20020_detach\n");
+
+	dev_dbg(&link->dev, "unregister...\n");
+
+	unregister_netdev(dev);
+
+	/* this is necessary because we register our IRQ separately
+	 * from card services.
+	 */
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+
+	com20020_release(link);
+
+	/* Unlink device structure, free bits */
+	dev_dbg(&link->dev, "unlinking...\n");
+	if (link->priv) {
+		dev = info->dev;
+		if (dev) {
+			dev_dbg(&link->dev, "kfree...\n");
+			free_netdev(dev);
+		}
+		dev_dbg(&link->dev, "kfree2...\n");
+		kfree(info);
+	}
+
+} /* com20020_detach */
+
+static int com20020_config(struct pcmcia_device *link)
+{
+	struct arcnet_local *lp;
+	struct com20020_dev *info;
+	struct net_device *dev;
+	int i, ret;
+	int ioaddr;
+
+	info = link->priv;
+	dev = info->dev;
+
+	dev_dbg(&link->dev, "config...\n");
+
+	dev_dbg(&link->dev, "com20020_config\n");
+
+	dev_dbg(&link->dev, "baseport1 is %Xh\n",
+		(unsigned int)link->resource[0]->start);
+
+	i = -ENODEV;
+	link->io_lines = 16;
+
+	if (!link->resource[0]->start) {
+		for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) {
+			link->resource[0]->start = ioaddr;
+			i = pcmcia_request_io(link);
+			if (i == 0)
+				break;
+		}
+	} else {
+		i = pcmcia_request_io(link);
+	}
+
+	if (i != 0) {
+		dev_dbg(&link->dev, "requestIO failed totally!\n");
+		goto failed;
+	}
+
+	ioaddr = dev->base_addr = link->resource[0]->start;
+	dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
+
+	dev_dbg(&link->dev, "request IRQ %d\n",
+		link->irq);
+	if (!link->irq) {
+		dev_dbg(&link->dev, "requestIRQ failed totally!\n");
+		goto failed;
+	}
+
+	dev->irq = link->irq;
+
+	ret = pcmcia_enable_device(link);
+	if (ret)
+		goto failed;
+
+	if (com20020_check(dev)) {
+		regdump(dev);
+		goto failed;
+	}
+
+	lp = netdev_priv(dev);
+	lp->card_name = "PCMCIA COM20020";
+	lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
+
+	SET_NETDEV_DEV(dev, &link->dev);
+
+	i = com20020_found(dev, 0);	/* calls register_netdev */
+
+	if (i != 0) {
+		dev_notice(&link->dev,
+			   "com20020_found() failed\n");
+		goto failed;
+	}
+
+	netdev_dbg(dev, "port %#3lx, irq %d\n",
+		   dev->base_addr, dev->irq);
+	return 0;
+
+failed:
+	dev_dbg(&link->dev, "com20020_config failed...\n");
+	com20020_release(link);
+	return -ENODEV;
+} /* com20020_config */
+
+static void com20020_release(struct pcmcia_device *link)
+{
+	dev_dbg(&link->dev, "com20020_release\n");
+	pcmcia_disable_device(link);
+}
+
+static int com20020_suspend(struct pcmcia_device *link)
+{
+	struct com20020_dev *info = link->priv;
+	struct net_device *dev = info->dev;
+
+	if (link->open)
+		netif_device_detach(dev);
+
+	return 0;
+}
+
+static int com20020_resume(struct pcmcia_device *link)
+{
+	struct com20020_dev *info = link->priv;
+	struct net_device *dev = info->dev;
+
+	if (link->open) {
+		int ioaddr = dev->base_addr;
+		struct arcnet_local *lp = netdev_priv(dev);
+
+		arcnet_outb(lp->config | 0x80, ioaddr, COM20020_REG_W_CONFIG);
+		udelay(5);
+		arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
+	}
+
+	return 0;
+}
+
+static const struct pcmcia_device_id com20020_ids[] = {
+	PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
+				"PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
+	PCMCIA_DEVICE_PROD_ID12("SoHard AG",
+				"SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
+	PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
+
+static struct pcmcia_driver com20020_cs_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "com20020_cs",
+	.probe		= com20020_probe,
+	.remove		= com20020_detach,
+	.id_table	= com20020_ids,
+	.suspend	= com20020_suspend,
+	.resume		= com20020_resume,
+};
+module_pcmcia_driver(com20020_cs_driver);
diff --git a/drivers/net/arcnet/com9026.h b/drivers/net/arcnet/com9026.h
new file mode 100644
index 0000000..6adbc18
--- /dev/null
+++ b/drivers/net/arcnet/com9026.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __COM9026_H
+#define __COM9026_H
+
+/* COM 9026 controller chip --> ARCnet register addresses */
+
+#define COM9026_REG_W_INTMASK	0	/* writable */
+#define COM9026_REG_R_STATUS	0	/* readable */
+#define COM9026_REG_W_COMMAND	1	/* writable, returns random vals on read (?) */
+#define COM9026_REG_RW_CONFIG	2	/* Configuration register */
+#define COM9026_REG_R_RESET	8	/* software reset (on read) */
+#define COM9026_REG_RW_MEMDATA	12	/* Data port for IO-mapped memory */
+#define COM9026_REG_W_ADDR_LO	14	/* Control registers for said */
+#define COM9026_REG_W_ADDR_HI	15
+
+#define COM9026_REG_R_STATION	1	/* Station ID */
+
+#endif
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
new file mode 100644
index 0000000..4e56aaf
--- /dev/null
+++ b/drivers/net/arcnet/com90io.c
@@ -0,0 +1,424 @@
+/*
+ * Linux ARCnet driver - COM90xx chipset (IO-mapped buffers)
+ *
+ * Written 1997 by David Woodhouse.
+ * Written 1994-1999 by Avery Pennarun.
+ * Written 1999-2000 by Martin Mares <mj@ucw.cz>.
+ * Derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+
+#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/bootmem.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include "arcdevice.h"
+#include "com9026.h"
+
+/* Internal function declarations */
+
+static int com90io_found(struct net_device *dev);
+static void com90io_command(struct net_device *dev, int command);
+static int com90io_status(struct net_device *dev);
+static void com90io_setmask(struct net_device *dev, int mask);
+static int com90io_reset(struct net_device *dev, int really_reset);
+static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset,
+				 void *buf, int count);
+static void com90io_copy_from_card(struct net_device *dev, int bufnum,
+				   int offset, void *buf, int count);
+
+/* Handy defines for ARCnet specific stuff */
+
+/* The number of low I/O ports used by the card. */
+#define ARCNET_TOTAL_SIZE 16
+
+/****************************************************************************
+ *                                                                          *
+ * IO-mapped operation routines                                             *
+ *                                                                          *
+ ****************************************************************************/
+
+#undef ONE_AT_A_TIME_TX
+#undef ONE_AT_A_TIME_RX
+
+static u_char get_buffer_byte(struct net_device *dev, unsigned offset)
+{
+	int ioaddr = dev->base_addr;
+
+	arcnet_outb(offset >> 8, ioaddr, COM9026_REG_W_ADDR_HI);
+	arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO);
+
+	return arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA);
+}
+
+#ifdef ONE_AT_A_TIME_TX
+static void put_buffer_byte(struct net_device *dev, unsigned offset,
+			    u_char datum)
+{
+	int ioaddr = dev->base_addr;
+
+	arcnet_outb(offset >> 8, ioaddr, COM9026_REG_W_ADDR_HI);
+	arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO);
+
+	arcnet_outb(datum, ioaddr, COM9026_REG_RW_MEMDATA);
+}
+
+#endif
+
+static void get_whole_buffer(struct net_device *dev, unsigned offset,
+			     unsigned length, char *dest)
+{
+	int ioaddr = dev->base_addr;
+
+	arcnet_outb((offset >> 8) | AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI);
+	arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO);
+
+	while (length--)
+#ifdef ONE_AT_A_TIME_RX
+		*(dest++) = get_buffer_byte(dev, offset++);
+#else
+		*(dest++) = arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA);
+#endif
+}
+
+static void put_whole_buffer(struct net_device *dev, unsigned offset,
+			     unsigned length, char *dest)
+{
+	int ioaddr = dev->base_addr;
+
+	arcnet_outb((offset >> 8) | AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI);
+	arcnet_outb(offset & 0xff, ioaddr,COM9026_REG_W_ADDR_LO);
+
+	while (length--)
+#ifdef ONE_AT_A_TIME_TX
+		put_buffer_byte(dev, offset++, *(dest++));
+#else
+		arcnet_outb(*(dest++), ioaddr, COM9026_REG_RW_MEMDATA);
+#endif
+}
+
+/* We cannot probe for an IO mapped card either, although we can check that
+ * it's where we were told it was, and even autoirq
+ */
+static int __init com90io_probe(struct net_device *dev)
+{
+	int ioaddr = dev->base_addr, status;
+	unsigned long airqmask;
+
+	if (BUGLVL(D_NORMAL)) {
+		pr_info("%s\n", "COM90xx IO-mapped mode support (by David Woodhouse et el.)");
+		pr_info("E-mail me if you actually test this driver, please!\n");
+	}
+
+	if (!ioaddr) {
+		arc_printk(D_NORMAL, dev, "No autoprobe for IO mapped cards; you must specify the base address!\n");
+		return -ENODEV;
+	}
+	if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com90io probe")) {
+		arc_printk(D_INIT_REASONS, dev, "IO request_region %x-%x failed\n",
+			   ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
+		return -ENXIO;
+	}
+	if (arcnet_inb(ioaddr, COM9026_REG_R_STATUS) == 0xFF) {
+		arc_printk(D_INIT_REASONS, dev, "IO address %x empty\n",
+			   ioaddr);
+		goto err_out;
+	}
+	arcnet_inb(ioaddr, COM9026_REG_R_RESET);
+	mdelay(RESETtime);
+
+	status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
+
+	if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
+		arc_printk(D_INIT_REASONS, dev, "Status invalid (%Xh)\n",
+			   status);
+		goto err_out;
+	}
+	arc_printk(D_INIT_REASONS, dev, "Status after reset: %X\n", status);
+
+	arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
+		    ioaddr, COM9026_REG_W_COMMAND);
+
+	arc_printk(D_INIT_REASONS, dev, "Status after reset acknowledged: %X\n",
+		   status);
+
+	status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
+
+	if (status & RESETflag) {
+		arc_printk(D_INIT_REASONS, dev, "Eternal reset (status=%Xh)\n",
+			   status);
+		goto err_out;
+	}
+	arcnet_outb((0x16 | IOMAPflag) & ~ENABLE16flag,
+		    ioaddr, COM9026_REG_RW_CONFIG);
+
+	/* Read first loc'n of memory */
+
+	arcnet_outb(AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI);
+	arcnet_outb(0, ioaddr,  COM9026_REG_W_ADDR_LO);
+
+	status = arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA);
+	if (status != 0xd1) {
+		arc_printk(D_INIT_REASONS, dev, "Signature byte not found (%Xh instead).\n",
+			   status);
+		goto err_out;
+	}
+	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();
+		arcnet_outb(NORXflag, ioaddr, COM9026_REG_W_INTMASK);
+		udelay(1);
+		arcnet_outb(0, ioaddr, COM9026_REG_W_INTMASK);
+		dev->irq = probe_irq_off(airqmask);
+
+		if ((int)dev->irq <= 0) {
+			arc_printk(D_INIT_REASONS, dev, "Autoprobe IRQ failed\n");
+			goto err_out;
+		}
+	}
+	release_region(ioaddr, ARCNET_TOTAL_SIZE); /* end of probing */
+	return com90io_found(dev);
+
+err_out:
+	release_region(ioaddr, ARCNET_TOTAL_SIZE);
+	return -ENODEV;
+}
+
+/* Set up the struct net_device associated with this card.  Called after
+ * probing succeeds.
+ */
+static int __init com90io_found(struct net_device *dev)
+{
+	struct arcnet_local *lp;
+	int ioaddr = dev->base_addr;
+	int err;
+
+	/* Reserve the irq */
+	if (request_irq(dev->irq, arcnet_interrupt, 0,
+			"arcnet (COM90xx-IO)", dev)) {
+		arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", dev->irq);
+		return -ENODEV;
+	}
+	/* Reserve the I/O region */
+	if (!request_region(dev->base_addr, ARCNET_TOTAL_SIZE,
+			    "arcnet (COM90xx-IO)")) {
+		free_irq(dev->irq, dev);
+		return -EBUSY;
+	}
+
+	lp = netdev_priv(dev);
+	lp->card_name = "COM90xx I/O";
+	lp->hw.command = com90io_command;
+	lp->hw.status = com90io_status;
+	lp->hw.intmask = com90io_setmask;
+	lp->hw.reset = com90io_reset;
+	lp->hw.owner = THIS_MODULE;
+	lp->hw.copy_to_card = com90io_copy_to_card;
+	lp->hw.copy_from_card = com90io_copy_from_card;
+
+	lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag;
+	arcnet_outb(lp->config, ioaddr, COM9026_REG_RW_CONFIG);
+
+	/* get and check the station ID from offset 1 in shmem */
+
+	dev->dev_addr[0] = get_buffer_byte(dev, 1);
+
+	err = register_netdev(dev);
+	if (err) {
+		arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) & ~IOMAPflag,
+			    ioaddr, COM9026_REG_RW_CONFIG);
+		free_irq(dev->irq, dev);
+		release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
+		return err;
+	}
+
+	arc_printk(D_NORMAL, dev, "COM90IO: station %02Xh found at %03lXh, IRQ %d.\n",
+		   dev->dev_addr[0], dev->base_addr, dev->irq);
+
+	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.
+ */
+static int com90io_reset(struct net_device *dev, int really_reset)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	short ioaddr = dev->base_addr;
+
+	arc_printk(D_INIT, dev, "Resetting %s (status=%02Xh)\n",
+		   dev->name, arcnet_inb(ioaddr, COM9026_REG_R_STATUS));
+
+	if (really_reset) {
+		/* reset the card */
+		arcnet_inb(ioaddr, COM9026_REG_R_RESET);
+		mdelay(RESETtime);
+	}
+	/* Set the thing to IO-mapped, 8-bit  mode */
+	lp->config = (0x1C | IOMAPflag) & ~ENABLE16flag;
+	arcnet_outb(lp->config, ioaddr, COM9026_REG_RW_CONFIG);
+
+	arcnet_outb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND);
+					/* clear flags & end reset */
+	arcnet_outb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND);
+
+	/* verify that the ARCnet signature byte is present */
+	if (get_buffer_byte(dev, 0) != TESTvalue) {
+		arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n");
+		return 1;
+	}
+	/* enable extended (512-byte) packets */
+	arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND);
+	/* done!  return success. */
+	return 0;
+}
+
+static void com90io_command(struct net_device *dev, int cmd)
+{
+	short ioaddr = dev->base_addr;
+
+	arcnet_outb(cmd, ioaddr, COM9026_REG_W_COMMAND);
+}
+
+static int com90io_status(struct net_device *dev)
+{
+	short ioaddr = dev->base_addr;
+
+	return arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
+}
+
+static void com90io_setmask(struct net_device *dev, int mask)
+{
+	short ioaddr = dev->base_addr;
+
+	arcnet_outb(mask, ioaddr, COM9026_REG_W_INTMASK);
+}
+
+static void com90io_copy_to_card(struct net_device *dev, int bufnum,
+				 int offset, void *buf, int count)
+{
+	TIME(dev, "put_whole_buffer", count,
+	     put_whole_buffer(dev, bufnum * 512 + offset, count, buf));
+}
+
+static void com90io_copy_from_card(struct net_device *dev, int bufnum,
+				   int offset, void *buf, int count)
+{
+	TIME(dev, "get_whole_buffer", count,
+	     get_whole_buffer(dev, bufnum * 512 + offset, count, buf));
+}
+
+static int io;			/* use the insmod io= irq= shmem= options */
+static int irq;
+static char device[9];		/* use eg. device=arc1 to change name */
+
+module_param_hw(io, int, ioport, 0);
+module_param_hw(irq, int, irq, 0);
+module_param_string(device, device, sizeof(device), 0);
+MODULE_LICENSE("GPL");
+
+#ifndef MODULE
+static int __init com90io_setup(char *s)
+{
+	int ints[4];
+
+	s = get_options(s, 4, ints);
+	if (!ints[0])
+		return 0;
+	switch (ints[0]) {
+	default:		/* ERROR */
+		pr_err("Too many arguments\n");
+	case 2:		/* IRQ */
+		irq = ints[2];
+	case 1:		/* IO address */
+		io = ints[1];
+	}
+	if (*s)
+		snprintf(device, sizeof(device), "%s", s);
+	return 1;
+}
+__setup("com90io=", com90io_setup);
+#endif
+
+static struct net_device *my_dev;
+
+static int __init com90io_init(void)
+{
+	struct net_device *dev;
+	int err;
+
+	dev = alloc_arcdev(device);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->base_addr = io;
+	dev->irq = irq;
+	if (dev->irq == 2)
+		dev->irq = 9;
+
+	err = com90io_probe(dev);
+
+	if (err) {
+		free_netdev(dev);
+		return err;
+	}
+
+	my_dev = dev;
+	return 0;
+}
+
+static void __exit com90io_exit(void)
+{
+	struct net_device *dev = my_dev;
+	int ioaddr = dev->base_addr;
+
+	unregister_netdev(dev);
+
+	/* In case the old driver is loaded later,
+	 * set the thing back to MMAP mode
+	 */
+	arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) & ~IOMAPflag,
+		    ioaddr, COM9026_REG_RW_CONFIG);
+
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
+	free_netdev(dev);
+}
+
+module_init(com90io_init)
+module_exit(com90io_exit)
diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c
new file mode 100644
index 0000000..ca4a57c
--- /dev/null
+++ b/drivers/net/arcnet/com90xx.c
@@ -0,0 +1,711 @@
+/*
+ * Linux ARCnet driver - COM90xx chipset (memory-mapped buffers)
+ *
+ * Written 1994-1999 by Avery Pennarun.
+ * Written 1999 by Martin Mares <mj@ucw.cz>.
+ * Derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+
+#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include "arcdevice.h"
+#include "com9026.h"
+
+/* 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
+
+/* Internal function declarations */
+static int com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *);
+static void com90xx_command(struct net_device *dev, int command);
+static int com90xx_status(struct net_device *dev);
+static void com90xx_setmask(struct net_device *dev, int mask);
+static int com90xx_reset(struct net_device *dev, int really_reset);
+static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset,
+				 void *buf, int count);
+static void com90xx_copy_from_card(struct net_device *dev, int bufnum,
+				   int offset, void *buf, int count);
+
+/* Known ARCnet cards */
+
+static struct net_device *cards[16];
+static int numcards;
+
+/* Handy defines for ARCnet specific stuff */
+
+/* The number of low I/O ports used by the card */
+#define ARCNET_TOTAL_SIZE	16
+
+/* Amount of I/O memory used by the card */
+#define BUFFER_SIZE (512)
+#define MIRROR_SIZE (BUFFER_SIZE * 4)
+
+static int com90xx_skip_probe __initdata = 0;
+
+/* Module parameters */
+
+static int io;			/* use the insmod io= irq= shmem= options */
+static int irq;
+static int shmem;
+static char device[9];		/* use eg. device=arc1 to change name */
+
+module_param_hw(io, int, ioport, 0);
+module_param_hw(irq, int, irq, 0);
+module_param(shmem, int, 0);
+module_param_string(device, device, sizeof(device), 0);
+
+static void __init com90xx_probe(void)
+{
+	int count, status, ioaddr, numprint, airq, openparen = 0;
+	unsigned long airqmask;
+	int ports[(0x3f0 - 0x200) / 16 + 1] = {	0 };
+	unsigned long *shmems;
+	void __iomem **iomem;
+	int numports, numshmems, *port;
+	u_long *p;
+	int index;
+
+	if (!io && !irq && !shmem && !*device && com90xx_skip_probe)
+		return;
+
+	shmems = kzalloc(((0x100000 - 0xa0000) / 0x800) * sizeof(unsigned long),
+			 GFP_KERNEL);
+	if (!shmems)
+		return;
+	iomem = kzalloc(((0x100000 - 0xa0000) / 0x800) * sizeof(void __iomem *),
+			GFP_KERNEL);
+	if (!iomem) {
+		kfree(shmems);
+		return;
+	}
+
+	if (BUGLVL(D_NORMAL))
+		pr_info("%s\n", "COM90xx chipset support");
+
+	/* set up the arrays where we'll store the possible probe addresses */
+	numports = numshmems = 0;
+	if (io)
+		ports[numports++] = io;
+	else
+		for (count = 0x200; count <= 0x3f0; count += 16)
+			ports[numports++] = count;
+	if (shmem)
+		shmems[numshmems++] = shmem;
+	else
+		for (count = 0xA0000; count <= 0xFF800; count += 2048)
+			shmems[numshmems++] = count;
+
+	/* Stage 1: abandon any reserved ports, or ones with status==0xFF
+	 * (empty), and reset any others by reading the reset port.
+	 */
+	numprint = -1;
+	for (port = &ports[0]; port - ports < numports; port++) {
+		numprint++;
+		numprint %= 8;
+		if (!numprint) {
+			arc_cont(D_INIT, "\n");
+			arc_cont(D_INIT, "S1: ");
+		}
+		arc_cont(D_INIT, "%Xh ", *port);
+
+		ioaddr = *port;
+
+		if (!request_region(*port, ARCNET_TOTAL_SIZE,
+				    "arcnet (90xx)")) {
+			arc_cont(D_INIT_REASONS, "(request_region)\n");
+			arc_cont(D_INIT_REASONS, "S1: ");
+			if (BUGLVL(D_INIT_REASONS))
+				numprint = 0;
+			*port-- = ports[--numports];
+			continue;
+		}
+		if (arcnet_inb(ioaddr, COM9026_REG_R_STATUS) == 0xFF) {
+			arc_cont(D_INIT_REASONS, "(empty)\n");
+			arc_cont(D_INIT_REASONS, "S1: ");
+			if (BUGLVL(D_INIT_REASONS))
+				numprint = 0;
+			release_region(*port, ARCNET_TOTAL_SIZE);
+			*port-- = ports[--numports];
+			continue;
+		}
+		/* begin resetting card */
+		arcnet_inb(ioaddr, COM9026_REG_R_RESET);
+
+		arc_cont(D_INIT_REASONS, "\n");
+		arc_cont(D_INIT_REASONS, "S1: ");
+		if (BUGLVL(D_INIT_REASONS))
+			numprint = 0;
+	}
+	arc_cont(D_INIT, "\n");
+
+	if (!numports) {
+		arc_cont(D_NORMAL, "S1: No ARCnet cards found.\n");
+		kfree(shmems);
+		kfree(iomem);
+		return;
+	}
+	/* 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.
+	 */
+	numprint = -1;
+	for (port = &ports[0]; port < ports + numports; port++) {
+		numprint++;
+		numprint %= 8;
+		if (!numprint) {
+			arc_cont(D_INIT, "\n");
+			arc_cont(D_INIT, "S2: ");
+		}
+		arc_cont(D_INIT, "%Xh ", *port);
+	}
+	arc_cont(D_INIT, "\n");
+	mdelay(RESETtime);
+
+	/* Stage 3: abandon any shmem addresses that don't have the signature
+	 * 0xD1 byte in the right place, or are read-only.
+	 */
+	numprint = -1;
+	for (index = 0, p = &shmems[0]; index < numshmems; p++, index++) {
+		void __iomem *base;
+
+		numprint++;
+		numprint %= 8;
+		if (!numprint) {
+			arc_cont(D_INIT, "\n");
+			arc_cont(D_INIT, "S3: ");
+		}
+		arc_cont(D_INIT, "%lXh ", *p);
+
+		if (!request_mem_region(*p, MIRROR_SIZE, "arcnet (90xx)")) {
+			arc_cont(D_INIT_REASONS, "(request_mem_region)\n");
+			arc_cont(D_INIT_REASONS, "Stage 3: ");
+			if (BUGLVL(D_INIT_REASONS))
+				numprint = 0;
+			goto out;
+		}
+		base = ioremap(*p, MIRROR_SIZE);
+		if (!base) {
+			arc_cont(D_INIT_REASONS, "(ioremap)\n");
+			arc_cont(D_INIT_REASONS, "Stage 3: ");
+			if (BUGLVL(D_INIT_REASONS))
+				numprint = 0;
+			goto out1;
+		}
+		if (arcnet_readb(base, COM9026_REG_R_STATUS) != TESTvalue) {
+			arc_cont(D_INIT_REASONS, "(%02Xh != %02Xh)\n",
+				 arcnet_readb(base, COM9026_REG_R_STATUS),
+				 TESTvalue);
+			arc_cont(D_INIT_REASONS, "S3: ");
+			if (BUGLVL(D_INIT_REASONS))
+				numprint = 0;
+			goto out2;
+		}
+		/* 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.
+		 */
+		arcnet_writeb(0x42, base, COM9026_REG_W_INTMASK);
+		if (arcnet_readb(base, COM9026_REG_R_STATUS) != 0x42) {
+			arc_cont(D_INIT_REASONS, "(read only)\n");
+			arc_cont(D_INIT_REASONS, "S3: ");
+			goto out2;
+		}
+		arc_cont(D_INIT_REASONS, "\n");
+		arc_cont(D_INIT_REASONS, "S3: ");
+		if (BUGLVL(D_INIT_REASONS))
+			numprint = 0;
+		iomem[index] = base;
+		continue;
+	out2:
+		iounmap(base);
+	out1:
+		release_mem_region(*p, MIRROR_SIZE);
+	out:
+		*p-- = shmems[--numshmems];
+		index--;
+	}
+	arc_cont(D_INIT, "\n");
+
+	if (!numshmems) {
+		arc_cont(D_NORMAL, "S3: No ARCnet cards found.\n");
+		for (port = &ports[0]; port < ports + numports; port++)
+			release_region(*port, ARCNET_TOTAL_SIZE);
+		kfree(shmems);
+		kfree(iomem);
+		return;
+	}
+	/* Stage 4: something of a dummy, to report the shmems that are
+	 * still possible after stage 3.
+	 */
+	numprint = -1;
+	for (p = &shmems[0]; p < shmems + numshmems; p++) {
+		numprint++;
+		numprint %= 8;
+		if (!numprint) {
+			arc_cont(D_INIT, "\n");
+			arc_cont(D_INIT, "S4: ");
+		}
+		arc_cont(D_INIT, "%lXh ", *p);
+	}
+	arc_cont(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.
+	 */
+	numprint = -1;
+	for (port = &ports[0]; port < ports + numports; port++) {
+		int found = 0;
+
+		numprint++;
+		numprint %= 8;
+		if (!numprint) {
+			arc_cont(D_INIT, "\n");
+			arc_cont(D_INIT, "S5: ");
+		}
+		arc_cont(D_INIT, "%Xh ", *port);
+
+		ioaddr = *port;
+		status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
+
+		if ((status & 0x9D)
+		    != (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
+			arc_cont(D_INIT_REASONS, "(status=%Xh)\n", status);
+			arc_cont(D_INIT_REASONS, "S5: ");
+			if (BUGLVL(D_INIT_REASONS))
+				numprint = 0;
+			release_region(*port, ARCNET_TOTAL_SIZE);
+			*port-- = ports[--numports];
+			continue;
+		}
+		arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
+			    ioaddr, COM9026_REG_W_COMMAND);
+		status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
+		if (status & RESETflag) {
+			arc_cont(D_INIT_REASONS, " (eternal reset, status=%Xh)\n",
+				 status);
+			arc_cont(D_INIT_REASONS, "S5: ");
+			if (BUGLVL(D_INIT_REASONS))
+				numprint = 0;
+			release_region(*port, ARCNET_TOTAL_SIZE);
+			*port-- = ports[--numports];
+			continue;
+		}
+		/* skip this completely if an IRQ was given, because maybe
+		 * we're on a machine that locks during autoirq!
+		 */
+		if (!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();
+			arcnet_outb(NORXflag, ioaddr, COM9026_REG_W_INTMASK);
+			udelay(1);
+			arcnet_outb(0, ioaddr, COM9026_REG_W_INTMASK);
+			airq = probe_irq_off(airqmask);
+
+			if (airq <= 0) {
+				arc_cont(D_INIT_REASONS, "(airq=%d)\n", airq);
+				arc_cont(D_INIT_REASONS, "S5: ");
+				if (BUGLVL(D_INIT_REASONS))
+					numprint = 0;
+				release_region(*port, ARCNET_TOTAL_SIZE);
+				*port-- = ports[--numports];
+				continue;
+			}
+		} else {
+			airq = irq;
+		}
+
+		arc_cont(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) {
+			arcnet_inb(ioaddr, COM9026_REG_R_RESET);
+			mdelay(RESETtime);
+		} else {
+			/* just one shmem and port, assume they match */
+			arcnet_writeb(TESTvalue, iomem[0],
+				      COM9026_REG_W_INTMASK);
+		}
+#else
+		arcnet_inb(ioaddr, COM9026_REG_R_RESET);
+		mdelay(RESETtime);
+#endif
+
+		for (index = 0; index < numshmems; index++) {
+			u_long ptr = shmems[index];
+			void __iomem *base = iomem[index];
+
+			if (arcnet_readb(base, COM9026_REG_R_STATUS) == TESTvalue) {	/* found one */
+				arc_cont(D_INIT, "%lXh)\n", *p);
+				openparen = 0;
+
+				/* register the card */
+				if (com90xx_found(*port, airq, ptr, base) == 0)
+					found = 1;
+				numprint = -1;
+
+				/* remove shmem from the list */
+				shmems[index] = shmems[--numshmems];
+				iomem[index] = iomem[numshmems];
+				break;	/* go to the next I/O port */
+			} else {
+				arc_cont(D_INIT_REASONS, "%Xh-",
+					 arcnet_readb(base, COM9026_REG_R_STATUS));
+			}
+		}
+
+		if (openparen) {
+			if (BUGLVL(D_INIT))
+				pr_cont("no matching shmem)\n");
+			if (BUGLVL(D_INIT_REASONS)) {
+				pr_cont("S5: ");
+				numprint = 0;
+			}
+		}
+		if (!found)
+			release_region(*port, ARCNET_TOTAL_SIZE);
+		*port-- = ports[--numports];
+	}
+
+	if (BUGLVL(D_INIT_REASONS))
+		pr_cont("\n");
+
+	/* Now put back TESTvalue on all leftover shmems. */
+	for (index = 0; index < numshmems; index++) {
+		arcnet_writeb(TESTvalue, iomem[index], COM9026_REG_W_INTMASK);
+		iounmap(iomem[index]);
+		release_mem_region(shmems[index], MIRROR_SIZE);
+	}
+	kfree(shmems);
+	kfree(iomem);
+}
+
+static int __init check_mirror(unsigned long addr, size_t size)
+{
+	void __iomem *p;
+	int res = -1;
+
+	if (!request_mem_region(addr, size, "arcnet (90xx)"))
+		return -1;
+
+	p = ioremap(addr, size);
+	if (p) {
+		if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue)
+			res = 1;
+		else
+			res = 0;
+		iounmap(p);
+	}
+
+	release_mem_region(addr, size);
+	return res;
+}
+
+/* Set up the struct net_device associated with this card.  Called after
+ * probing succeeds.
+ */
+static int __init com90xx_found(int ioaddr, int airq, u_long shmem,
+				void __iomem *p)
+{
+	struct net_device *dev = NULL;
+	struct arcnet_local *lp;
+	u_long first_mirror, last_mirror;
+	int mirror_size;
+
+	/* allocate struct net_device */
+	dev = alloc_arcdev(device);
+	if (!dev) {
+		arc_cont(D_NORMAL, "com90xx: Can't allocate device!\n");
+		iounmap(p);
+		release_mem_region(shmem, MIRROR_SIZE);
+		return -ENOMEM;
+	}
+	lp = netdev_priv(dev);
+	/* find the real shared memory start/end points, including mirrors */
+
+	/* 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 (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue &&
+	    check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 &&
+	    check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1)
+		mirror_size = 2 * MIRROR_SIZE;
+
+	first_mirror = shmem - mirror_size;
+	while (check_mirror(first_mirror, mirror_size) == 1)
+		first_mirror -= mirror_size;
+	first_mirror += mirror_size;
+
+	last_mirror = shmem + mirror_size;
+	while (check_mirror(last_mirror, mirror_size) == 1)
+		last_mirror += mirror_size;
+	last_mirror -= mirror_size;
+
+	dev->mem_start = first_mirror;
+	dev->mem_end = last_mirror + MIRROR_SIZE - 1;
+
+	iounmap(p);
+	release_mem_region(shmem, MIRROR_SIZE);
+
+	if (!request_mem_region(dev->mem_start,
+				dev->mem_end - dev->mem_start + 1,
+				"arcnet (90xx)"))
+		goto err_free_dev;
+
+	/* reserve the irq */
+	if (request_irq(airq, arcnet_interrupt, 0, "arcnet (90xx)", dev)) {
+		arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", airq);
+		goto err_release_mem;
+	}
+	dev->irq = airq;
+
+	/* Initialize the rest of the device structure. */
+	lp->card_name = "COM90xx";
+	lp->hw.command = com90xx_command;
+	lp->hw.status = com90xx_status;
+	lp->hw.intmask = com90xx_setmask;
+	lp->hw.reset = com90xx_reset;
+	lp->hw.owner = THIS_MODULE;
+	lp->hw.copy_to_card = com90xx_copy_to_card;
+	lp->hw.copy_from_card = com90xx_copy_from_card;
+	lp->mem_start = ioremap(dev->mem_start,
+				dev->mem_end - dev->mem_start + 1);
+	if (!lp->mem_start) {
+		arc_printk(D_NORMAL, dev, "Can't remap device memory!\n");
+		goto err_free_irq;
+	}
+
+	/* get and check the station ID from offset 1 in shmem */
+	dev->dev_addr[0] = arcnet_readb(lp->mem_start, COM9026_REG_R_STATION);
+
+	dev->base_addr = ioaddr;
+
+	arc_printk(D_NORMAL, dev, "COM90xx station %02Xh found at %03lXh, IRQ %d, ShMem %lXh (%ld*%xh).\n",
+		   dev->dev_addr[0],
+		   dev->base_addr, dev->irq, dev->mem_start,
+		   (dev->mem_end - dev->mem_start + 1) / mirror_size,
+		   mirror_size);
+
+	if (register_netdev(dev))
+		goto err_unmap;
+
+	cards[numcards++] = dev;
+	return 0;
+
+err_unmap:
+	iounmap(lp->mem_start);
+err_free_irq:
+	free_irq(dev->irq, dev);
+err_release_mem:
+	release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
+err_free_dev:
+	free_netdev(dev);
+	return -EIO;
+}
+
+static void com90xx_command(struct net_device *dev, int cmd)
+{
+	short ioaddr = dev->base_addr;
+
+	arcnet_outb(cmd, ioaddr, COM9026_REG_W_COMMAND);
+}
+
+static int com90xx_status(struct net_device *dev)
+{
+	short ioaddr = dev->base_addr;
+
+	return arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
+}
+
+static void com90xx_setmask(struct net_device *dev, int mask)
+{
+	short ioaddr = dev->base_addr;
+
+	arcnet_outb(mask, ioaddr, COM9026_REG_W_INTMASK);
+}
+
+/* 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.
+ */
+static int com90xx_reset(struct net_device *dev, int really_reset)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	short ioaddr = dev->base_addr;
+
+	arc_printk(D_INIT, dev, "Resetting (status=%02Xh)\n",
+		   arcnet_inb(ioaddr, COM9026_REG_R_STATUS));
+
+	if (really_reset) {
+		/* reset the card */
+		arcnet_inb(ioaddr, COM9026_REG_R_RESET);
+		mdelay(RESETtime);
+	}
+	/* clear flags & end reset */
+	arcnet_outb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND);
+	arcnet_outb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND);
+
+#if 0
+	/* don't do this until we verify that it doesn't hurt older cards! */
+	arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) | ENABLE16flag,
+		    ioaddr, COM9026_REG_RW_CONFIG);
+#endif
+
+	/* verify that the ARCnet signature byte is present */
+	if (arcnet_readb(lp->mem_start, COM9026_REG_R_STATUS) != TESTvalue) {
+		if (really_reset)
+			arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n");
+		return 1;
+	}
+	/* enable extended (512-byte) packets */
+	arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND);
+
+	/* clean out all the memory to make debugging make more sense :) */
+	if (BUGLVL(D_DURING))
+		memset_io(lp->mem_start, 0x42, 2048);
+
+	/* done!  return success. */
+	return 0;
+}
+
+static void com90xx_copy_to_card(struct net_device *dev, int bufnum,
+				 int offset, void *buf, int count)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
+
+	TIME(dev, "memcpy_toio", count, memcpy_toio(memaddr, buf, count));
+}
+
+static void com90xx_copy_from_card(struct net_device *dev, int bufnum,
+				   int offset, void *buf, int count)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
+
+	TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
+}
+
+MODULE_LICENSE("GPL");
+
+static int __init com90xx_init(void)
+{
+	if (irq == 2)
+		irq = 9;
+	com90xx_probe();
+	if (!numcards)
+		return -EIO;
+	return 0;
+}
+
+static void __exit com90xx_exit(void)
+{
+	struct net_device *dev;
+	struct arcnet_local *lp;
+	int count;
+
+	for (count = 0; count < numcards; count++) {
+		dev = cards[count];
+		lp = netdev_priv(dev);
+
+		unregister_netdev(dev);
+		free_irq(dev->irq, dev);
+		iounmap(lp->mem_start);
+		release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
+		release_mem_region(dev->mem_start,
+				   dev->mem_end - dev->mem_start + 1);
+		free_netdev(dev);
+	}
+}
+
+module_init(com90xx_init);
+module_exit(com90xx_exit);
+
+#ifndef MODULE
+static int __init com90xx_setup(char *s)
+{
+	int ints[8];
+
+	s = get_options(s, 8, ints);
+	if (!ints[0] && !*s) {
+		pr_notice("Disabled\n");
+		return 1;
+	}
+
+	switch (ints[0]) {
+	default:		/* ERROR */
+		pr_err("Too many arguments\n");
+	case 3:		/* Mem address */
+		shmem = ints[3];
+	case 2:		/* IRQ */
+		irq = ints[2];
+	case 1:		/* IO address */
+		io = ints[1];
+	}
+
+	if (*s)
+		snprintf(device, sizeof(device), "%s", s);
+
+	return 1;
+}
+
+__setup("com90xx=", com90xx_setup);
+#endif
diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c
new file mode 100644
index 0000000..a7752a5
--- /dev/null
+++ b/drivers/net/arcnet/rfc1051.c
@@ -0,0 +1,242 @@
+/*
+ * Linux ARCnet driver - RFC1051 ("simple" standard) packet encapsulation
+ *
+ * Written 1994-1999 by Avery Pennarun.
+ * Derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+
+#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <net/arp.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+#include "arcdevice.h"
+
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
+static void rx(struct net_device *dev, int bufnum,
+	       struct archdr *pkthdr, int length);
+static int build_header(struct sk_buff *skb, struct net_device *dev,
+			unsigned short type, uint8_t daddr);
+static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
+		      int bufnum);
+
+static struct ArcProto rfc1051_proto = {
+	.suffix		= 's',
+	.mtu		= XMTU - RFC1051_HDR_SIZE,
+	.is_ip          = 1,
+	.rx		= rx,
+	.build_header	= build_header,
+	.prepare_tx	= prepare_tx,
+	.continue_tx    = NULL,
+	.ack_tx         = NULL
+};
+
+static int __init arcnet_rfc1051_init(void)
+{
+	pr_info("%s\n", "RFC1051 \"simple standard\" (`s') encapsulation support loaded");
+
+	arc_proto_map[ARC_P_IP_RFC1051]
+	    = arc_proto_map[ARC_P_ARP_RFC1051]
+	    = &rfc1051_proto;
+
+	/* if someone else already owns the broadcast, we won't take it */
+	if (arc_bcast_proto == arc_proto_default)
+		arc_bcast_proto = &rfc1051_proto;
+
+	return 0;
+}
+
+static void __exit arcnet_rfc1051_exit(void)
+{
+	arcnet_unregister_proto(&rfc1051_proto);
+}
+
+module_init(arcnet_rfc1051_init);
+module_exit(arcnet_rfc1051_exit);
+
+MODULE_LICENSE("GPL");
+
+/* Determine a packet's protocol ID.
+ *
+ * With ARCnet we have to convert everything to Ethernet-style stuff.
+ */
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+	struct archdr *pkt = (struct archdr *)skb->data;
+	struct arc_rfc1051 *soft = &pkt->soft.rfc1051;
+	int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;
+
+	/* Pull off the arcnet header. */
+	skb_reset_mac_header(skb);
+	skb_pull(skb, hdr_size);
+
+	if (pkt->hard.dest == 0) {
+		skb->pkt_type = PACKET_BROADCAST;
+	} else if (dev->flags & IFF_PROMISC) {
+		/* if we're not sending to ourselves :) */
+		if (pkt->hard.dest != dev->dev_addr[0])
+			skb->pkt_type = PACKET_OTHERHOST;
+	}
+	/* now return the protocol number */
+	switch (soft->proto) {
+	case ARC_P_IP_RFC1051:
+		return htons(ETH_P_IP);
+	case ARC_P_ARP_RFC1051:
+		return htons(ETH_P_ARP);
+
+	default:
+		dev->stats.rx_errors++;
+		dev->stats.rx_crc_errors++;
+		return 0;
+	}
+
+	return htons(ETH_P_IP);
+}
+
+/* packet receiver */
+static void rx(struct net_device *dev, int bufnum,
+	       struct archdr *pkthdr, int length)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct sk_buff *skb;
+	struct archdr *pkt = pkthdr;
+	int ofs;
+
+	arc_printk(D_DURING, dev, "it's a raw packet (length=%d)\n", length);
+
+	if (length >= MinTU)
+		ofs = 512 - length;
+	else
+		ofs = 256 - length;
+
+	skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
+	if (!skb) {
+		dev->stats.rx_dropped++;
+		return;
+	}
+	skb_put(skb, length + ARC_HDR_SIZE);
+	skb->dev = dev;
+
+	pkt = (struct archdr *)skb->data;
+
+	/* up to sizeof(pkt->soft) has already been copied from the card */
+	memcpy(pkt, pkthdr, sizeof(struct archdr));
+	if (length > sizeof(pkt->soft))
+		lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft),
+				      pkt->soft.raw + sizeof(pkt->soft),
+				      length - sizeof(pkt->soft));
+
+	if (BUGLVL(D_SKB))
+		arcnet_dump_skb(dev, skb, "rx");
+
+	skb->protocol = type_trans(skb, dev);
+	netif_rx(skb);
+}
+
+/* Create the ARCnet hard/soft headers for RFC1051 */
+static int build_header(struct sk_buff *skb, struct net_device *dev,
+			unsigned short type, uint8_t daddr)
+{
+	int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;
+	struct archdr *pkt = skb_push(skb, hdr_size);
+	struct arc_rfc1051 *soft = &pkt->soft.rfc1051;
+
+	/* set the protocol ID according to RFC1051 */
+	switch (type) {
+	case ETH_P_IP:
+		soft->proto = ARC_P_IP_RFC1051;
+		break;
+	case ETH_P_ARP:
+		soft->proto = ARC_P_ARP_RFC1051;
+		break;
+	default:
+		arc_printk(D_NORMAL, dev, "RFC1051: I don't understand protocol %d (%Xh)\n",
+			   type, type);
+		dev->stats.tx_errors++;
+		dev->stats.tx_aborted_errors++;
+		return 0;
+	}
+
+	/* Set the source hardware address.
+	 *
+	 * This is pretty pointless for most purposes, but it can help in
+	 * debugging.  ARCnet does not allow us to change the source address
+	 * in the actual packet sent.
+	 */
+	pkt->hard.source = *dev->dev_addr;
+
+	/* see linux/net/ethernet/eth.c to see where I got the following */
+
+	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
+		/* FIXME: fill in the last byte of the dest ipaddr here to
+		 * better comply with RFC1051 in "noarp" mode.
+		 */
+		pkt->hard.dest = 0;
+		return hdr_size;
+	}
+	/* otherwise, just fill it in and go! */
+	pkt->hard.dest = daddr;
+
+	return hdr_size;	/* success */
+}
+
+static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
+		      int bufnum)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct arc_hardware *hard = &pkt->hard;
+	int ofs;
+
+	arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",
+		   lp->next_tx, lp->cur_tx, bufnum);
+
+	/* hard header is not included in packet length */
+	length -= ARC_HDR_SIZE;
+
+	if (length > XMTU) {
+		/* should never happen! other people already check for this. */
+		arc_printk(D_NORMAL, dev, "Bug!  prepare_tx with size %d (> %d)\n",
+			   length, XMTU);
+		length = XMTU;
+	}
+	if (length > MinTU) {
+		hard->offset[0] = 0;
+		hard->offset[1] = ofs = 512 - length;
+	} else if (length > MTU) {
+		hard->offset[0] = 0;
+		hard->offset[1] = ofs = 512 - length - 3;
+	} else {
+		hard->offset[0] = ofs = 256 - length;
+	}
+
+	lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
+	lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length);
+
+	lp->lastload_dest = hard->dest;
+
+	return 1;		/* done */
+}
diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c
new file mode 100644
index 0000000..a4c8562
--- /dev/null
+++ b/drivers/net/arcnet/rfc1201.c
@@ -0,0 +1,547 @@
+/*
+ * Linux ARCnet driver - RFC1201 (standard) packet encapsulation
+ *
+ * Written 1994-1999 by Avery Pennarun.
+ * Derived from skeleton.c by Donald Becker.
+ *
+ * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
+ *  for sponsoring the further development of this driver.
+ *
+ * **********************
+ *
+ * The original copyright of skeleton.c 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 General Public License as
+ * modified by SRC, incorporated herein by reference.
+ *
+ * **********************
+ *
+ * For more details, see drivers/net/arcnet.c
+ *
+ * **********************
+ */
+
+#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
+
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+#include "arcdevice.h"
+
+MODULE_LICENSE("GPL");
+
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
+static void rx(struct net_device *dev, int bufnum,
+	       struct archdr *pkthdr, int length);
+static int build_header(struct sk_buff *skb, struct net_device *dev,
+			unsigned short type, uint8_t daddr);
+static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
+		      int bufnum);
+static int continue_tx(struct net_device *dev, int bufnum);
+
+static struct ArcProto rfc1201_proto = {
+	.suffix		= 'a',
+	.mtu		= 1500,	/* could be more, but some receivers can't handle it... */
+	.is_ip          = 1,    /* This is for sending IP and ARP packages */
+	.rx		= rx,
+	.build_header	= build_header,
+	.prepare_tx	= prepare_tx,
+	.continue_tx	= continue_tx,
+	.ack_tx         = NULL
+};
+
+static int __init arcnet_rfc1201_init(void)
+{
+	pr_info("%s\n", "RFC1201 \"standard\" (`a') encapsulation support loaded");
+
+	arc_proto_map[ARC_P_IP]
+	    = arc_proto_map[ARC_P_IPV6]
+	    = arc_proto_map[ARC_P_ARP]
+	    = arc_proto_map[ARC_P_RARP]
+	    = arc_proto_map[ARC_P_IPX]
+	    = arc_proto_map[ARC_P_NOVELL_EC]
+	    = &rfc1201_proto;
+
+	/* if someone else already owns the broadcast, we won't take it */
+	if (arc_bcast_proto == arc_proto_default)
+		arc_bcast_proto = &rfc1201_proto;
+
+	return 0;
+}
+
+static void __exit arcnet_rfc1201_exit(void)
+{
+	arcnet_unregister_proto(&rfc1201_proto);
+}
+
+module_init(arcnet_rfc1201_init);
+module_exit(arcnet_rfc1201_exit);
+
+/* Determine a packet's protocol ID.
+ *
+ * With ARCnet we have to convert everything to Ethernet-style stuff.
+ */
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+	struct archdr *pkt = (struct archdr *)skb->data;
+	struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
+	int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
+
+	/* Pull off the arcnet header. */
+	skb_reset_mac_header(skb);
+	skb_pull(skb, hdr_size);
+
+	if (pkt->hard.dest == 0) {
+		skb->pkt_type = PACKET_BROADCAST;
+	} else if (dev->flags & IFF_PROMISC) {
+		/* if we're not sending to ourselves :) */
+		if (pkt->hard.dest != dev->dev_addr[0])
+			skb->pkt_type = PACKET_OTHERHOST;
+	}
+	/* now return the protocol number */
+	switch (soft->proto) {
+	case ARC_P_IP:
+		return htons(ETH_P_IP);
+	case ARC_P_IPV6:
+		return htons(ETH_P_IPV6);
+	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:
+		dev->stats.rx_errors++;
+		dev->stats.rx_crc_errors++;
+		return 0;
+	}
+
+	return htons(ETH_P_IP);
+}
+
+/* packet receiver */
+static void rx(struct net_device *dev, int bufnum,
+	       struct archdr *pkthdr, int length)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct sk_buff *skb;
+	struct archdr *pkt = pkthdr;
+	struct arc_rfc1201 *soft = &pkthdr->soft.rfc1201;
+	int saddr = pkt->hard.source, ofs;
+	struct Incoming *in = &lp->rfc1201.incoming[saddr];
+
+	arc_printk(D_DURING, dev, "it's an RFC1201 packet (length=%d)\n",
+		   length);
+
+	if (length >= MinTU)
+		ofs = 512 - length;
+	else
+		ofs = 256 - length;
+
+	if (soft->split_flag == 0xFF) {		/* Exception Packet */
+		if (length >= 4 + RFC1201_HDR_SIZE) {
+			arc_printk(D_DURING, dev, "compensating for exception packet\n");
+		} else {
+			arc_printk(D_EXTRA, dev, "short RFC1201 exception packet from %02Xh",
+				   saddr);
+			return;
+		}
+
+		/* skip over 4-byte junkola */
+		length -= 4;
+		ofs += 4;
+		lp->hw.copy_from_card(dev, bufnum, 512 - length,
+				      soft, sizeof(pkt->soft));
+	}
+	if (!soft->split_flag) {	/* not split */
+		arc_printk(D_RX, dev, "incoming is not split (splitflag=%d)\n",
+			   soft->split_flag);
+
+		if (in->skb) {	/* already assembling one! */
+			arc_printk(D_EXTRA, dev, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
+				   in->sequence, soft->split_flag,
+				   soft->sequence);
+			lp->rfc1201.aborted_seq = soft->sequence;
+			dev_kfree_skb_irq(in->skb);
+			dev->stats.rx_errors++;
+			dev->stats.rx_missed_errors++;
+			in->skb = NULL;
+		}
+		in->sequence = soft->sequence;
+
+		skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
+		if (!skb) {
+			dev->stats.rx_dropped++;
+			return;
+		}
+		skb_put(skb, length + ARC_HDR_SIZE);
+		skb->dev = dev;
+
+		pkt = (struct archdr *)skb->data;
+		soft = &pkt->soft.rfc1201;
+
+		/* up to sizeof(pkt->soft) has already
+		 * been copied from the card
+		 */
+		memcpy(pkt, pkthdr, sizeof(struct archdr));
+		if (length > sizeof(pkt->soft))
+			lp->hw.copy_from_card(dev, bufnum,
+					      ofs + sizeof(pkt->soft),
+					      pkt->soft.raw + sizeof(pkt->soft),
+					      length - sizeof(pkt->soft));
+
+		/* ARP packets have problems when sent from some DOS systems:
+		 * the source address is always 0!
+		 * So we take the hardware source addr (which is impossible
+		 * to fumble) and insert it ourselves.
+		 */
+		if (soft->proto == ARC_P_ARP) {
+			struct arphdr *arp = (struct arphdr *)soft->payload;
+
+			/* make sure addresses are the right length */
+			if (arp->ar_hln == 1 && arp->ar_pln == 4) {
+				uint8_t *cptr = (uint8_t *)arp + sizeof(struct arphdr);
+
+				if (!*cptr) {	/* is saddr = 00? */
+					arc_printk(D_EXTRA, dev,
+						   "ARP source address was 00h, set to %02Xh\n",
+						   saddr);
+					dev->stats.rx_crc_errors++;
+					*cptr = saddr;
+				} else {
+					arc_printk(D_DURING, dev, "ARP source address (%Xh) is fine.\n",
+						   *cptr);
+				}
+			} else {
+				arc_printk(D_NORMAL, dev, "funny-shaped ARP packet. (%Xh, %Xh)\n",
+					   arp->ar_hln, arp->ar_pln);
+				dev->stats.rx_errors++;
+				dev->stats.rx_crc_errors++;
+			}
+		}
+		if (BUGLVL(D_SKB))
+			arcnet_dump_skb(dev, skb, "rx");
+
+		skb->protocol = 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 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, but there's no
+		 * other way to be reliable.
+		 */
+
+		arc_printk(D_RX, dev, "packet is split (splitflag=%d, seq=%d)\n",
+			   soft->split_flag, in->sequence);
+
+		if (in->skb && in->sequence != soft->sequence) {
+			arc_printk(D_EXTRA, dev, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
+				   saddr, in->sequence, soft->sequence,
+				   soft->split_flag);
+			dev_kfree_skb_irq(in->skb);
+			in->skb = NULL;
+			dev->stats.rx_errors++;
+			dev->stats.rx_missed_errors++;
+			in->lastpacket = in->numpackets = 0;
+		}
+		if (soft->split_flag & 1) {	/* first packet in split */
+			arc_printk(D_RX, dev, "brand new splitpacket (splitflag=%d)\n",
+				   soft->split_flag);
+			if (in->skb) {	/* already assembling one! */
+				arc_printk(D_EXTRA, dev, "aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
+					   in->sequence, soft->split_flag,
+					   soft->sequence);
+				dev->stats.rx_errors++;
+				dev->stats.rx_missed_errors++;
+				dev_kfree_skb_irq(in->skb);
+			}
+			in->sequence = soft->sequence;
+			in->numpackets = ((unsigned)soft->split_flag >> 1) + 2;
+			in->lastpacket = 1;
+
+			if (in->numpackets > 16) {
+				arc_printk(D_EXTRA, dev, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
+					   soft->split_flag);
+				lp->rfc1201.aborted_seq = soft->sequence;
+				dev->stats.rx_errors++;
+				dev->stats.rx_length_errors++;
+				return;
+			}
+			in->skb = skb = alloc_skb(508 * in->numpackets + ARC_HDR_SIZE,
+						  GFP_ATOMIC);
+			if (!skb) {
+				arc_printk(D_NORMAL, dev, "(split) memory squeeze, dropping packet.\n");
+				lp->rfc1201.aborted_seq = soft->sequence;
+				dev->stats.rx_dropped++;
+				return;
+			}
+			skb->dev = dev;
+			pkt = (struct archdr *)skb->data;
+			soft = &pkt->soft.rfc1201;
+
+			memcpy(pkt, pkthdr, ARC_HDR_SIZE + RFC1201_HDR_SIZE);
+			skb_put(skb, ARC_HDR_SIZE + RFC1201_HDR_SIZE);
+
+			soft->split_flag = 0;	/* end result won't be split */
+		} else {	/* not first packet */
+			int packetnum = ((unsigned)soft->split_flag >> 1) + 1;
+
+			/* if we're not assembling, there's no point trying to
+			 * continue.
+			 */
+			if (!in->skb) {
+				if (lp->rfc1201.aborted_seq != soft->sequence) {
+					arc_printk(D_EXTRA, dev, "can't continue split without starting first! (splitflag=%d, seq=%d, aborted=%d)\n",
+						   soft->split_flag,
+						   soft->sequence,
+						   lp->rfc1201.aborted_seq);
+					dev->stats.rx_errors++;
+					dev->stats.rx_missed_errors++;
+				}
+				return;
+			}
+			in->lastpacket++;
+			/* if not the right flag */
+			if (packetnum != in->lastpacket) {
+				/* harmless duplicate? ignore. */
+				if (packetnum <= in->lastpacket - 1) {
+					arc_printk(D_EXTRA, dev, "duplicate splitpacket ignored! (splitflag=%d)\n",
+						   soft->split_flag);
+					dev->stats.rx_errors++;
+					dev->stats.rx_frame_errors++;
+					return;
+				}
+				/* "bad" duplicate, kill reassembly */
+				arc_printk(D_EXTRA, dev, "out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
+					   in->sequence, soft->split_flag,
+					   soft->sequence);
+				lp->rfc1201.aborted_seq = soft->sequence;
+				dev_kfree_skb_irq(in->skb);
+				in->skb = NULL;
+				dev->stats.rx_errors++;
+				dev->stats.rx_missed_errors++;
+				in->lastpacket = in->numpackets = 0;
+				return;
+			}
+			pkt = (struct archdr *)in->skb->data;
+			soft = &pkt->soft.rfc1201;
+		}
+
+		skb = in->skb;
+
+		lp->hw.copy_from_card(dev, bufnum, ofs + RFC1201_HDR_SIZE,
+				      skb->data + skb->len,
+				      length - RFC1201_HDR_SIZE);
+		skb_put(skb, length - RFC1201_HDR_SIZE);
+
+		/* are we done? */
+		if (in->lastpacket == in->numpackets) {
+			in->skb = NULL;
+			in->lastpacket = in->numpackets = 0;
+
+			arc_printk(D_SKB_SIZE, dev, "skb: received %d bytes from %02X (unsplit)\n",
+				   skb->len, pkt->hard.source);
+			arc_printk(D_SKB_SIZE, dev, "skb: received %d bytes from %02X (split)\n",
+				   skb->len, pkt->hard.source);
+			if (BUGLVL(D_SKB))
+				arcnet_dump_skb(dev, skb, "rx");
+
+			skb->protocol = type_trans(skb, dev);
+			netif_rx(skb);
+		}
+	}
+}
+
+/* Create the ARCnet hard/soft headers for RFC1201. */
+static int build_header(struct sk_buff *skb, struct net_device *dev,
+			unsigned short type, uint8_t daddr)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
+	struct archdr *pkt = skb_push(skb, hdr_size);
+	struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
+
+	/* set the protocol ID according to RFC1201 */
+	switch (type) {
+	case ETH_P_IP:
+		soft->proto = ARC_P_IP;
+		break;
+	case ETH_P_IPV6:
+		soft->proto = ARC_P_IPV6;
+		break;
+	case ETH_P_ARP:
+		soft->proto = ARC_P_ARP;
+		break;
+	case ETH_P_RARP:
+		soft->proto = ARC_P_RARP;
+		break;
+	case ETH_P_IPX:
+	case ETH_P_802_3:
+	case ETH_P_802_2:
+		soft->proto = ARC_P_IPX;
+		break;
+	case ETH_P_ATALK:
+		soft->proto = ARC_P_ATALK;
+		break;
+	default:
+		arc_printk(D_NORMAL, dev, "RFC1201: I don't understand protocol %d (%Xh)\n",
+			   type, type);
+		dev->stats.tx_errors++;
+		dev->stats.tx_aborted_errors++;
+		return 0;
+	}
+
+	/* Set the source hardware address.
+	 *
+	 * This is pretty pointless for most purposes, but it can help in
+	 * debugging.  ARCnet does not allow us to change the source address
+	 * in the actual packet sent.
+	 */
+	pkt->hard.source = *dev->dev_addr;
+
+	soft->sequence = htons(lp->rfc1201.sequence++);
+	soft->split_flag = 0;	/* split packets are done elsewhere */
+
+	/* see linux/net/ethernet/eth.c to see where I got the following */
+
+	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
+		/* FIXME: fill in the last byte of the dest ipaddr here
+		 * to better comply with RFC1051 in "noarp" mode.
+		 * For now, always broadcasting will probably at least get
+		 * packets sent out :)
+		 */
+		pkt->hard.dest = 0;
+		return hdr_size;
+	}
+	/* otherwise, drop in the dest address */
+	pkt->hard.dest = daddr;
+	return hdr_size;
+}
+
+static void load_pkt(struct net_device *dev, struct arc_hardware *hard,
+		     struct arc_rfc1201 *soft, int softlen, int bufnum)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	int ofs;
+
+	/* assume length <= XMTU: someone should have handled that by now. */
+
+	if (softlen > MinTU) {
+		hard->offset[0] = 0;
+		hard->offset[1] = ofs = 512 - softlen;
+	} else if (softlen > MTU) {	/* exception packet - add an extra header */
+		struct arc_rfc1201 excsoft;
+
+		excsoft.proto = soft->proto;
+		excsoft.split_flag = 0xff;
+		excsoft.sequence = htons(0xffff);
+
+		hard->offset[0] = 0;
+		ofs = 512 - softlen;
+		hard->offset[1] = ofs - RFC1201_HDR_SIZE;
+		lp->hw.copy_to_card(dev, bufnum, ofs - RFC1201_HDR_SIZE,
+				    &excsoft, RFC1201_HDR_SIZE);
+	} else {
+		hard->offset[0] = ofs = 256 - softlen;
+	}
+
+	lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
+	lp->hw.copy_to_card(dev, bufnum, ofs, soft, softlen);
+
+	lp->lastload_dest = hard->dest;
+}
+
+static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
+		      int bufnum)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	const int maxsegsize = XMTU - RFC1201_HDR_SIZE;
+	struct Outgoing *out;
+
+	arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",
+		   lp->next_tx, lp->cur_tx, bufnum);
+
+	/* hard header is not included in packet length */
+	length -= ARC_HDR_SIZE;
+	pkt->soft.rfc1201.split_flag = 0;
+
+	/* need to do a split packet? */
+	if (length > XMTU) {
+		out = &lp->outgoing;
+
+		out->length = length - RFC1201_HDR_SIZE;
+		out->dataleft = lp->outgoing.length;
+		out->numsegs = (out->dataleft + maxsegsize - 1) / maxsegsize;
+		out->segnum = 0;
+
+		arc_printk(D_DURING, dev, "rfc1201 prep_tx: ready for %d-segment split (%d bytes, seq=%d)\n",
+			   out->numsegs, out->length,
+			   pkt->soft.rfc1201.sequence);
+
+		return 0;	/* not done */
+	}
+	/* just load the packet into the buffers and send it off */
+	load_pkt(dev, &pkt->hard, &pkt->soft.rfc1201, length, bufnum);
+
+	return 1;		/* done */
+}
+
+static int continue_tx(struct net_device *dev, int bufnum)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct Outgoing *out = &lp->outgoing;
+	struct arc_hardware *hard = &out->pkt->hard;
+	struct arc_rfc1201 *soft = &out->pkt->soft.rfc1201, *newsoft;
+	int maxsegsize = XMTU - RFC1201_HDR_SIZE;
+	int seglen;
+
+	arc_printk(D_DURING, dev,
+		   "rfc1201 continue_tx: loading segment %d(+1) of %d (seq=%d)\n",
+		   out->segnum, out->numsegs, soft->sequence);
+
+	/* the "new" soft header comes right before the data chunk */
+	newsoft = (struct arc_rfc1201 *)
+	    (out->pkt->soft.raw + out->length - out->dataleft);
+
+	if (!out->segnum)	/* first packet; newsoft == soft */
+		newsoft->split_flag = ((out->numsegs - 2) << 1) | 1;
+	else {
+		newsoft->split_flag = out->segnum << 1;
+		newsoft->proto = soft->proto;
+		newsoft->sequence = soft->sequence;
+	}
+
+	seglen = maxsegsize;
+	if (seglen > out->dataleft)
+		seglen = out->dataleft;
+	out->dataleft -= seglen;
+
+	load_pkt(dev, hard, newsoft, seglen + RFC1201_HDR_SIZE, bufnum);
+
+	out->segnum++;
+	if (out->segnum >= out->numsegs)
+		return 1;
+	else
+		return 0;
+}