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:
140
drivers/net/arcnet/Kconfig
Normal file
140
drivers/net/arcnet/Kconfig
Normal 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
|
||||
|
14
drivers/net/arcnet/Makefile
Normal file
14
drivers/net/arcnet/Makefile
Normal 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
|
204
drivers/net/arcnet/arc-rawmode.c
Normal file
204
drivers/net/arcnet/arc-rawmode.c
Normal 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 */
|
||||
}
|
368
drivers/net/arcnet/arc-rimi.c
Normal file
368
drivers/net/arcnet/arc-rimi.c
Normal 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
1102
drivers/net/arcnet/arcnet.c
Normal file
File diff suppressed because it is too large
Load Diff
296
drivers/net/arcnet/capmode.c
Normal file
296
drivers/net/arcnet/capmode.c
Normal 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;
|
||||
}
|
219
drivers/net/arcnet/com20020-isa.c
Normal file
219
drivers/net/arcnet/com20020-isa.c
Normal 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)
|
189
drivers/net/arcnet/com20020-pci.c
Normal file
189
drivers/net/arcnet/com20020-pci.c
Normal 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)
|
357
drivers/net/arcnet/com20020.c
Normal file
357
drivers/net/arcnet/com20020.c
Normal 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 */
|
435
drivers/net/arcnet/com90io.c
Normal file
435
drivers/net/arcnet/com90io.c
Normal 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)
|
646
drivers/net/arcnet/com90xx.c
Normal file
646
drivers/net/arcnet/com90xx.c
Normal 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
|
253
drivers/net/arcnet/rfc1051.c
Normal file
253
drivers/net/arcnet/rfc1051.c
Normal 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 */
|
||||
}
|
549
drivers/net/arcnet/rfc1201.c
Normal file
549
drivers/net/arcnet/rfc1201.c
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user