Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
This commit is contained in:
Linus Torvalds
2005-04-16 15:20:36 -07:00
commit 1da177e4c3
17291 changed files with 6718755 additions and 0 deletions

140
drivers/net/arcnet/Kconfig Normal file
View File

@@ -0,0 +1,140 @@
#
# Arcnet configuration
#
menu "ARCnet devices"
depends on NETDEVICES && (ISA || PCI)
config ARCNET
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.
You might also want to have a look at the Ethernet-HOWTO, available
from <http://www.tldp.org/docs.html#howto>(even though ARCnet
is not really Ethernet).
To compile this driver as a module, choose M here and read
<file:Documentation/networking/net-modules.txt>. The module will
be called arcnet.
config ARCNET_1201
tristate "Enable standard ARCNet packet format (RFC 1201)"
depends on ARCNET
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)"
depends on ARCNET
---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"
depends on ARCNET
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"
depends on ARCNET
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
transmition:
0=no hardware acknowledge
1=excessive nak
2=transmition accepted by the reciever 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"
depends on ARCNET
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 and read
<file:Documentation/networking/net-modules.txt>. The module will
be called com90xx.
config ARCNET_COM90xxIO
tristate "ARCnet COM90xx (IO mapped) chipset driver"
depends on ARCNET
---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 and read
<file:Documentation/networking/net-modules.txt>. The module will
be called com90io.
config ARCNET_RIM_I
tristate "ARCnet COM90xx (RIM I) chipset driver"
depends on ARCNET
---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 and read
<file:Documentation/networking/net-modules.txt>. The module will
be called arc-rimi.
config ARCNET_COM20020
tristate "ARCnet COM20020 chipset driver"
depends on ARCNET
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 and read
<file:Documentation/networking/net-modules.txt>. 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
endmenu

View File

@@ -0,0 +1,14 @@
# 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

View File

@@ -0,0 +1,204 @@
/*
* 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
*
* **********************
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/if_arp.h>
#include <net/arp.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: raw mode (`r') encapsulation support loaded.\n"
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);
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;
printk(VERSION);
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");
/* packet receiver */
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length)
{
struct arcnet_local *lp = dev->priv;
struct sk_buff *skb;
struct archdr *pkt = pkthdr;
int ofs;
BUGMSG(D_DURING, "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 == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
lp->stats.rx_dropped++;
return;
}
skb_put(skb, length + ARC_HDR_SIZE);
skb->dev = dev;
pkt = (struct archdr *) skb->data;
skb->mac.raw = skb->data;
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));
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
skb->protocol = __constant_htons(ETH_P_ARCNET);
;
netif_rx(skb);
dev->last_rx = jiffies;
}
/*
* 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 = (struct archdr *) 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 = dev->priv;
struct arc_hardware *hard = &pkt->hard;
int ofs;
BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
length -= ARC_HDR_SIZE; /* hard header is not included in packet length */
if (length > XMTU) {
/* should never happen! other people already check for this. */
BUGMSG(D_NORMAL, "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;
BUGMSG(D_DURING, "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 */
}

View File

@@ -0,0 +1,368 @@
/*
* 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
*
* **********************
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/bootmem.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: RIM I (entirely mem-mapped) support\n"
/* 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)
/* COM 9026 controller chip --> ARCnet register addresses */
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define _RESET (ioaddr+8) /* software reset (on read) */
#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */
#define _ADDR_HI (ioaddr+15) /* Control registers for said */
#define _ADDR_LO (ioaddr+14)
#define _CONFIG (ioaddr+2) /* Configuration register */
#undef ASTATUS
#undef ACOMMAND
#undef AINTMASK
#define ASTATUS() readb(_STATUS)
#define ACOMMAND(cmd) writeb((cmd),_COMMAND)
#define AINTMASK(msk) writeb((msk),_INTMASK)
#define SETCONF() writeb(lp->config,_CONFIG)
/*
* 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)
{
BUGLVL(D_NORMAL) printk(VERSION);
BUGLVL(D_NORMAL) printk("E-mail me if you actually test the RIM I driver, please!\n");
BUGMSG(D_NORMAL, "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) {
BUGMSG(D_NORMAL, "No autoprobe for RIM I; you "
"must specify the shmem and irq!\n");
return -ENODEV;
}
/*
* Grab the memory region at mem_start for BUFFER_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, BUFFER_SIZE, "arcnet (90xx)")) {
BUGMSG(D_NORMAL, "Card memory already allocated\n");
return -ENODEV;
}
if (dev->dev_addr[0] == 0) {
release_mem_region(dev->mem_start, BUFFER_SIZE);
BUGMSG(D_NORMAL, "You need to specify your card's station "
"ID!\n");
return -ENODEV;
}
return arcrimi_found(dev);
}
/*
* 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;
int mirror_size;
int err;
/* reserve the irq */
if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (RIM I)", dev)) {
release_mem_region(dev->mem_start, BUFFER_SIZE);
BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
return -ENODEV;
}
shmem = dev->mem_start;
isa_writeb(TESTvalue, shmem);
isa_writeb(dev->dev_addr[0], shmem + 1); /* actually the 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 (isa_readb(shmem) == TESTvalue
&& isa_readb(shmem - mirror_size) != TESTvalue
&& isa_readb(shmem - 2 * mirror_size) == TESTvalue)
mirror_size *= 2;
first_mirror = last_mirror = shmem;
while (isa_readb(first_mirror) == TESTvalue)
first_mirror -= mirror_size;
first_mirror += mirror_size;
while (isa_readb(last_mirror) == TESTvalue)
last_mirror += mirror_size;
last_mirror -= mirror_size;
dev->mem_start = first_mirror;
dev->mem_end = last_mirror + MIRROR_SIZE - 1;
/* initialize the rest of the device structure. */
lp = dev->priv;
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.
*/
release_mem_region(shmem, BUFFER_SIZE);
if (!request_mem_region(dev->mem_start,
dev->mem_end - dev->mem_start + 1,
"arcnet (90xx)")) {
BUGMSG(D_NORMAL, "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) {
BUGMSG(D_NORMAL, "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] = readb(lp->mem_start + 1);
BUGMSG(D_NORMAL, "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 = dev->priv;
void __iomem *ioaddr = lp->mem_start + 0x800;
BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS());
if (really_reset) {
writeb(TESTvalue, ioaddr - 0x800); /* fake reset */
return 0;
}
ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd | CONFIGclear);
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd | EXTconf);
/* done! return success. */
return 0;
}
static void arcrimi_setmask(struct net_device *dev, int mask)
{
struct arcnet_local *lp = dev->priv;
void __iomem *ioaddr = lp->mem_start + 0x800;
AINTMASK(mask);
}
static int arcrimi_status(struct net_device *dev)
{
struct arcnet_local *lp = dev->priv;
void __iomem *ioaddr = lp->mem_start + 0x800;
return ASTATUS();
}
static void arcrimi_command(struct net_device *dev, int cmd)
{
struct arcnet_local *lp = dev->priv;
void __iomem *ioaddr = lp->mem_start + 0x800;
ACOMMAND(cmd);
}
static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count)
{
struct arcnet_local *lp = dev->priv;
void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
TIME("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 = dev->priv;
void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
TIME("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 = dev->priv;
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 */
printk("arcrimi: 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)

1102
drivers/net/arcnet/arcnet.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,296 @@
/*
* 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
*
* **********************
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/if_arp.h>
#include <net/arp.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: cap mode (`c') encapsulation support loaded.\n"
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 ack_tx(struct net_device *dev, int acked);
struct ArcProto capmode_proto =
{
'r',
XMTU,
0,
rx,
build_header,
prepare_tx,
NULL,
ack_tx
};
void arcnet_cap_init(void)
{
int count;
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;
}
#ifdef MODULE
int __init init_module(void)
{
printk(VERSION);
arcnet_cap_init();
return 0;
}
void cleanup_module(void)
{
arcnet_unregister_proto(&capmode_proto);
}
MODULE_LICENSE("GPL");
#endif /* MODULE */
/* packet receiver */
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
struct sk_buff *skb;
struct archdr *pkt = pkthdr;
char *pktbuf, *pkthdrbuf;
int ofs;
BUGMSG(D_DURING, "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 == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
lp->stats.rx_dropped++;
return;
}
skb_put(skb, length + ARC_HDR_SIZE + sizeof(int));
skb->dev = dev;
pkt = (struct archdr *) skb->data;
skb->mac.raw = skb->data;
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));
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
skb->protocol = __constant_htons(ETH_P_ARCNET);
;
netif_rx(skb);
dev->last_rx = jiffies;
}
/*
* 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 = (struct archdr *) skb_push(skb, hdr_size);
BUGMSG(D_PROTO, "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 = (struct arcnet_local *) dev->priv;
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);
BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
BUGMSG(D_PROTO, "Sending for cap packet %x.\n",
*((int*)&pkt->soft.cap.cookie[0]));
if (length > XMTU) {
/* should never happen! other people already check for this. */
BUGMSG(D_NORMAL, "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;
BUGMSG(D_DURING, "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 = (struct arcnet_local *) dev->priv;
struct sk_buff *ackskb;
struct archdr *ackpkt;
int length=sizeof(struct arc_cap);
BUGMSG(D_DURING, "capmode: ack_tx: protocol: %x: result: %d\n",
lp->outgoing.skb->protocol, acked);
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 == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, can't acknowledge.\n");
goto free_outskb;
}
skb_put(ackskb, length + ARC_HDR_SIZE );
ackskb->dev = dev;
ackpkt = (struct archdr *) ackskb->data;
ackskb->mac.raw = ackskb->data;
/* skb_pull(ackskb, ARC_HDR_SIZE); */
memcpy(ackpkt, lp->outgoing.skb->data, ARC_HDR_SIZE+sizeof(struct arc_cap));
ackpkt->soft.cap.proto=0; /* using protocol 0 for acknowledge */
ackpkt->soft.cap.mes.ack=acked;
BUGMSG(D_PROTO, "Ackknowledge for cap packet %x.\n",
*((int*)&ackpkt->soft.cap.cookie[0]));
ackskb->protocol = __constant_htons(ETH_P_ARCNET);
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;
}

View File

@@ -0,0 +1,219 @@
/*
* 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
*
* **********************
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/arcdevice.h>
#include <linux/com20020.h>
#include <asm/io.h>
#define VERSION "arcnet: COM20020 ISA support (by David Woodhouse et al.)\n"
/*
* 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 = dev->priv;
int err;
BUGLVL(D_NORMAL) printk(VERSION);
ioaddr = dev->base_addr;
if (!ioaddr) {
BUGMSG(D_NORMAL, "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)")) {
BUGMSG(D_NORMAL, "IO region %xh-%xh already allocated.\n",
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
return -ENXIO;
}
if (ASTATUS() == 0xFF) {
BUGMSG(D_NORMAL, "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.
*/
BUGMSG(D_INIT_REASONS, "intmask was %02Xh\n", inb(_INTMASK));
outb(0, _INTMASK);
airqmask = probe_irq_on();
outb(NORXflag, _INTMASK);
udelay(1);
outb(0, _INTMASK);
dev->irq = probe_irq_off(airqmask);
if (dev->irq <= 0) {
BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed first time\n");
airqmask = probe_irq_on();
outb(NORXflag, _INTMASK);
udelay(5);
outb(0, _INTMASK);
dev->irq = probe_irq_off(airqmask);
if (dev->irq <= 0) {
BUGMSG(D_NORMAL, "Autoprobe IRQ failed.\n");
err = -ENODEV;
goto out;
}
}
}
lp->card_name = "ISA COM20020";
if ((err = com20020_found(dev, 0)) != 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(io, int, 0);
module_param(irq, 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 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;
lp = dev->priv;
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 */
printk("com90xx: 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)

View File

@@ -0,0 +1,189 @@
/*
* 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
*
* **********************
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/arcdevice.h>
#include <linux/com20020.h>
#include <asm/io.h>
#define VERSION "arcnet: COM20020 PCI support\n"
/* 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 int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct net_device *dev;
struct arcnet_local *lp;
int ioaddr, err;
if (pci_enable_device(pdev))
return -EIO;
dev = alloc_arcdev(device);
if (!dev)
return -ENOMEM;
lp = dev->priv;
pci_set_drvdata(pdev, dev);
// SOHARD needs PCI base addr 4
if (pdev->vendor==0x10B5) {
BUGMSG(D_NORMAL, "SOHARD\n");
ioaddr = pci_resource_start(pdev, 4);
}
else {
BUGMSG(D_NORMAL, "Contemporary Controls\n");
ioaddr = pci_resource_start(pdev, 2);
}
if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) {
BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n",
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
err = -EBUSY;
goto out_dev;
}
// Dummy access after Reset
// ARCNET controller needs this access to detect bustype
outb(0x00,ioaddr+1);
inb(ioaddr+1);
dev->base_addr = ioaddr;
dev->irq = pdev->irq;
dev->dev_addr[0] = node;
lp->card_name = "PCI COM20020";
lp->card_flags = id->driver_data;
lp->backplane = backplane;
lp->clockp = clockp & 7;
lp->clockm = clockm & 3;
lp->timeout = timeout;
lp->hw.owner = THIS_MODULE;
if (ASTATUS() == 0xFF) {
BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, "
"but seems empty!\n", ioaddr);
err = -EIO;
goto out_port;
}
if (com20020_check(dev)) {
err = -EIO;
goto out_port;
}
if ((err = com20020_found(dev, SA_SHIRQ)) != 0)
goto out_port;
return 0;
out_port:
release_region(ioaddr, ARCNET_TOTAL_SIZE);
out_dev:
free_netdev(dev);
return err;
}
static void __devexit com20020pci_remove(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
unregister_netdev(dev);
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
free_netdev(dev);
}
static 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, ARC_IS_5MBIT },
{ 0x1571, 0xa00a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
{ 0x1571, 0xa00b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
{ 0x1571, 0xa00c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
{ 0x1571, 0xa00d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
{ 0x1571, 0xa201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x1571, 0xa202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x1571, 0xa203, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_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 = __devexit_p(com20020pci_remove),
};
static int __init com20020pci_init(void)
{
BUGLVL(D_NORMAL) printk(VERSION);
return pci_module_init(&com20020pci_driver);
}
static void __exit com20020pci_cleanup(void)
{
pci_unregister_driver(&com20020pci_driver);
}
module_init(com20020pci_init)
module_exit(com20020pci_cleanup)

View File

@@ -0,0 +1,357 @@
/*
* 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
*
* **********************
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/init.h>
#include <linux/arcdevice.h>
#include <linux/com20020.h>
#include <asm/io.h>
#define VERSION "arcnet: COM20020 chipset support (by David Woodhouse et al.)\n"
static char *clockrates[] =
{"10 Mb/s", "Reserved", "5 Mb/s",
"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 */
outb((ofs >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
outb(ofs & 0xff, _ADDR_LO);
/* copy the data */
TIME("insb", count, insb(_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 */
outb((ofs >> 8) | AUTOINCflag, _ADDR_HI);
outb(ofs & 0xff, _ADDR_LO);
/* copy the data */
TIME("outsb", count, outsb(_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 = dev->priv;
ARCRESET0;
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;
SET_SUBADR(SUB_SETUP1);
outb(lp->setup, _XREG);
if (lp->card_flags & ARC_CAN_10MBIT)
{
SET_SUBADR(SUB_SETUP2);
outb(lp->setup2, _XREG);
/* must now write the magic "restart operation" command */
mdelay(1);
outb(0x18, _COMMAND);
}
lp->config = 0x21 | (lp->timeout << 3) | (lp->backplane << 2);
/* set node ID to 0x42 (but transmitter is disabled, so it's okay) */
SETCONF;
outb(0x42, ioaddr + BUS_ALIGN*7);
status = ASTATUS();
if ((status & 0x99) != (NORXflag | TXFREEflag | RESETflag)) {
BUGMSG(D_NORMAL, "status invalid (%Xh).\n", status);
return -ENODEV;
}
BUGMSG(D_INIT_REASONS, "status after reset: %X\n", status);
/* Enable TX */
outb(0x39, _CONFIG);
outb(inb(ioaddr + BUS_ALIGN*8), ioaddr + BUS_ALIGN*7);
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
status = ASTATUS();
BUGMSG(D_INIT_REASONS, "status after reset acknowledged: %X\n",
status);
/* Read first location of memory */
outb(0 | RDDATAflag | AUTOINCflag, _ADDR_HI);
outb(0, _ADDR_LO);
if ((status = inb(_MEMDATA)) != TESTvalue) {
BUGMSG(D_NORMAL, "Signature byte not found (%02Xh != D1h).\n",
status);
return -ENODEV;
}
return 0;
}
/* 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 = dev->priv;
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;
dev->set_multicast_list = com20020_set_mc_list;
if (!dev->dev_addr[0])
dev->dev_addr[0] = inb(ioaddr + BUS_ALIGN*8); /* FIXME: do this some other way! */
SET_SUBADR(SUB_SETUP1);
outb(lp->setup, _XREG);
if (lp->card_flags & ARC_CAN_10MBIT)
{
SET_SUBADR(SUB_SETUP2);
outb(lp->setup2, _XREG);
/* must now write the magic "restart operation" command */
mdelay(1);
outb(0x18, _COMMAND);
}
lp->config = 0x20 | (lp->timeout << 3) | (lp->backplane << 2) | 1;
/* Default 0x38 + register: Node ID */
SETCONF;
outb(dev->dev_addr[0], _XREG);
/* reserve the irq */
if (request_irq(dev->irq, &arcnet_interrupt, shared,
"arcnet (COM20020)", dev)) {
BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
return -ENODEV;
}
dev->base_addr = ioaddr;
BUGMSG(D_NORMAL, "%s: station %02Xh found at %03lXh, IRQ %d.\n",
lp->card_name, dev->dev_addr[0], dev->base_addr, dev->irq);
if (lp->backplane)
BUGMSG(D_NORMAL, "Using backplane mode.\n");
if (lp->timeout != 3)
BUGMSG(D_NORMAL, "Using extended timeout value of %d.\n", lp->timeout);
BUGMSG(D_NORMAL, "Using CKP %d - data rate %s.\n",
lp->setup >> 1,
clockrates[3 - ((lp->setup2 & 0xF0) >> 4) + ((lp->setup & 0x0F) >> 1)]);
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 = dev->priv;
u_int ioaddr = dev->base_addr;
u_char inbyte;
BUGMSG(D_DEBUG, "%s: %d: %s: dev: %p, lp: %p, dev->name: %s\n",
__FILE__,__LINE__,__FUNCTION__,dev,lp,dev->name);
BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n",
dev->name, ASTATUS());
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2);
/* power-up defaults */
SETCONF;
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
if (really_reset) {
/* reset the card */
ARCRESET;
mdelay(RESETtime * 2); /* COM20020 seems to be slower sometimes */
}
/* clear flags & end reset */
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
/* verify that the ARCnet signature byte is present */
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
com20020_copy_from_card(dev, 0, 0, &inbyte, 1);
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
if (inbyte != TESTvalue) {
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
return 1;
}
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd | EXTconf);
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
/* done! return success. */
return 0;
}
static void com20020_setmask(struct net_device *dev, int mask)
{
u_int ioaddr = dev->base_addr;
BUGMSG(D_DURING, "Setting mask to %x at %x\n",mask,ioaddr);
AINTMASK(mask);
}
static void com20020_command(struct net_device *dev, int cmd)
{
u_int ioaddr = dev->base_addr;
ACOMMAND(cmd);
}
static int com20020_status(struct net_device *dev)
{
u_int ioaddr = dev->base_addr;
return ASTATUS() + (ADIAGSTATUS()<<8);
}
static void com20020_close(struct net_device *dev)
{
struct arcnet_local *lp = dev->priv;
int ioaddr = dev->base_addr;
/* disable transmitter */
lp->config &= ~TXENcfg;
SETCONF;
}
/* 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 = dev->priv;
int ioaddr = dev->base_addr;
if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) { /* Enable promiscuous mode */
if (!(lp->setup & PROMISCset))
BUGMSG(D_NORMAL, "Setting promiscuous flag...\n");
SET_SUBADR(SUB_SETUP1);
lp->setup |= PROMISCset;
outb(lp->setup, _XREG);
} else
/* Disable promiscuous mode, use normal mode */
{
if ((lp->setup & PROMISCset))
BUGMSG(D_NORMAL, "Resetting promiscuous flag...\n");
SET_SUBADR(SUB_SETUP1);
lp->setup &= ~PROMISCset;
outb(lp->setup, _XREG);
}
}
#ifdef MODULE
EXPORT_SYMBOL(com20020_check);
EXPORT_SYMBOL(com20020_found);
MODULE_LICENSE("GPL");
int init_module(void)
{
BUGLVL(D_NORMAL) printk(VERSION);
return 0;
}
void cleanup_module(void)
{
}
#endif /* MODULE */

View File

@@ -0,0 +1,435 @@
/*
* 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
*
* **********************
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/bootmem.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: COM90xx IO-mapped mode support (by David Woodhouse et el.)\n"
/* 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
/* COM 9026 controller chip --> ARCnet register addresses */
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define _RESET (ioaddr+8) /* software reset (on read) */
#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */
#define _ADDR_HI (ioaddr+15) /* Control registers for said */
#define _ADDR_LO (ioaddr+14)
#define _CONFIG (ioaddr+2) /* Configuration register */
#undef ASTATUS
#undef ACOMMAND
#undef AINTMASK
#define ASTATUS() inb(_STATUS)
#define ACOMMAND(cmd) outb((cmd),_COMMAND)
#define AINTMASK(msk) outb((msk),_INTMASK)
#define SETCONF() outb((lp->config),_CONFIG)
/****************************************************************************
* *
* 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;
outb(offset >> 8, _ADDR_HI);
outb(offset & 0xff, _ADDR_LO);
return inb(_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;
outb(offset >> 8, _ADDR_HI);
outb(offset & 0xff, _ADDR_LO);
outb(datum, _MEMDATA);
}
#endif
static void get_whole_buffer(struct net_device *dev, unsigned offset, unsigned length, char *dest)
{
int ioaddr = dev->base_addr;
outb((offset >> 8) | AUTOINCflag, _ADDR_HI);
outb(offset & 0xff, _ADDR_LO);
while (length--)
#ifdef ONE_AT_A_TIME_RX
*(dest++) = get_buffer_byte(dev, offset++);
#else
*(dest++) = inb(_MEMDATA);
#endif
}
static void put_whole_buffer(struct net_device *dev, unsigned offset, unsigned length, char *dest)
{
int ioaddr = dev->base_addr;
outb((offset >> 8) | AUTOINCflag, _ADDR_HI);
outb(offset & 0xff, _ADDR_LO);
while (length--)
#ifdef ONE_AT_A_TIME_TX
put_buffer_byte(dev, offset++, *(dest++));
#else
outb(*(dest++), _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;
BUGLVL(D_NORMAL) printk(VERSION);
BUGLVL(D_NORMAL) printk("E-mail me if you actually test this driver, please!\n");
if (!ioaddr) {
BUGMSG(D_NORMAL, "No autoprobe for IO mapped cards; you "
"must specify the base address!\n");
return -ENODEV;
}
if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com90io probe")) {
BUGMSG(D_INIT_REASONS, "IO check_region %x-%x failed.\n",
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
return -ENXIO;
}
if (ASTATUS() == 0xFF) {
BUGMSG(D_INIT_REASONS, "IO address %x empty\n", ioaddr);
goto err_out;
}
inb(_RESET);
mdelay(RESETtime);
status = ASTATUS();
if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
BUGMSG(D_INIT_REASONS, "Status invalid (%Xh).\n", status);
goto err_out;
}
BUGMSG(D_INIT_REASONS, "Status after reset: %X\n", status);
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
BUGMSG(D_INIT_REASONS, "Status after reset acknowledged: %X\n", status);
status = ASTATUS();
if (status & RESETflag) {
BUGMSG(D_INIT_REASONS, "Eternal reset (status=%Xh)\n", status);
goto err_out;
}
outb((0x16 | IOMAPflag) & ~ENABLE16flag, _CONFIG);
/* Read first loc'n of memory */
outb(AUTOINCflag, _ADDR_HI);
outb(0, _ADDR_LO);
if ((status = inb(_MEMDATA)) != 0xd1) {
BUGMSG(D_INIT_REASONS, "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();
outb(NORXflag, _INTMASK);
udelay(1);
outb(0, _INTMASK);
dev->irq = probe_irq_off(airqmask);
if (dev->irq <= 0) {
BUGMSG(D_INIT_REASONS, "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)) {
BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
return -ENODEV;
}
/* Reserve the I/O region - guaranteed to work by check_region */
if (!request_region(dev->base_addr, ARCNET_TOTAL_SIZE, "arcnet (COM90xx-IO)")) {
free_irq(dev->irq, dev);
return -EBUSY;
}
lp = dev->priv;
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;
SETCONF();
/* 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) {
outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG);
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
return err;
}
BUGMSG(D_NORMAL, "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 = dev->priv;
short ioaddr = dev->base_addr;
BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS());
if (really_reset) {
/* reset the card */
inb(_RESET);
mdelay(RESETtime);
}
/* Set the thing to IO-mapped, 8-bit mode */
lp->config = (0x1C | IOMAPflag) & ~ENABLE16flag;
SETCONF();
ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd | CONFIGclear);
/* verify that the ARCnet signature byte is present */
if (get_buffer_byte(dev, 0) != TESTvalue) {
BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
return 1;
}
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd | EXTconf);
/* done! return success. */
return 0;
}
static void com90io_command(struct net_device *dev, int cmd)
{
short ioaddr = dev->base_addr;
ACOMMAND(cmd);
}
static int com90io_status(struct net_device *dev)
{
short ioaddr = dev->base_addr;
return ASTATUS();
}
static void com90io_setmask(struct net_device *dev, int mask)
{
short ioaddr = dev->base_addr;
AINTMASK(mask);
}
static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count)
{
TIME("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("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(io, int, 0);
module_param(irq, int, 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 */
printk("com90io: 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;
SET_MODULE_OWNER(dev);
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);
/* Set the thing back to MMAP mode, in case the old driver is loaded later */
outb((inb(_CONFIG) & ~IOMAPflag), _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)

View File

@@ -0,0 +1,646 @@
/*
* 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
*
* **********************
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <asm/io.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: COM90xx chipset support\n"
/* 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);
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)
/* COM 9026 controller chip --> ARCnet register addresses */
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define _CONFIG (ioaddr+2) /* Configuration register */
#define _RESET (ioaddr+8) /* software reset (on read) */
#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */
#define _ADDR_HI (ioaddr+15) /* Control registers for said */
#define _ADDR_LO (ioaddr+14)
#undef ASTATUS
#undef ACOMMAND
#undef AINTMASK
#define ASTATUS() inb(_STATUS)
#define ACOMMAND(cmd) outb((cmd),_COMMAND)
#define AINTMASK(msk) outb((msk),_INTMASK)
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(io, int, 0);
module_param(irq, int, 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};
u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] =
{0};
int numports, numshmems, *port;
u_long *p;
if (!io && !irq && !shmem && !*device && com90xx_skip_probe)
return;
BUGLVL(D_NORMAL) printk(VERSION);
/* 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) {
BUGMSG2(D_INIT, "\n");
BUGMSG2(D_INIT, "S1: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
ioaddr = *port;
if (!request_region(*port, ARCNET_TOTAL_SIZE, "arcnet (90xx)")) {
BUGMSG2(D_INIT_REASONS, "(request_region)\n");
BUGMSG2(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port-- = ports[--numports];
continue;
}
if (ASTATUS() == 0xFF) {
BUGMSG2(D_INIT_REASONS, "(empty)\n");
BUGMSG2(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
release_region(*port, ARCNET_TOTAL_SIZE);
*port-- = ports[--numports];
continue;
}
inb(_RESET); /* begin resetting card */
BUGMSG2(D_INIT_REASONS, "\n");
BUGMSG2(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
}
BUGMSG2(D_INIT, "\n");
if (!numports) {
BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n");
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) {
BUGMSG2(D_INIT, "\n");
BUGMSG2(D_INIT, "S2: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
}
BUGMSG2(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 (p = &shmems[0]; p < shmems + numshmems; p++) {
u_long ptr = *p;
numprint++;
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
BUGMSG2(D_INIT, "S3: ");
}
BUGMSG2(D_INIT, "%lXh ", *p);
if (!request_mem_region(*p, BUFFER_SIZE, "arcnet (90xx)")) {
BUGMSG2(D_INIT_REASONS, "(request_mem_region)\n");
BUGMSG2(D_INIT_REASONS, "Stage 3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*p-- = shmems[--numshmems];
continue;
}
if (isa_readb(ptr) != TESTvalue) {
BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n",
isa_readb(ptr), TESTvalue);
BUGMSG2(D_INIT_REASONS, "S3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
release_mem_region(*p, BUFFER_SIZE);
*p-- = shmems[--numshmems];
continue;
}
/* By writing 0x42 to the TESTvalue location, we also make
* sure no "mirror" shmem areas show up - if they occur
* in another pass through this loop, they will be discarded
* because *cptr != TESTvalue.
*/
isa_writeb(0x42, ptr);
if (isa_readb(ptr) != 0x42) {
BUGMSG2(D_INIT_REASONS, "(read only)\n");
BUGMSG2(D_INIT_REASONS, "S3: ");
release_mem_region(*p, BUFFER_SIZE);
*p-- = shmems[--numshmems];
continue;
}
BUGMSG2(D_INIT_REASONS, "\n");
BUGMSG2(D_INIT_REASONS, "S3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
}
BUGMSG2(D_INIT, "\n");
if (!numshmems) {
BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n");
for (port = &ports[0]; port < ports + numports; port++)
release_region(*port, ARCNET_TOTAL_SIZE);
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) {
BUGMSG2(D_INIT, "\n");
BUGMSG2(D_INIT, "S4: ");
}
BUGMSG2(D_INIT, "%lXh ", *p);
}
BUGMSG2(D_INIT, "\n");
/* Stage 5: for any ports that have the correct status, can disable
* the RESET flag, and (if no irq is given) generate an autoirq,
* register an ARCnet device.
*
* Currently, we can only register one device per probe, so quit
* after the first one is found.
*/
numprint = -1;
for (port = &ports[0]; port < ports + numports; port++) {
int found = 0;
numprint++;
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
BUGMSG2(D_INIT, "S5: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
ioaddr = *port;
status = ASTATUS();
if ((status & 0x9D)
!= (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status);
BUGMSG2(D_INIT_REASONS, "S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
release_region(*port, ARCNET_TOTAL_SIZE);
*port-- = ports[--numports];
continue;
}
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
status = ASTATUS();
if (status & RESETflag) {
BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n",
status);
BUGMSG2(D_INIT_REASONS, "S5: ");
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();
AINTMASK(NORXflag);
udelay(1);
AINTMASK(0);
airq = probe_irq_off(airqmask);
if (airq <= 0) {
BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq);
BUGMSG2(D_INIT_REASONS, "S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
release_region(*port, ARCNET_TOTAL_SIZE);
*port-- = ports[--numports];
continue;
}
} else {
airq = irq;
}
BUGMSG2(D_INIT, "(%d,", airq);
openparen = 1;
/* Everything seems okay. But which shmem, if any, puts
* back its signature byte when the card is reset?
*
* If there are multiple cards installed, there might be
* multiple shmems still in the list.
*/
#ifdef FAST_PROBE
if (numports > 1 || numshmems > 1) {
inb(_RESET);
mdelay(RESETtime);
} else {
/* just one shmem and port, assume they match */
isa_writeb(TESTvalue, shmems[0]);
}
#else
inb(_RESET);
mdelay(RESETtime);
#endif
for (p = &shmems[0]; p < shmems + numshmems; p++) {
u_long ptr = *p;
if (isa_readb(ptr) == TESTvalue) { /* found one */
BUGMSG2(D_INIT, "%lXh)\n", *p);
openparen = 0;
/* register the card */
if (com90xx_found(*port, airq, *p) == 0)
found = 1;
numprint = -1;
/* remove shmem from the list */
*p = shmems[--numshmems];
break; /* go to the next I/O port */
} else {
BUGMSG2(D_INIT_REASONS, "%Xh-", isa_readb(ptr));
}
}
if (openparen) {
BUGLVL(D_INIT) printk("no matching shmem)\n");
BUGLVL(D_INIT_REASONS) printk("S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
}
if (!found)
release_region(*port, ARCNET_TOTAL_SIZE);
*port-- = ports[--numports];
}
BUGLVL(D_INIT_REASONS) printk("\n");
/* Now put back TESTvalue on all leftover shmems. */
for (p = &shmems[0]; p < shmems + numshmems; p++) {
isa_writeb(TESTvalue, *p);
release_mem_region(*p, BUFFER_SIZE);
}
}
/* 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)
{
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) {
BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n");
release_mem_region(shmem, BUFFER_SIZE);
return -ENOMEM;
}
lp = dev->priv;
/* 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 (isa_readb(shmem) == TESTvalue
&& isa_readb(shmem - mirror_size) != TESTvalue
&& isa_readb(shmem - 2 * mirror_size) == TESTvalue)
mirror_size *= 2;
first_mirror = last_mirror = shmem;
while (isa_readb(first_mirror) == TESTvalue)
first_mirror -= mirror_size;
first_mirror += mirror_size;
while (isa_readb(last_mirror) == TESTvalue)
last_mirror += mirror_size;
last_mirror -= mirror_size;
dev->mem_start = first_mirror;
dev->mem_end = last_mirror + MIRROR_SIZE - 1;
release_mem_region(shmem, BUFFER_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)) {
BUGMSG(D_NORMAL, "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) {
BUGMSG(D_NORMAL, "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] = readb(lp->mem_start + 1);
dev->base_addr = ioaddr;
BUGMSG(D_NORMAL, "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;
ACOMMAND(cmd);
}
static int com90xx_status(struct net_device *dev)
{
short ioaddr = dev->base_addr;
return ASTATUS();
}
static void com90xx_setmask(struct net_device *dev, int mask)
{
short ioaddr = dev->base_addr;
AINTMASK(mask);
}
/*
* Do a hardware reset on the card, and set up necessary registers.
*
* This should be called as little as possible, because it disrupts the
* token on the network (causes a RECON) and requires a significant delay.
*
* However, it does make sure the card is in a defined state.
*/
int com90xx_reset(struct net_device *dev, int really_reset)
{
struct arcnet_local *lp = dev->priv;
short ioaddr = dev->base_addr;
BUGMSG(D_INIT, "Resetting (status=%02Xh)\n", ASTATUS());
if (really_reset) {
/* reset the card */
inb(_RESET);
mdelay(RESETtime);
}
ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd | CONFIGclear);
/* don't do this until we verify that it doesn't hurt older cards! */
/* outb(inb(_CONFIG) | ENABLE16flag, _CONFIG); */
/* verify that the ARCnet signature byte is present */
if (readb(lp->mem_start) != TESTvalue) {
if (really_reset)
BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
return 1;
}
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd | EXTconf);
/* clean out all the memory to make debugging make more sense :) */
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 = dev->priv;
void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
TIME("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 = dev->priv;
void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
TIME("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 = dev->priv;
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) {
printk("com90xx: Disabled.\n");
return 1;
}
switch (ints[0]) {
default: /* ERROR */
printk("com90xx: 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

View File

@@ -0,0 +1,253 @@
/*
* 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
*
* **********************
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/if_arp.h>
#include <net/arp.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: RFC1051 \"simple standard\" (`s') encapsulation support loaded.\n"
static unsigned short 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);
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)
{
printk(VERSION);
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 unsigned short type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct arcnet_local *lp = dev->priv;
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->mac.raw = skb->data;
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:
lp->stats.rx_errors++;
lp->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 = dev->priv;
struct sk_buff *skb;
struct archdr *pkt = pkthdr;
int ofs;
BUGMSG(D_DURING, "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 == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
lp->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));
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
skb->protocol = type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
}
/*
* 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)
{
struct arcnet_local *lp = dev->priv;
int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;
struct archdr *pkt = (struct archdr *) 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:
BUGMSG(D_NORMAL, "RFC1051: I don't understand protocol %d (%Xh)\n",
type, type);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
return 0;
}
/*
* Set the source hardware address.
*
* This is pretty pointless for most purposes, but it can help in
* debugging. 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 = dev->priv;
struct arc_hardware *hard = &pkt->hard;
int ofs;
BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
length -= ARC_HDR_SIZE; /* hard header is not included in packet length */
if (length > XMTU) {
/* should never happen! other people already check for this. */
BUGMSG(D_NORMAL, "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 */
}

View File

@@ -0,0 +1,549 @@
/*
* 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
*
* **********************
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/arcdevice.h>
MODULE_LICENSE("GPL");
#define VERSION "arcnet: RFC1201 \"standard\" (`a') encapsulation support loaded.\n"
static unsigned short 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);
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)
{
printk(VERSION);
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 unsigned short type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct archdr *pkt = (struct archdr *) skb->data;
struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
struct arcnet_local *lp = dev->priv;
int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
/* Pull off the arcnet header. */
skb->mac.raw = skb->data;
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:
lp->stats.rx_errors++;
lp->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 = dev->priv;
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];
BUGMSG(D_DURING, "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)
BUGMSG(D_DURING, "compensating for exception packet\n");
else {
BUGMSG(D_EXTRA, "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 */
BUGMSG(D_RX, "incoming is not split (splitflag=%d)\n",
soft->split_flag);
if (in->skb) { /* already assembling one! */
BUGMSG(D_EXTRA, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
in->sequence, soft->split_flag, soft->sequence);
lp->rfc1201.aborted_seq = soft->sequence;
dev_kfree_skb_irq(in->skb);
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
in->skb = NULL;
}
in->sequence = soft->sequence;
skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
lp->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? */
BUGMSG(D_EXTRA,
"ARP source address was 00h, set to %02Xh.\n",
saddr);
lp->stats.rx_crc_errors++;
*cptr = saddr;
} else {
BUGMSG(D_DURING, "ARP source address (%Xh) is fine.\n",
*cptr);
}
} else {
BUGMSG(D_NORMAL, "funny-shaped ARP packet. (%Xh, %Xh)\n",
arp->ar_hln, arp->ar_pln);
lp->stats.rx_errors++;
lp->stats.rx_crc_errors++;
}
}
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
skb->protocol = type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
} 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.
*/
BUGMSG(D_RX, "packet is split (splitflag=%d, seq=%d)\n",
soft->split_flag, in->sequence);
if (in->skb && in->sequence != soft->sequence) {
BUGMSG(D_EXTRA, "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;
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
in->lastpacket = in->numpackets = 0;
}
if (soft->split_flag & 1) { /* first packet in split */
BUGMSG(D_RX, "brand new splitpacket (splitflag=%d)\n",
soft->split_flag);
if (in->skb) { /* already assembling one! */
BUGMSG(D_EXTRA, "aborting previous (seq=%d) assembly "
"(splitflag=%d, seq=%d)\n",
in->sequence, soft->split_flag,
soft->sequence);
lp->stats.rx_errors++;
lp->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) {
BUGMSG(D_EXTRA, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
soft->split_flag);
lp->rfc1201.aborted_seq = soft->sequence;
lp->stats.rx_errors++;
lp->stats.rx_length_errors++;
return;
}
in->skb = skb = alloc_skb(508 * in->numpackets + ARC_HDR_SIZE,
GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL, "(split) memory squeeze, dropping packet.\n");
lp->rfc1201.aborted_seq = soft->sequence;
lp->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) {
BUGMSG(D_EXTRA, "can't continue split without starting "
"first! (splitflag=%d, seq=%d, aborted=%d)\n",
soft->split_flag, soft->sequence,
lp->rfc1201.aborted_seq);
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
}
return;
}
in->lastpacket++;
if (packetnum != in->lastpacket) { /* not the right flag! */
/* harmless duplicate? ignore. */
if (packetnum <= in->lastpacket - 1) {
BUGMSG(D_EXTRA, "duplicate splitpacket ignored! (splitflag=%d)\n",
soft->split_flag);
lp->stats.rx_errors++;
lp->stats.rx_frame_errors++;
return;
}
/* "bad" duplicate, kill reassembly */
BUGMSG(D_EXTRA, "out-of-order splitpacket, reassembly "
"(seq=%d) aborted (splitflag=%d, seq=%d)\n",
in->sequence, soft->split_flag, soft->sequence);
lp->rfc1201.aborted_seq = soft->sequence;
dev_kfree_skb_irq(in->skb);
in->skb = NULL;
lp->stats.rx_errors++;
lp->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;
BUGMSG(D_SKB_SIZE, "skb: received %d bytes from %02X (unsplit)\n",
skb->len, pkt->hard.source);
BUGMSG(D_SKB_SIZE, "skb: received %d bytes from %02X (split)\n",
skb->len, pkt->hard.source);
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
skb->protocol = type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
}
}
}
/* 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 = dev->priv;
int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
struct archdr *pkt = (struct archdr *) 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:
BUGMSG(D_NORMAL, "RFC1201: I don't understand protocol %d (%Xh)\n",
type, type);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
return 0;
}
/*
* Set the source hardware address.
*
* This is pretty pointless for most purposes, but it can help in
* debugging. 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 = dev->priv;
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 = 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 = dev->priv;
const int maxsegsize = XMTU - RFC1201_HDR_SIZE;
struct Outgoing *out;
BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
length -= ARC_HDR_SIZE; /* hard header is not included in packet length */
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;
BUGMSG(D_DURING, "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 = dev->priv;
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;
BUGMSG(D_DURING,
"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;
}