Commit 3ddf5291 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.36pre2

parent 8f3af4d1
......@@ -38,13 +38,17 @@ KMod
If you use kmod, you will find it useful to edit /etc/modules.conf.
Here is an example of the lines that need to be added:
post-install parport modprobe -k parport_pc
alias parport_lowlevel parport_pc
options parport_pc io=0x378,0x278 irq=7,auto
KMod will then automatically load parport_pc (with the options
"io=0x378,0x278 irq=7,auto") whenever a parallel port device driver
(such as lp) is loaded.
Note that these are example lines only! You shouldn't in general need
to specify any options to parport_pc in order to be able to use a
parallel port.
Parport probe [optional]
-------------
......
......@@ -146,6 +146,10 @@ ifdef CONFIG_WAN
DRIVERS := $(DRIVERS) drivers/net/wan/wan.a
endif
ifeq ($(CONFIG_ARCNET),y)
DRIVERS := $(DRIVERS) drivers/net/arcnet/arcnet.a
endif
ifdef CONFIG_ATM
DRIVERS := $(DRIVERS) drivers/atm/atm.a
endif
......
......@@ -154,6 +154,12 @@ CONFIG_SKB_LARGE=y
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
#
# Telephony Support
#
# CONFIG_PHONE is not set
# CONFIG_PHONE_IXJ is not set
#
# SCSI support
#
......
......@@ -731,6 +731,7 @@ unsigned long probe_irq_on(void)
{
unsigned int i;
unsigned long delay;
unsigned long val;
/*
* first, enable any unassigned irqs
......@@ -754,6 +755,7 @@ unsigned long probe_irq_on(void)
/*
* Now filter out any obviously spurious interrupts
*/
val = 0;
spin_lock_irq(&irq_controller_lock);
for (i=0; i<NR_IRQS; i++) {
unsigned int status = irq_desc[i].status;
......@@ -766,24 +768,24 @@ unsigned long probe_irq_on(void)
irq_desc[i].status = status & ~IRQ_AUTODETECT;
irq_desc[i].handler->shutdown(i);
}
if (i < 32)
val |= 1 << i;
}
spin_unlock_irq(&irq_controller_lock);
return 0x12345678;
return val;
}
/*
* Return a mask of triggered interrupts (this
* can handle only legacy ISA interrupts).
*/
unsigned int probe_irq_mask(unsigned long unused)
unsigned int probe_irq_mask(unsigned long val)
{
int i;
unsigned int mask;
if (unused != 0x12345678)
printk("Bad IRQ probe from %lx\n", (&unused)[-1]);
mask = 0;
spin_lock_irq(&irq_controller_lock);
for (i = 0; i < 16; i++) {
......@@ -800,20 +802,17 @@ unsigned int probe_irq_mask(unsigned long unused)
}
spin_unlock_irq(&irq_controller_lock);
return mask;
return mask & val;
}
/*
* Return the one interrupt that triggered (this can
* handle any interrupt source)
*/
int probe_irq_off(unsigned long unused)
int probe_irq_off(unsigned long val)
{
int i, irq_found, nr_irqs;
if (unused != 0x12345678)
printk("Bad IRQ probe from %lx\n", (&unused)[-1]);
nr_irqs = 0;
irq_found = 0;
spin_lock_irq(&irq_controller_lock);
......
......@@ -662,11 +662,30 @@ static void lp_console_write (struct console *co, const char *s,
parport_negotiate (port, IEEE1284_MODE_COMPAT);
do {
/* Write the data. */
written = parport_write (port, s, count);
if (written > 0) {
s += written;
count -= written;
/* Write the data, converting LF->CRLF as we go. */
ssize_t canwrite = count;
char *line = strchr (s, '\n');
if (line)
canwrite = line - s;
written = parport_write (port, s, canwrite);
if (written <= 0)
continue;
s += written;
count -= written;
if (line) {
const char *crlf = "\r\n";
int i = 2;
/* Dodge the original '\n', and put '\r\n' instead. */
s++;
count--;
while (i) {
written = parport_write (port, crlf, i);
if (written > 0)
i -= written, crlf += written;
}
}
} while (count > 0 && (CONSOLE_LP_STRICT || written > 0));
......
......@@ -2,20 +2,7 @@
# Network device configuration
#
mainmenu_option next_comment
comment 'ARCnet devices'
tristate 'ARCnet support' CONFIG_ARCNET
if [ "$CONFIG_ARCNET" != "n" ]; then
bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH
bool ' Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051
dep_tristate ' ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET
dep_tristate ' ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET
dep_tristate ' ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET
dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
fi
endmenu
source drivers/net/arcnet/Config.in
tristate 'Dummy net driver support' CONFIG_DUMMY
tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
......
......@@ -17,7 +17,7 @@ obj- :=
SUB_DIRS :=
MOD_SUB_DIRS :=
MOD_IN_SUB_DIRS :=
ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin
ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin arcnet
O_TARGET := net.o
O_OBJS :=
......@@ -27,7 +27,7 @@ MOD_LIST_NAME := NET_MODULES
# All of the (potential) objects that export symbols.
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
export-objs := 8390.o arcnet.o arlan.o aironet4500_core.o aironet4500_card.o ppp_async.o \
export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o ppp_async.o \
ppp_generic.o slhc.o
ifeq ($(CONFIG_PCMCIA),y)
......@@ -96,6 +96,15 @@ else
endif
endif
ifeq ($(CONFIG_ARCNET),y)
SUB_DIRS += arcnet
MOD_IN_SUB_DIRS += arcnet
else
ifeq ($(CONFIG_ARCNET),m)
MOD_IN_SUB_DIRS += arcnet
endif
endif
obj-$(CONFIG_AIRONET4500) += aironet4500_core.o
......@@ -215,11 +224,6 @@ obj-$(CONFIG_APRICOT) += 82596.o
obj-$(CONFIG_MVME16x_NET) += 82596.o
obj-$(CONFIG_BVME6000_NET) += 82596.o
obj-$(CONFIG_DEC_ELCP) += tulip.o
obj-$(CONFIG_ARCNET) += arcnet.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_ETH16I) += eth16i.o
obj-$(CONFIG_EPIC100) += epic100.o
obj-$(CONFIG_ARIADNE2) += ariadne2.o 8390.o
......
/* $Id: arc-rimi.c,v 1.5 1997/11/09 11:04:57 mj Exp $
Derived from the original arcnet.c,
Written 1994-1996 by Avery Pennarun,
which was in turn derived from skeleton.c by Donald Becker.
**********************
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 Public License as
modified by SRC, incorporated herein by reference.
**********************
For more details, see drivers/net/arcnet.c
**********************
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/if_arcnet.h>
#include <linux/arcdevice.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <net/arp.h>
/**************************************************************************/
/* On a fast computer, the buffer copy from memory to the ARCnet card during
* a transmit can hog the bus just a little too long. SLOW_XMIT_COPY
* replaces the fast memcpy() with a slower for() loop that seems to solve
* my problems with ftape.
*
* Probably a better solution would be to use memcpy_toio (more portable
* anyway) and modify that routine to support REALLY_SLOW_IO-style
* defines; ARCnet probably is not the only driver that can screw up an
* ftape DMA transfer.
*
* Turn this on if you have timing-sensitive DMA (ie. a tape drive) and
* would like to sacrifice a little bit of network speed to reduce tape
* write retries or some related problem.
*/
#undef SLOW_XMIT_COPY
/* Internal function declarations */
static int arcrimi_probe(struct net_device *dev);
static void arcrimi_rx(struct net_device *dev,int recbuf);
static int arcrimi_found(struct net_device *dev,int ioaddr,int airq,u_long shmem);
static void arcrimi_inthandler (struct net_device *dev);
static int arcrimi_reset (struct net_device *dev, int reset_delay);
static void arcrimi_setmask (struct net_device *dev, u_char mask);
static void arcrimi_command (struct net_device *dev, u_char command);
static u_char arcrimi_status (struct net_device *dev);
static void arcrimi_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen,
char *data,int length,int daddr,int exceptA, int offset);
static void arcrimi_openclose(int open);
/* Module parameters */
#ifdef MODULE
static int shmem=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
static int irq=0; /* or use the insmod io= irq= shmem= options */
static char *device; /* use eg. device="arc1" to change name */
static int node=0; /* you must specify the node ID for RIM I cards */
MODULE_PARM(shmem, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(device, "s");
MODULE_PARM (node, "i");
#else
void __init arcrimi_setup (char *str, int *ints);
extern struct net_device arcnet_devs[];
extern char arcnet_dev_names[][10];
extern int arcnet_num_devs;
#endif
/* Handy defines for ARCnet specific stuff */
/* COM 9026 controller chip --> ARCnet register addresses */
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define _RESET (ioaddr+8) /* software reset (on read) */
#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 */
#define RDDATAflag 0x00 /* Next access is a read/~write */
#define ARCSTATUS readb(_STATUS)
#define ACOMMAND(cmd) writeb((cmd),_COMMAND)
#define ARCRESET writeb(TESTvalue,ioaddr-0x800) /* fake reset */
#define AINTMASK(msk) writeb((msk),_INTMASK)
#define SETCONF writeb(lp->config,_CONFIG)
static const char *version =
"arc-rimi.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
/****************************************************************************
* *
* Probe and initialization *
* *
****************************************************************************/
/* 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.
*/
int __init arcrimi_probe(struct net_device *dev)
{
BUGLVL(D_NORMAL) printk(version);
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;
}
if (dev->dev_addr[0]==0)
{
BUGMSG(D_NORMAL,"You need to specify your card's station "
"ID!\n");
return -ENODEV;
}
return arcrimi_found(dev,dev->dev_addr[0],dev->irq,dev->mem_start);
}
/* Set up the struct net_device associated with this card. Called after
* probing succeeds.
*/
int __init arcrimi_found(struct net_device *dev,int node,int airq, u_long shmem)
{
struct arcnet_local *lp;
u_long first_mirror,last_mirror;
int mirror_size;
/* reserve the irq */
if (request_irq(airq,&arcnet_interrupt,0,"arcnet (RIM I)",dev))
{
BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq);
return -ENODEV;
}
dev->irq=airq;
dev->base_addr=0;
writeb(TESTvalue,shmem);
writeb(node,shmem+1); /* actually the node ID */
/* find the real shared memory start/end points, including mirrors */
#define BUFFER_SIZE (512)
#define MIRROR_SIZE (BUFFER_SIZE*4)
/* guess the actual size of one "memory mirror" - the number of
* bytes between copies of the shared memory. On most cards, it's
* 2k (or there are no mirrors at all) but on some, it's 4k.
*/
mirror_size=MIRROR_SIZE;
if (readb(shmem)==TESTvalue
&& readb(shmem-mirror_size)!=TESTvalue
&& readb(shmem-2*mirror_size)==TESTvalue)
mirror_size*=2;
first_mirror=last_mirror=shmem;
while (readb(first_mirror)==TESTvalue) first_mirror-=mirror_size;
first_mirror+=mirror_size;
while (readb(last_mirror)==TESTvalue) last_mirror+=mirror_size;
last_mirror-=mirror_size;
dev->mem_start=first_mirror;
dev->mem_end=last_mirror+MIRROR_SIZE-1;
dev->rmem_start=dev->mem_start+BUFFER_SIZE*0;
dev->rmem_end=dev->mem_start+BUFFER_SIZE*2-1;
/* Initialize the rest of the device structure. */
dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (dev->priv == NULL)
{
free_irq(airq,dev);
return -ENOMEM;
}
memset(dev->priv,0,sizeof(struct arcnet_local));
lp=(struct arcnet_local *)(dev->priv);
lp->card_type = ARC_RIM_I;
lp->card_type_str = "RIM I";
lp->arcnet_reset=arcrimi_reset;
lp->asetmask=arcrimi_setmask;
lp->astatus=arcrimi_status;
lp->acommand=arcrimi_command;
lp->openclose_device=arcrimi_openclose;
lp->prepare_tx=arcrimi_prepare_tx;
lp->inthandler=arcrimi_inthandler;
/* Fill in the fields of the device structure with generic
* values.
*/
arcnet_setup(dev);
/* And now fill particular fields with arcnet values */
dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
dev->hard_header_len=sizeof(struct ClientData);
lp->sequence=1;
lp->recbuf=0;
BUGMSG(D_DURING,"ClientData header size is %d.\n",
sizeof(struct ClientData));
BUGMSG(D_DURING,"HardHeader size is %d.\n",
sizeof(struct archdr));
/* get and check the station ID from offset 1 in shmem */
lp->stationid = readb(first_mirror+1);
if (lp->stationid==0)
BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved "
"for broadcasts!\n");
else if (lp->stationid==255)
BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse "
"DOS networking programs!\n");
dev->dev_addr[0]=lp->stationid;
BUGMSG(D_NORMAL,"ARCnet RIM I: station %02Xh found at IRQ %d, "
"ShMem %lXh (%ld*%d bytes).\n",
lp->stationid,
dev->irq, dev->mem_start,
(dev->mem_end-dev->mem_start+1)/mirror_size,mirror_size);
return 0;
}
/* Do a hardware reset on the card, and set up necessary registers.
*
* This should be called as little as possible, because it disrupts the
* token on the network (causes a RECON) and requires a significant delay.
*
* However, it does make sure the card is in a defined state.
*/
int arcrimi_reset(struct net_device *dev,int reset_delay)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
short ioaddr=dev->mem_start + 0x800;
int recbuf=lp->recbuf;
if (reset_delay==3)
{
ARCRESET;
return 0;
}
/* no IRQ's, please! */
lp->intmask=0;
SETMASK;
BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
dev->name,ARCSTATUS);
ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd|CONFIGclear);
/* clear out status variables */
recbuf=lp->recbuf=0;
lp->txbuf=2;
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd|EXTconf);
#ifndef SLOW_XMIT_COPY
/* clean out all the memory to make debugging make more sense :) */
BUGLVL(D_DURING)
memset_io(dev->mem_start,0x42,2048);
#endif
/* and enable receive of our first packet to the first buffer */
EnableReceiver();
/* re-enable interrupts */
lp->intmask|=NORXflag;
#ifdef DETECT_RECONFIGS
lp->intmask|=RECONflag;
#endif
SETMASK;
/* done! return success. */
return 0;
}
static void arcrimi_openclose(int open)
{
if (open)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
static void arcrimi_setmask(struct net_device *dev, u_char mask)
{
int ioaddr=dev->mem_start+0x800;
AINTMASK(mask);
}
static u_char arcrimi_status(struct net_device *dev)
{
int ioaddr=dev->mem_start+0x800;
return ARCSTATUS;
}
static void arcrimi_command(struct net_device *dev, u_char cmd)
{
int ioaddr=dev->mem_start+0x800;
ACOMMAND(cmd);
}
/* The actual interrupt handler routine - handle various IRQ's generated
* by the card.
*/
static void
arcrimi_inthandler(struct net_device *dev)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->mem_start+0x800, status, boguscount = 3, didsomething;
AINTMASK(0);
BUGMSG(D_DURING,"in arcrimi_inthandler (status=%Xh, intmask=%Xh)\n",
ARCSTATUS,lp->intmask);
do
{
status = ARCSTATUS;
didsomething=0;
/* RESET flag was enabled - card is resetting and if RX
* is disabled, it's NOT because we just got a packet.
*/
if (status & RESETflag)
{
BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
status);
arcrimi_reset(dev,0);
/* all other flag values are just garbage */
break;
}
/* RX is inhibited - we must have received something. */
if (status & lp->intmask & NORXflag)
{
int recbuf=lp->recbuf=!lp->recbuf;
BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
status);
/* enable receive of our next packet */
EnableReceiver();
/* Got a packet. */
arcrimi_rx(dev,!recbuf);
didsomething++;
}
/* it can only be an xmit-done irq if we're xmitting :) */
/*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
if (status & lp->intmask & TXFREEflag)
{
struct Outgoing *out=&(lp->outgoing);
int was_sending=lp->sending;
lp->intmask &= ~TXFREEflag;
lp->in_txhandler++;
if (was_sending) lp->sending--;
BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
status,out->numsegs,out->segnum,out->skb);
if (was_sending && !(status&TXACKflag))
{
if (lp->lasttrans_dest != 0)
{
BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n",
status,lp->lasttrans_dest);
lp->stats.tx_errors++;
lp->stats.tx_carrier_errors++;
}
else
{
BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n",
status,
lp->lasttrans_dest);
}
}
/* send packet if there is one */
arcnet_go_tx(dev,0);
didsomething++;
if (lp->intx)
{
BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
ARCSTATUS,lp->intx);
lp->in_txhandler--;
continue;
}
if (!lp->outgoing.skb)
{
BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
lp->in_txhandler--;
continue;
}
/* if more than one segment, and not all segments
* are done, then continue xmit.
*/
if (out->segnum<out->numsegs)
arcnetA_continue_tx(dev);
arcnet_go_tx(dev,0);
/* if segnum==numsegs, the transmission is finished;
* free the skb.
*/
if (out->segnum>=out->numsegs)
{
/* transmit completed */
out->segnum++;
if (out->skb)
{
lp->stats.tx_bytes += out->skb->len;
dev_kfree_skb(out->skb);
}
out->skb=NULL;
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
}
didsomething++;
lp->in_txhandler--;
}
else if (lp->txready && !lp->sending && !lp->intx)
{
BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n",
status);
arcnet_go_tx(dev,0);
didsomething++;
}
#ifdef DETECT_RECONFIGS
if (status & (lp->intmask) & RECONflag)
{
ACOMMAND(CFLAGScmd|CONFIGclear);
lp->stats.tx_carrier_errors++;
#ifdef SHOW_RECONFIGS
BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n",
status);
#endif /* SHOW_RECONFIGS */
#ifdef RECON_THRESHOLD
/* is the RECON info empty or old? */
if (!lp->first_recon || !lp->last_recon ||
jiffies-lp->last_recon > HZ*10)
{
if (lp->network_down)
BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
lp->first_recon=lp->last_recon=jiffies;
lp->num_recons=lp->network_down=0;
BUGMSG(D_DURING,"recon: clearing counters.\n");
}
else /* add to current RECON counter */
{
lp->last_recon=jiffies;
lp->num_recons++;
BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
lp->num_recons,
(lp->last_recon-lp->first_recon)/HZ,
lp->network_down);
/* if network is marked up;
* and first_recon and last_recon are 60+ sec
* apart;
* and the average no. of recons counted is
* > RECON_THRESHOLD/min;
* then print a warning message.
*/
if (!lp->network_down
&& (lp->last_recon-lp->first_recon)<=HZ*60
&& lp->num_recons >= RECON_THRESHOLD)
{
lp->network_down=1;
BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
}
else if (!lp->network_down
&& lp->last_recon-lp->first_recon > HZ*60)
{
/* reset counters if we've gone for
* over a minute.
*/
lp->first_recon=lp->last_recon;
lp->num_recons=1;
}
}
}
else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
{
if (lp->network_down)
BUGMSG(D_NORMAL,"cabling restored?\n");
lp->first_recon=lp->last_recon=0;
lp->num_recons=lp->network_down=0;
BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
#endif
}
#endif /* DETECT_RECONFIGS */
} while (--boguscount && didsomething);
BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
ARCSTATUS,boguscount);
BUGMSG(D_DURING,"\n");
SETMASK; /* put back interrupt mask */
}
/* A packet has arrived; grab it from the buffers and pass it to the generic
* arcnet_rx routing to deal with it.
*/
static void
arcrimi_rx(struct net_device *dev,int recbuf)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr=dev->mem_start+0x800;
union ArcPacket *arcpacket=
(union ArcPacket *)phys_to_virt(dev->mem_start+recbuf*512);
u_char *arcsoft;
short length,offset;
u_char daddr,saddr;
lp->stats.rx_packets++;
saddr=arcpacket->hardheader.source;
/* if source is 0, it's a "used" packet! */
if (saddr==0)
{
BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n",
ARCSTATUS);
lp->stats.rx_errors++;
return;
}
/* Set source address to zero to mark it as old */
arcpacket->hardheader.source=0;
daddr=arcpacket->hardheader.destination;
if (arcpacket->hardheader.offset1) /* Normal Packet */
{
offset=arcpacket->hardheader.offset1;
arcsoft=&arcpacket->raw[offset];
length=256-offset;
}
else /* ExtendedPacket or ExceptionPacket */
{
offset=arcpacket->hardheader.offset2;
arcsoft=&arcpacket->raw[offset];
length=512-offset;
}
arcnet_rx(lp, arcsoft, length, saddr, daddr);
BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx");
#ifndef SLOW_XMIT_COPY
/* clean out the page to make debugging make more sense :) */
BUGLVL(D_DURING)
memset((void *)arcpacket->raw,0x42,512);
#endif
}
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnet_go_tx.
*/
static void
arcrimi_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen,
char *data,int length,int daddr,int exceptA, int offset)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
union ArcPacket *arcpacket =
(union ArcPacket *)phys_to_virt(dev->mem_start+512*(lp->txbuf^1));
#ifdef SLOW_XMIT_COPY
char *iptr,*iend,*optr;
#endif
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
length+=hdrlen;
BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr,length,data);
#ifndef SLOW_XMIT_COPY
/* clean out the page to make debugging make more sense :) */
BUGLVL(D_DURING)
memset_io(dev->mem_start+lp->txbuf*512,0x42,512);
#endif
arcpacket->hardheader.destination=daddr;
/* load packet into shared memory */
if (length<=MTU) /* Normal (256-byte) Packet */
arcpacket->hardheader.offset1=offset=offset?offset:256-length;
else if (length>=MinTU || offset) /* Extended (512-byte) Packet */
{
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=offset?offset:512-length;
}
else if (exceptA) /* RFC1201 Exception Packet */
{
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-length-4;
/* exception-specific stuff - these four bytes
* make the packet long enough to fit in a 512-byte
* frame.
*/
arcpacket->raw[offset+0]=hdr[0];
arcpacket->raw[offset+1]=0xFF; /* FF flag */
arcpacket->raw[offset+2]=0xFF; /* FF padding */
arcpacket->raw[offset+3]=0xFF; /* FF padding */
offset+=4;
}
else /* "other" Exception packet */
{
/* RFC1051 - set 4 trailing bytes to 0 */
memset(&arcpacket->raw[508],0,4);
/* now round up to MinTU */
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-MinTU;
}
/* copy the packet into ARCnet shmem
* - the first bytes of ClientData header are skipped
*/
memcpy((u_char*)arcpacket+offset, (u_char*)hdr,hdrlen);
#ifdef SLOW_XMIT_COPY
for (iptr=data,iend=iptr+length-hdrlen,optr=(char *)arcpacket+offset+hdrlen;
iptr<iend; iptr++,optr++)
{
*optr=*iptr;
/*udelay(5);*/
}
#else
memcpy((u_char*)arcpacket+offset+hdrlen, data,length-hdrlen);
#endif
BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
daddr,length);
BUGLVL(D_TX) arcnet_dump_packet(dev,arcpacket->raw,length>MTU,"tx");
lp->lastload_dest=daddr;
lp->txready=lp->txbuf; /* packet is ready for sending */
}
/****************************************************************************
* *
* Kernel Loadable Module Support *
* *
****************************************************************************/
#ifdef MODULE
static char devicename[9] = "";
static struct net_device thiscard = {
devicename, /* device name is inserted by linux/drivers/net/net_init.c */
0, 0, 0, 0,
0, 0, /* I/O address, IRQ */
0, 0, 0, NULL, arcrimi_probe
};
int init_module(void)
{
struct net_device *dev=&thiscard;
if (device)
strcpy(dev->name,device);
else arcnet_makename(dev->name);
if (node && node != 0xff)
dev->dev_addr[0]=node;
dev->irq=irq;
if (dev->irq==2) dev->irq=9;
if (shmem)
{
dev->mem_start=shmem;
dev->mem_end=thiscard.mem_start+512*4-1;
dev->rmem_start=thiscard.mem_start+512*0;
dev->rmem_end=thiscard.mem_start+512*2-1;
}
if (register_netdev(dev) != 0)
return -EIO;
arcnet_use_count(1);
return 0;
}
void cleanup_module(void)
{
struct net_device *dev=&thiscard;
int ioaddr=dev->mem_start;
if (dev->start) (*dev->stop)(dev);
/* Flush TX and disable RX */
if (ioaddr)
{
AINTMASK(0); /* disable IRQ's */
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
}
if (dev->irq)
{
free_irq(dev->irq,dev);
}
unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
arcnet_use_count(0);
}
#else
void __init arcrimi_setup (char *str, int *ints)
{
struct net_device *dev;
if (arcnet_num_devs == MAX_ARCNET_DEVS)
{
printk("ARCnet RIM I: Too many ARCnet devices registered (max %d).\n",
MAX_ARCNET_DEVS);
return;
}
dev=&arcnet_devs[arcnet_num_devs];
if (ints[0] < 3)
{
printk("ARCnet RIM I: You must give address, IRQ and node ID.\n");
return;
}
dev->init=arcrimi_probe;
switch(ints[0])
{
case 4: /* ERROR */
printk("ARCnet RIM I: Too many arguments.\n");
case 3: /* Node ID */
dev->dev_addr[0]=(u_char)ints[3];
case 2: /* IRQ */
dev->irq=ints[2];
case 1: /* Mem address */
dev->mem_start=ints[1];
}
dev->name = (char *)&arcnet_dev_names[arcnet_num_devs];
if (str)
strncpy(dev->name, str, 9);
arcnet_num_devs++;
}
#endif /* MODULE */
/* $Id: arcnet.c,v 1.34 1997/11/09 11:04:55 mj Exp $
Written 1994-1996 by Avery Pennarun,
derived from skeleton.c by Donald Becker.
**********************
The original copyright was as follows:
skeleton.c Written 1993 by Donald Becker.
Copyright 1993 United States Government as represented by the
Director, National Security Agency. This software may only be used
and distributed according to the terms of the GNU Public License as
modified by SRC, incorporated herein by reference.
**********************
v3.02 (98/06/07)
- Use register_netdevice() instead of register_netdev() to create
new devices for RFC1051 and Ethernet encapsulation in arcnet_open.
Likewise for unregistering them later. This avoids the deadlock
encountered because the original routines call rtnl_lock() when
it's already locked. [dw]
v3.01 (98/04/17)
- Interrupt handler now also checks dev->[se]dev are non-NULL
to avoid crashes in interrupts during card init. [dw]
v3.00 (97/11/09)
- Minor cleanup of debugging messages. [mj]
v2.93 ALPHA (97/11/06)
- irq2dev mapping removed.
- Interrupt handler now checks whether dev->priv is non-null in order
to avoid crashes in interrupts which come during card init. [mj]
v2.92 ALPHA (97/09/02)
- Code cleanup [Martin Mares <mj@atrey.karlin.mff.cuni.cz>]
- Better probing for the COM90xx chipset, although only as
a temporary solution until we implement adding of all found
devices at once. [mj]
v2.91 ALPHA (97/08/19)
- Add counting of octets in/out.
v2.90 ALPHA (97/08/08)
- Add support for kernel command line parsing so that chipset
drivers are usable when compiled in.
v2.80 ALPHA (97/08/01)
- Split source into multiple files; generic arcnet support and
individual chipset drivers. <Dave@imladris.demon.co.uk>
v2.61 ALPHA (97/07/30) by David Woodhouse (Dave@imladris.demon.co.uk)
for Nortel (Northern Telecom).
- Added support for IO-mapped modes and for SMC COM20020 chipset.
- Fixed (avoided) race condition in send_packet routines which was
discovered when the buffer copy routines got slow (?).
- Fixed support for device naming at load time.
- Added backplane, clock and timeout options for COM20020.
- Added support for promiscuous mode.
v2.60 ALPHA (96/11/23)
- Added patch from Vojtech Pavlik <vojtech@suse.cz>
and Martin Mares <mj@k332.feld.cvut.cz> to make the driver work
with the new Linux 2.1.x memory management. I modified their
patch quite a bit though; bugs are my fault. More changes should
be made to get eliminate any remaining phys_to_virt calls.
- Quietly ignore protocol id's 0, 1, 8, and 243. Thanks to Jake
Messinger <jake@ams.com> for reporting these codes and their
meanings.
- Smarter shmem probe for cards with 4k mirrors. (does it work?)
- Initial support for RIM I type cards which use no I/O ports at
all. To use this option, you need to compile with RIM_I_MODE
enabled. Thanks to Kolja Waschk <kawk@yo.com> for explaining
RIM I programming to me. Now, does my RIM I code actually
work?
v2.56 (96/10/18)
- Turned arc0e/arc0s startup messages back on by default, as most
people will probably not notice the additional devices
otherwise. This causes undue confusion.
- Fixed a tiny but noticeable bug in the packet debugging routines
(thanks Tomasz)
The following has been SUMMARIZED. The complete ChangeLog is
available in the full Linux-ARCnet package at
http://www.worldvisions.ca/~apenwarr/arcnet
v2.50 (96/02/24)
- Massively improved autoprobe routines; they now work even as a
module. Thanks to Vojtech Pavlik <vojtech@suse.cz>
for his ideas and help in this area.
- Changed printk's around quite a lot.
v2.22 (95/12/08)
- Major cleanups, speedups, and better code-sharing.
- Eliminated/changed many useless/meaningless/scary debug messages
(and, in most cases, the bugs that caused them).
- Better IPX support.
- lp->stats updated properly.
- RECON checking now by default only prints a message if there are
excessive errors (ie. your cable is probably broken).
- New RFC1051-compliant "arc0s" virtual device by Tomasz
Motylewski.
- Excess debug messages can be compiled out to reduce code size.
v2.00 (95/09/06)
- ARCnet RECON messages are now detected and logged as "carrier"
errors.
- The TXACK flag is now checked, and errors are logged.
- Debug levels are now completely different. See the README.
- Massive code cleanups, with several no-longer-necessary and some
completely useless options removed.
- Multiprotocol support. You can now use the "arc0e" device to
send "Ethernet-Encapsulation" packets, which are compatible with
Windows for Workgroups and LAN Manager, and possibly other
software. See the README for more information.
v1.02 (95/06/21)
- A fix to make "exception" packets sent from Linux receivable
on other systems. (The protocol_id byte was sometimes being set
incorrectly, and Linux wasn't checking it on receive so it
didn't show up)
v1.01 (95/03/24)
- Fixed some IPX-related bugs. (Thanks to Tomasz Motylewski
<motyl@tichy.ch.uj.edu.pl> for the patches to make arcnet work
with dosemu!)
v1.00 (95/02/15)
- Initial non-alpha release.
TO DO: (semi-prioritized)
- Use cleaner "architecture-independent" shared memory access.
This is half-done in ARCnet 2.60, but still uses some
undocumented i386 stuff. (We shouldn't call phys_to_virt,
for example.)
- Allow use of RFC1051 or Ether devices without RFC1201.
- Keep separate stats for each device.
- Support "arpless" mode like NetBSD does, and as recommended
by the (obsoleted) RFC1051.
- Smarter recovery from RECON-during-transmit conditions. (ie.
retransmit immediately)
- Add support for the new 1.3.x IP header cache, and other features.
- Replace setting of debug level with the "metric" flag hack by
something that still exists. SIOCDEVPRIVATE is a good candidate,
but it would require an extra user-level utility.
- What about cards with shared memory that can be "turned off?"
(or that have none at all, like the SMC PC500longboard)
Does this work now, with IO_MAPPED_BUFFERS?
- Autoconfigure PDI5xxPlus cards. (I now have a PDI508Plus to play
with temporarily.) Update: yes, the Pure Data config program
for DOS works fine, but the PDI508Plus I have doesn't! :)
- ATA protocol support??
- VINES TCP/IP encapsulation?? (info needed)
Sources:
- Crynwr arcnet.com/arcether.com packet drivers.
- arcnet.c v0.00 dated 1/1/94 and apparently by
Donald Becker - it didn't work :)
- skeleton.c v0.05 dated 11/16/93 by Donald Becker
(from Linux Kernel 1.1.45)
- RFC's 1201 and 1051 - re: TCP/IP over ARCnet
- The official ARCnet COM9026 data sheets (!) thanks to Ken
Cornetet <kcornete@nyx10.cs.du.edu>
- The official ARCnet COM20020 data sheets.
- Information on some more obscure ARCnet controller chips, thanks
to the nice people at SMC.
- net/inet/eth.c (from kernel 1.1.50) for header-building info.
- Alternate Linux ARCnet source by V.Shergin <vsher@sao.stavropol.su>
- Textual information and more alternate source from Joachim Koenig
<jojo@repas.de>
*/
static const char *version =
"arcnet.c: v3.02 98/06/07 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
#include <linux/module.h>
#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/if_arcnet.h>
#include <linux/arcdevice.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <net/arp.h>
/* Define this if you want to make it easier to use the "call trace" when
* a kernel NULL pointer assignment occurs. Hopefully unnecessary, most of
* the time. It will make all the function names (and other things) show
* up as kernel symbols. (especially handy when using arcnet as a module)
*/
#undef static
/**************************************************************************/
/* These are now provided by the chipset driver. There's a performance
* overhead in using them.
*/
#define AINTMASK(x) ((*lp->asetmask)(dev, x))
#define ARCSTATUS ((*lp->astatus)(dev))
#define ACOMMAND(x) ((*lp->acommand)(dev, x))
int arcnet_debug = ARCNET_DEBUG;
/* Exported function prototypes */
#ifdef MODULE
int init_module(void);
void cleanup_module(void);
#else
int arcnet_init(void);
static int init_module(void);
#ifdef CONFIG_ARCNET_COM90xx
extern char com90xx_explicit;
extern int arc90xx_probe(struct net_device *dev);
#endif
#endif
void arcnet_tx_done(struct net_device *dev, struct arcnet_local *lp);
void arcnet_use_count(int open);
void arcnet_setup(struct net_device *dev);
void arcnet_makename(char *device);
void arcnetA_continue_tx(struct net_device *dev);
int arcnet_go_tx(struct net_device *dev, int enable_irq);
void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
void arcnet_rx(struct arcnet_local *lp, u_char * arcsoft, short length, int saddr, int daddr);
EXPORT_SYMBOL(arcnet_debug);
EXPORT_SYMBOL(arcnet_tx_done);
EXPORT_SYMBOL(arcnet_use_count);
EXPORT_SYMBOL(arcnet_setup);
EXPORT_SYMBOL(arcnet_makename);
EXPORT_SYMBOL(arcnetA_continue_tx);
EXPORT_SYMBOL(arcnet_go_tx);
EXPORT_SYMBOL(arcnet_interrupt);
EXPORT_SYMBOL(arcnet_rx);
#if ARCNET_DEBUG_MAX & D_SKB
void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb,
char *desc);
EXPORT_SYMBOL(arcnet_dump_skb);
#else
#define arcnet_dump_skb(dev,skb,desc) ;
#endif
#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
void arcnet_dump_packet(struct net_device *dev, u_char * buffer, int ext,
char *desc);
EXPORT_SYMBOL(arcnet_dump_packet);
#else
#define arcnet_dump_packet(dev,buffer,ext,desc) ;
#endif
/* Internal function prototypes */
static int arcnet_open(struct net_device *dev);
static int arcnet_close(struct net_device *dev);
static int arcnetA_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr, unsigned len);
static int arcnetA_rebuild_header(struct sk_buff *skb);
static int arcnet_send_packet_bad(struct sk_buff *skb, struct net_device *dev);
static int arcnetA_send_packet(struct sk_buff *skb, struct net_device *dev);
static void arcnetA_rx(struct net_device *dev, u_char * buf,
int length, u_char saddr, u_char daddr);
static struct net_device_stats *arcnet_get_stats(struct net_device *dev);
static unsigned short arcnetA_type_trans(struct sk_buff *skb,
struct net_device *dev);
#ifdef CONFIG_ARCNET_ETH
/* functions specific to Ethernet-Encap */
static int arcnetE_init(struct net_device *dev);
static int arcnetE_open_close(struct net_device *dev);
static int arcnetE_send_packet(struct sk_buff *skb, struct net_device *dev);
static void arcnetE_rx(struct net_device *dev, u_char * arcsoft,
int length, u_char saddr, u_char daddr);
#endif
#ifdef CONFIG_ARCNET_1051
/* functions specific to RFC1051 */
static int arcnetS_init(struct net_device *dev);
static int arcnetS_open_close(struct net_device *dev);
static int arcnetS_send_packet(struct sk_buff *skb, struct net_device *dev);
static void arcnetS_rx(struct net_device *dev, u_char * buf,
int length, u_char saddr, u_char daddr);
static int arcnetS_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr, unsigned len);
static int arcnetS_rebuild_header(struct sk_buff *skb);
static unsigned short arcnetS_type_trans(struct sk_buff *skb, struct net_device *dev);
#endif
/****************************************************************************
* *
* Packet dumps for debugging *
* *
****************************************************************************/
/* Dump the contents of an sk_buff
*/
#if ARCNET_DEBUG_MAX & D_SKB
void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc)
{
int i;
long flags;
save_flags(flags);
cli();
printk(KERN_DEBUG "%6s: skb dump (%s) follows:", dev->name, desc);
for (i = 0; i < skb->len; i++) {
if (i % 16 == 0)
printk("\n" KERN_DEBUG "[%04X] ", i);
printk("%02X ", ((u_char *) skb->data)[i]);
}
printk("\n");
restore_flags(flags);
}
#endif
/* Dump the contents of an ARCnet buffer
*/
#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
void arcnet_dump_packet(struct net_device *dev, u_char * buffer, int ext, char *desc)
{
int i;
long flags;
save_flags(flags);
cli();
printk(KERN_DEBUG "%6s: packet dump (%s) follows:", dev->name, desc);
for (i = 0; i < 256 + (ext != 0) * 256; i++) {
if (i % 16 == 0)
printk("\n" KERN_DEBUG "[%04X] ", i);
printk("%02X ", buffer[i]);
}
printk("\n");
restore_flags(flags);
}
#endif
/* Setup a struct net_device for ARCnet. This should really be in net_init.c
* but since there are three different ARCnet devices ANYWAY... <gargle>
*
* Actually, the whole idea of having all this kernel-dependent stuff (ie.
* "new-style flags") setup per-net-device is kind of weird anyway.
*
* Intelligent defaults?! Nah.
*/
void arcnet_setup(struct net_device *dev)
{
dev_init_buffers(dev);
dev->broadcast[0] = 0x00; /* for us, broadcasts are address 0 */
dev->addr_len = 1;
dev->type = ARPHRD_ARCNET;
dev->tx_queue_len = 30;
/* New-style flags. */
dev->flags = IFF_BROADCAST;
/* Put in this stuff here, so we don't have to export the symbols
* to the chipset drivers.
*/
dev->open = arcnet_open;
dev->stop = arcnet_close;
dev->hard_start_xmit = arcnetA_send_packet;
dev->get_stats = arcnet_get_stats;
dev->hard_header = arcnetA_header;
dev->rebuild_header = arcnetA_rebuild_header;
}
/****************************************************************************
* *
* Open and close the driver *
* *
****************************************************************************/
/* Open/initialize the board. This is called sometime after booting when
* the 'ifconfig' program is run.
*
* This routine should set everything up anew at each open, even
* registers that "should" only need to be set once at boot, so that
* there is non-reboot way to recover if something goes wrong.
*/
static int arcnet_open(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
/* if (dev->metric>=1000)
* {
* arcnet_debug=dev->metric-1000;
* printk(KERN_INFO "%6s: debug level set to %d\n",dev->name,arcnet_debug);
* dev->metric=1;
*}
*/
BUGMSG(D_INIT, "arcnet_open: resetting card.\n");
/* try to put the card in a defined state - if it fails the first
* time, actually reset it.
*/
if ((*lp->arcnet_reset) (dev, 0) && (*lp->arcnet_reset) (dev, 1))
return -ENODEV;
dev->tbusy = 0;
dev->interrupt = 0;
lp->intx = 0;
lp->in_txhandler = 0;
/* The RFC1201 driver is the default - just store */
lp->adev = dev;
/* we're started */
dev->start = 1;
#ifdef CONFIG_ARCNET_ETH
/* Initialize the ethernet-encap protocol driver */
lp->edev = (struct net_device *) kmalloc(sizeof(struct net_device), GFP_KERNEL);
if (lp->edev == NULL)
return -ENOMEM;
memcpy(lp->edev, dev, sizeof(struct net_device));
lp->edev->type = ARPHRD_ETHER;
lp->edev->name = (char *) kmalloc(10, GFP_KERNEL);
if (lp->edev->name == NULL) {
kfree(lp->edev);
lp->edev = NULL;
return -ENOMEM;
}
sprintf(lp->edev->name, "%se", dev->name);
lp->edev->init = arcnetE_init;
register_netdevice(lp->edev);
#endif
#ifdef CONFIG_ARCNET_1051
/* Initialize the RFC1051-encap protocol driver */
lp->sdev = (struct net_device *) kmalloc(sizeof(struct net_device) + 10, GFP_KERNEL);
if (lp->sdev == NULL) {
#ifdef CONFIG_ARCNET_ETH
if (lp->edev)
kfree(lp->edev);
lp->edev = NULL;
return -ENOMEM;
#endif
}
memcpy(lp->sdev, dev, sizeof(struct net_device));
lp->sdev->name = (char *) (lp + 1);
sprintf(lp->sdev->name, "%ss", dev->name);
lp->sdev->init = arcnetS_init;
register_netdevice(lp->sdev);
#endif
/* Enable TX if we need to */
if (lp->en_dis_able_TX)
(*lp->en_dis_able_TX) (dev, 1);
/* make sure we're ready to receive IRQ's.
* arcnet_reset sets this for us, but if we receive one before
* START is set to 1, it could be ignored. So, we turn IRQ's
* off, then on again to clean out the IRQ controller.
*/
AINTMASK(0);
udelay(1); /* give it time to set the mask before
* we reset it again. (may not even be
* necessary)
*/
SETMASK;
/* Let it increase its use count */
(*lp->openclose_device) (1);
return 0;
}
/* The inverse routine to arcnet_open - shuts down the card.
*/
static int arcnet_close(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
if (test_and_set_bit(0, (int *) &dev->tbusy))
BUGMSG(D_NORMAL, "arcnet_close: tbusy already set!\n");
dev->start = 0;
#ifdef CONFIG_ARCNET_1051
lp->sdev->tbusy = 1;
lp->sdev->start = 0;
#endif
#ifdef CONFIG_ARCNET_ETH
lp->edev->tbusy = 1;
lp->edev->start = 0;
#endif
/* Shut down the card */
/* Disable TX if we need to */
if (lp->en_dis_able_TX)
(*lp->en_dis_able_TX) (dev, 0);
(*lp->arcnet_reset) (dev, 3); /* reset IRQ won't run if START=0 */
#if 0
lp->intmask = 0;
SETMASK; /* no IRQ's (except RESET, of course) */
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
#endif
/* reset more flags */
dev->interrupt = 0;
#ifdef CONFIG_ARCNET_ETH
lp->edev->interrupt = 0;
#endif
#ifdef CONFIG_ARCNET_1051
lp->sdev->interrupt = 0;
#endif
/* do NOT free lp->adev!! It's static! */
lp->adev = NULL;
#ifdef CONFIG_ARCNET_ETH
/* free the ethernet-encap protocol device */
lp->edev->priv = NULL;
unregister_netdevice(lp->edev);
kfree(lp->edev->name);
kfree(lp->edev);
lp->edev = NULL;
#endif
#ifdef CONFIG_ARCNET_1051
/* free the RFC1051-encap protocol device */
lp->sdev->priv = NULL;
unregister_netdevice(lp->sdev);
kfree(lp->sdev);
lp->sdev = NULL;
#endif
/* Update the statistics here. (not necessary in ARCnet) */
/* Decrease the use count */
(*lp->openclose_device) (0);
return 0;
}
/****************************************************************************
* *
* Transmitter routines *
* *
****************************************************************************/
/* Generic error checking routine for arcnet??_send_packet
*/
static int arcnet_send_packet_bad(struct sk_buff *skb, struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
BUGMSG(D_DURING, "transmit requested (status=%Xh, inTX=%d)\n",
ARCSTATUS, lp->intx);
if (lp->in_txhandler) {
BUGMSG(D_NORMAL, "send_packet called while in txhandler!\n");
lp->stats.tx_dropped++;
return 1;
}
if (lp->intx > 1) {
BUGMSG(D_NORMAL, "send_packet called while intx!\n");
lp->stats.tx_dropped++;
return 1;
}
if (test_bit(0, (int *) &dev->tbusy)) {
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
int tickssofar = jiffies - dev->trans_start;
int status = ARCSTATUS;
if (tickssofar < TX_TIMEOUT) {
BUGMSG(D_DURING, "premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n",
status, tickssofar, lp->outgoing.skb,
lp->outgoing.numsegs,
lp->outgoing.segnum);
return 1;
}
lp->intmask &= ~TXFREEflag;
SETMASK;
if (status & TXFREEflag) { /* transmit _DID_ finish */
BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n",
status, tickssofar, lp->intmask, lp->lasttrans_dest);
lp->stats.tx_errors++;
} else {
BUGMSG(D_EXTRA, "tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n",
status, tickssofar, lp->intmask, lp->lasttrans_dest);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
ACOMMAND(NOTXcmd);
}
if (lp->outgoing.skb) {
dev_kfree_skb(lp->outgoing.skb);
lp->stats.tx_dropped++;
}
lp->outgoing.skb = NULL;
#ifdef CONFIG_ARCNET_ETH
lp->edev->tbusy = 0;
#endif
#ifdef CONFIG_ARCNET_1051
lp->sdev->tbusy = 0;
#endif
if (!test_and_clear_bit(0, (int *) &dev->tbusy))
BUGMSG(D_EXTRA, "after timing out, tbusy was clear!\n");
lp->txready = 0;
lp->sending = 0;
return 1;
}
if (lp->txready) { /* transmit already in progress! */
BUGMSG(D_NORMAL, "trying to start new packet while busy! (status=%Xh)\n",
ARCSTATUS);
lp->intmask &= ~TXFREEflag;
SETMASK;
ACOMMAND(NOTXcmd); /* abort current send */
(*lp->inthandler) (dev); /* fake an interrupt */
lp->stats.tx_errors++;
lp->stats.tx_fifo_errors++;
lp->txready = 0; /* we definitely need this line! */
return 1;
}
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (test_and_set_bit(0, (int *) &lp->adev->tbusy)) {
BUGMSG(D_NORMAL, "transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
ARCSTATUS, lp->intx, jiffies - dev->trans_start);
lp->stats.tx_errors++;
lp->stats.tx_fifo_errors++;
return -EBUSY;
}
#ifdef CONFIG_ARCNET_1051
lp->sdev->tbusy = 1;
#endif
#ifdef CONFIG_ARCNET_ETH
lp->edev->tbusy = 1;
#endif
return 0;
}
/* Called by the kernel in order to transmit a packet.
*/
static int arcnetA_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
int bad, oldmask = 0;
struct Outgoing *out = &(lp->outgoing);
lp->intx++;
oldmask |= lp->intmask;
lp->intmask = 0;
SETMASK;
bad = arcnet_send_packet_bad(skb, dev);
if (bad) {
lp->intx--;
lp->intmask = oldmask;
SETMASK;
return bad;
}
/* arcnet_send_packet_pad has already set tbusy - don't bother here. */
lp->intmask = oldmask & ~TXFREEflag;
SETMASK;
out->length = 1 < skb->len ? skb->len : 1;
out->hdr = (struct ClientData *) skb->data;
out->skb = skb;
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx");
out->hdr->sequence = (lp->sequence++);
/* fits in one packet? */
if (out->length - EXTRA_CLIENTDATA <= XMTU) {
BUGMSG(D_DURING, "not splitting %d-byte packet. (split_flag=%d)\n",
out->length, out->hdr->split_flag);
if (out->hdr->split_flag)
BUGMSG(D_NORMAL, "short packet has split_flag set?! (split_flag=%d)\n",
out->hdr->split_flag);
out->numsegs = 1;
out->segnum = 1;
(*lp->prepare_tx) (dev,
((char *) out->hdr) + EXTRA_CLIENTDATA,
sizeof(struct ClientData) - EXTRA_CLIENTDATA,
((char *) skb->data) + sizeof(struct ClientData),
out->length - sizeof(struct ClientData),
out->hdr->daddr, 1, 0);
/* done right away */
lp->stats.tx_bytes += out->skb->len;
dev_kfree_skb(out->skb);
out->skb = NULL;
if (arcnet_go_tx(dev, 1)) {
/* inform upper layers */
arcnet_tx_done(dev, lp);
}
} else { /* too big for one - split it */
int maxsegsize = XMTU - 4;
out->data = (u_char *) skb->data
+ sizeof(struct ClientData);
out->dataleft = out->length - sizeof(struct ClientData);
out->numsegs = (out->dataleft + maxsegsize - 1) / maxsegsize;
out->segnum = 0;
BUGMSG(D_TX, "packet (%d bytes) split into %d fragments:\n",
out->length, out->numsegs);
/* if a packet waiting, launch it */
arcnet_go_tx(dev, 1);
if (!lp->txready) {
/* prepare a packet, launch it and prepare
* another.
*/
arcnetA_continue_tx(dev);
if (arcnet_go_tx(dev, 1)) {
arcnetA_continue_tx(dev);
arcnet_go_tx(dev, 1);
}
}
/* if segnum==numsegs, the transmission is finished;
* free the skb right away.
*/
if (out->segnum == out->numsegs) {
/* transmit completed */
out->segnum++;
if (out->skb) {
lp->stats.tx_bytes += skb->len;
dev_kfree_skb(out->skb);
}
out->skb = NULL;
}
}
dev->trans_start = jiffies;
lp->intx--;
/* make sure we didn't ignore a TX IRQ while we were in here */
lp->intmask |= TXFREEflag;
SETMASK;
return 0;
}
/* After an RFC1201 split packet has been set up, this function calls
* arcnetAS_prepare_tx to load the next segment into the card. This function
* does NOT automatically call arcnet_go_tx.
*/
void arcnetA_continue_tx(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
int maxsegsize = XMTU - 4;
struct Outgoing *out = &(lp->outgoing);
BUGMSG(D_DURING, "continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n",
ARCSTATUS, lp->intx, lp->in_txhandler, lp->intmask);
if (lp->txready) {
BUGMSG(D_NORMAL, "continue_tx: called with packet in buffer!\n");
return;
}
if (out->segnum >= out->numsegs) {
BUGMSG(D_NORMAL, "continue_tx: building segment %d of %d!\n",
out->segnum + 1, out->numsegs);
}
if (!out->segnum) /* first packet */
out->hdr->split_flag = ((out->numsegs - 2) << 1) + 1;
else
out->hdr->split_flag = out->segnum << 1;
out->seglen = maxsegsize;
if (out->seglen > out->dataleft)
out->seglen = out->dataleft;
BUGMSG(D_TX, "building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n",
out->segnum + 1, out->seglen, out->numsegs,
out->length, out->hdr->split_flag);
(*lp->prepare_tx) (dev, ((char *) out->hdr) + EXTRA_CLIENTDATA,
sizeof(struct ClientData) - EXTRA_CLIENTDATA,
out->data, out->seglen, out->hdr->daddr, 1, 0);
out->dataleft -= out->seglen;
out->data += out->seglen;
out->segnum++;
}
/* Actually start transmitting a packet that was placed in the card's
* buffer by arcnetAS_prepare_tx. Returns 1 if a Tx is really started.
*
* This should probably always be called with the INTMASK register set to 0,
* so go_tx is not called recursively.
*
* The enable_irq flag determines whether to actually write INTMASK value
* to the card; TXFREEflag is always OR'ed into the memory variable either
* way.
*/
int arcnet_go_tx(struct net_device *dev, int enable_irq)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, txready=%d, sending=%d\n",
ARCSTATUS, lp->intmask, lp->txready, lp->sending);
if (lp->sending || !lp->txready) {
if (enable_irq && lp->sending) {
lp->intmask |= TXFREEflag;
SETMASK;
}
return 0;
}
/* start sending */
ACOMMAND(TXcmd | (lp->txready << 3));
lp->stats.tx_packets++;
lp->txready = 0;
lp->sending++;
lp->lasttrans_dest = lp->lastload_dest;
lp->lastload_dest = 0;
lp->intmask |= TXFREEflag;
if (enable_irq)
SETMASK;
return 1;
}
/****************************************************************************
* *
* Interrupt handler *
* *
****************************************************************************/
/* The typical workload of the driver: Handle the network interface
* interrupts. Establish which device needs attention, and call the correct
* chipset interrupt handler.
*/
void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct arcnet_local *lp;
if (dev == NULL) {
BUGMSG(D_DURING, "arcnet: irq %d for unknown device.\n", irq);
return;
}
BUGMSG(D_DURING, "in arcnet_interrupt\n");
lp = (struct arcnet_local *) dev->priv;
if (!lp) {
BUGMSG(D_DURING, "arcnet: irq ignored.\n");
return;
}
/* RESET flag was enabled - if !dev->start, we must clear it right
* away (but nothing else) since inthandler() is never called.
*/
if (!dev->start) {
if (ARCSTATUS & RESETflag)
ACOMMAND(CFLAGScmd | RESETclear);
return;
}
if (test_and_set_bit(0, (int *) &dev->interrupt)) {
BUGMSG(D_NORMAL, "DRIVER PROBLEM! Nested arcnet interrupts!\n");
return; /* don't even try. */
}
#ifdef CONFIG_ARCNET_1051
if (lp->sdev)
lp->sdev->interrupt = 1;
#endif
#ifdef CONFIG_ARCNET_ETH
if (lp->edev)
lp->edev->interrupt = 1;
#endif
/* Call the "real" interrupt handler. */
(*lp->inthandler) (dev);
#ifdef CONFIG_ARCNET_ETH
if (lp->edev)
lp->edev->interrupt = 0;
#endif
#ifdef CONFIG_ARCNET_1051
if (lp->sdev)
lp->sdev->interrupt = 0;
#endif
if (!test_and_clear_bit(0, (int *) &dev->interrupt))
BUGMSG(D_NORMAL, "Someone cleared our dev->interrupt flag!\n");
}
void arcnet_tx_done(struct net_device *dev, struct arcnet_local *lp)
{
if (dev->tbusy) {
#ifdef CONFIG_ARCNET_ETH
lp->edev->tbusy = 0;
#endif
#ifdef CONFIG_ARCNET_1051
lp->sdev->tbusy = 0;
#endif
if (!test_and_clear_bit(0, (int *) &dev->tbusy))
BUGMSG(D_NORMAL, "In arcnet_tx_done: Someone cleared our dev->tbusy"
" flag!\n");
mark_bh(NET_BH);
}
}
/****************************************************************************
* *
* Receiver routines *
* *
****************************************************************************/
/*
* This is a generic packet receiver that calls arcnet??_rx depending on the
* protocol ID found.
*/
void arcnet_rx(struct arcnet_local *lp, u_char * arcsoft, short length, int saddr, int daddr)
{
struct net_device *dev = lp->adev;
BUGMSG(D_DURING, "received packet from %02Xh to %02Xh (%d bytes)\n",
saddr, daddr, length);
/* call the right receiver for the protocol */
switch (arcsoft[0]) {
case ARC_P_IP:
case ARC_P_ARP:
case ARC_P_RARP:
case ARC_P_IPX:
case ARC_P_NOVELL_EC:
arcnetA_rx(lp->adev, arcsoft, length, saddr, daddr);
break;
#ifdef CONFIG_ARCNET_ETH
case ARC_P_ETHER:
arcnetE_rx(lp->edev, arcsoft, length, saddr, daddr);
break;
#endif
#ifdef CONFIG_ARCNET_1051
case ARC_P_IP_RFC1051:
case ARC_P_ARP_RFC1051:
arcnetS_rx(lp->sdev, arcsoft, length, saddr, daddr);
break;
#endif
case ARC_P_DATAPOINT_BOOT:
case ARC_P_DATAPOINT_MOUNT:
break;
case ARC_P_POWERLAN_BEACON:
case ARC_P_POWERLAN_BEACON2:
break;
case ARC_P_LANSOFT: /* don't understand. fall through. */
default:
BUGMSG(D_EXTRA, "received unknown protocol %d (%Xh) from station %d.\n",
arcsoft[0], arcsoft[0], saddr);
lp->stats.rx_errors++;
lp->stats.rx_crc_errors++;
break;
}
/* If any worth-while packets have been received, a mark_bh(NET_BH)
* has been done by netif_rx and Linux will handle them after we
* return.
*/
}
/* Packet receiver for "standard" RFC1201-style packets
*/
static void arcnetA_rx(struct net_device *dev, u_char * buf,
int length, u_char saddr, u_char daddr)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
struct sk_buff *skb;
struct ClientData *arcsoft, *soft;
BUGMSG(D_DURING, "it's an RFC1201 packet (length=%d)\n",
length);
/* compensate for EXTRA_CLIENTDATA (which isn't actually in the
* packet)
*/
arcsoft = (struct ClientData *) (buf - EXTRA_CLIENTDATA);
length += EXTRA_CLIENTDATA;
if (arcsoft->split_flag == 0xFF) { /* Exception Packet */
BUGMSG(D_DURING, "compensating for exception packet\n");
/* skip over 4-byte junkola */
arcsoft = (struct ClientData *)
((u_char *) arcsoft + 4);
length -= 4;
}
if (!arcsoft->split_flag) { /* not split */
struct Incoming *in = &lp->incoming[saddr];
BUGMSG(D_RX, "incoming is not split (splitflag=%d)\n",
arcsoft->split_flag);
if (in->skb) { /* already assembling one! */
BUGMSG(D_EXTRA, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
in->sequence, arcsoft->split_flag,
arcsoft->sequence);
lp->aborted_seq = arcsoft->sequence;
kfree_skb(in->skb);
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
in->skb = NULL;
}
in->sequence = arcsoft->sequence;
skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
lp->stats.rx_dropped++;
return;
}
soft = (struct ClientData *) skb->data;
skb_put(skb, length);
skb->dev = dev;
memcpy((u_char *) soft + EXTRA_CLIENTDATA,
(u_char *) arcsoft + EXTRA_CLIENTDATA,
length - EXTRA_CLIENTDATA);
soft->daddr = daddr;
soft->saddr = saddr;
/* ARP packets have problems when sent from DOS.
* source address is always 0 on some systems! So we take
* the hardware source addr (which is impossible to fumble)
* and insert it ourselves.
*/
if (soft->protocol_id == ARC_P_ARP) {
struct arphdr *arp = (struct arphdr *)
((char *) soft + sizeof(struct ClientData));
/* make sure addresses are the right length */
if (arp->ar_hln == 1 && arp->ar_pln == 4) {
char *cptr = (char *) (arp) + sizeof(struct arphdr);
if (!*cptr) { /* is saddr = 00? */
BUGMSG(D_EXTRA, "ARP source address was 00h, set to %02Xh.\n",
saddr);
lp->stats.rx_crc_errors++;
*cptr = saddr;
} else {
BUGMSG(D_DURING, "ARP source address (%Xh) is fine.\n",
*cptr);
}
} else {
BUGMSG(D_NORMAL, "funny-shaped ARP packet. (%Xh, %Xh)\n",
arp->ar_hln, arp->ar_pln);
lp->stats.rx_errors++;
lp->stats.rx_crc_errors++;
}
}
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
lp->stats.rx_bytes += skb->len;
skb->protocol = arcnetA_type_trans(skb, dev);
netif_rx(skb);
} else { /* split packet */
/* NOTE: MSDOS ARP packet correction should only need to
* apply to unsplit packets, since ARP packets are so short.
*
* My interpretation of the RFC1201 (ARCnet) document is that
* if a packet is received out of order, the entire assembly
* process should be aborted.
*
* The RFC also mentions "it is possible for successfully
* received packets to be retransmitted." As of 0.40 all
* previously received packets are allowed, not just the
* most recent one.
*
* We allow multiple assembly processes, one for each
* ARCnet card possible on the network. Seems rather like
* a waste of memory. Necessary?
*/
struct Incoming *in = &lp->incoming[saddr];
BUGMSG(D_RX, "packet is split (splitflag=%d, seq=%d)\n",
arcsoft->split_flag, in->sequence);
if (in->skb && in->sequence != arcsoft->sequence) {
BUGMSG(D_EXTRA, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
saddr, in->sequence, arcsoft->sequence,
arcsoft->split_flag);
kfree_skb(in->skb);
in->skb = NULL;
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
in->lastpacket = in->numpackets = 0;
}
if (arcsoft->split_flag & 1) { /* first packet in split */
BUGMSG(D_RX, "brand new splitpacket (splitflag=%d)\n",
arcsoft->split_flag);
if (in->skb) { /* already assembling one! */
BUGMSG(D_EXTRA, "aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
in->sequence, arcsoft->split_flag,
arcsoft->sequence);
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
kfree_skb(in->skb);
}
in->sequence = arcsoft->sequence;
in->numpackets = ((unsigned) arcsoft->split_flag >> 1) + 2;
in->lastpacket = 1;
if (in->numpackets > 16) {
BUGMSG(D_EXTRA, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
arcsoft->split_flag);
lp->stats.rx_errors++;
lp->stats.rx_length_errors++;
return;
}
in->skb = skb = alloc_skb(508 * in->numpackets
+ sizeof(struct ClientData),
GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL, "(split) memory squeeze, dropping packet.\n");
lp->stats.rx_dropped++;
return;
}
soft = (struct ClientData *) skb->data;
skb_put(skb, sizeof(struct ClientData));
skb->dev = dev;
memcpy((u_char *) soft + EXTRA_CLIENTDATA,
(u_char *) arcsoft + EXTRA_CLIENTDATA,
sizeof(struct ClientData) - EXTRA_CLIENTDATA);
soft->split_flag = 0; /* final packet won't be split */
} else { /* not first packet */
int packetnum = ((unsigned) arcsoft->split_flag >> 1) + 1;
/* if we're not assembling, there's no point
* trying to continue.
*/
if (!in->skb) {
if (lp->aborted_seq != arcsoft->sequence) {
BUGMSG(D_EXTRA, "can't continue split without starting first! (splitflag=%d, seq=%d, aborted=%d)\n",
arcsoft->split_flag, arcsoft->sequence, lp->aborted_seq);
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
}
return;
}
in->lastpacket++;
if (packetnum != in->lastpacket) { /* not the right flag! */
/* harmless duplicate? ignore. */
if (packetnum <= in->lastpacket - 1) {
BUGMSG(D_EXTRA, "duplicate splitpacket ignored! (splitflag=%d)\n",
arcsoft->split_flag);
lp->stats.rx_errors++;
lp->stats.rx_frame_errors++;
return;
}
/* "bad" duplicate, kill reassembly */
BUGMSG(D_EXTRA, "out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
in->sequence, arcsoft->split_flag,
arcsoft->sequence);
lp->aborted_seq = arcsoft->sequence;
kfree_skb(in->skb);
in->skb = NULL;
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
in->lastpacket = in->numpackets = 0;
return;
}
soft = (struct ClientData *) in->skb->data;
}
skb = in->skb;
memcpy(skb->data + skb->len,
(u_char *) arcsoft + sizeof(struct ClientData),
length - sizeof(struct ClientData));
skb_put(skb, length - sizeof(struct ClientData));
soft->daddr = daddr;
soft->saddr = saddr;
/* are we done? */
if (in->lastpacket == in->numpackets) {
if (!skb || !in->skb) {
BUGMSG(D_NORMAL, "?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n",
skb, in->skb);
} else {
in->skb = NULL;
in->lastpacket = in->numpackets = 0;
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
lp->stats.rx_bytes += skb->len;
skb->protocol = arcnetA_type_trans(skb, dev);
netif_rx(skb);
}
}
}
}
/****************************************************************************
* *
* Miscellaneous routines *
* *
****************************************************************************/
/* Get the current statistics. This may be called with the card open or
* closed.
*/
static struct net_device_stats *arcnet_get_stats(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
return &lp->stats;
}
/* Create the ARCnet ClientData header for an arbitrary protocol layer
* saddr=NULL means use device source address (always will anyway)
* daddr=NULL means leave destination address (eg unresolved arp)
*/
static int arcnetA_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr, unsigned len)
{
struct ClientData *head = (struct ClientData *)
skb_push(skb, dev->hard_header_len);
struct arcnet_local *lp = (struct arcnet_local *) (dev->priv);
BUGMSG(D_DURING, "create header from %d to %d; protocol %d (%Xh); size %u.\n",
saddr ? *(u_char *) saddr : -1,
daddr ? *(u_char *) daddr : -1,
type, type, len);
/* set the protocol ID according to RFC1201 */
switch (type) {
case ETH_P_IP:
head->protocol_id = ARC_P_IP;
break;
case ETH_P_ARP:
head->protocol_id = ARC_P_ARP;
break;
case ETH_P_RARP:
head->protocol_id = ARC_P_RARP;
break;
case ETH_P_IPX:
case ETH_P_802_3:
case ETH_P_802_2:
head->protocol_id = ARC_P_IPX;
break;
case ETH_P_ATALK:
head->protocol_id = ARC_P_ATALK;
break;
default:
BUGMSG(D_NORMAL, "I don't understand protocol %d (%Xh)\n",
type, type);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
return 0;
}
/*
* Set the source hardware address.
*
* This is pretty pointless for most purposes, but it can help
* in debugging. saddr is stored in the ClientData header and
* removed before sending the packet (since ARCnet does not allow
* us to change the source address in the actual packet sent)
*/
if (saddr)
head->saddr = ((u_char *) saddr)[0];
else
head->saddr = ((u_char *) (dev->dev_addr))[0];
head->split_flag = 0; /* split packets are done elsewhere */
head->sequence = 0; /* so are sequence numbers */
/* supposedly if daddr is NULL, we should ignore it... */
if (daddr) {
head->daddr = ((u_char *) daddr)[0];
return dev->hard_header_len;
} else
head->daddr = 0; /* better fill one in anyway */
return -dev->hard_header_len;
}
/* Rebuild the ARCnet ClientData header. This is called after an ARP
* (or in future other address resolution) has completed on this
* sk_buff. We now let ARP fill in the other fields.
*/
static int arcnetA_rebuild_header(struct sk_buff *skb)
{
struct ClientData *head = (struct ClientData *) skb->data;
struct net_device *dev = skb->dev;
struct arcnet_local *lp = (struct arcnet_local *) (dev->priv);
#ifdef CONFIG_INET
int status;
#endif
/*
* Only ARP and IP are currently supported
*
* FIXME: Anyone want to spec IPv6 over ARCnet ?
*/
if (head->protocol_id != ARC_P_IP) {
BUGMSG(D_NORMAL, "I don't understand protocol type %d (%Xh) addresses!\n",
head->protocol_id, head->protocol_id);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
head->daddr = 0;
/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len); */
return 0;
}
/*
* Try to get ARP to resolve the header.
*/
#ifdef CONFIG_INET
BUGMSG(D_DURING, "rebuild header from %d to %d; protocol %Xh\n",
head->saddr, head->daddr, head->protocol_id);
status = arp_find(&(head->daddr), skb) ? 1 : 0;
BUGMSG(D_DURING, " rebuilt: from %d to %d; protocol %Xh\n",
head->saddr, head->daddr, head->protocol_id);
return status;
#else
return 0;
#endif
}
/* Determine a packet's protocol ID.
* With ARCnet we have to convert everything to Ethernet-style stuff.
*/
static unsigned short arcnetA_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ClientData *head;
struct arcnet_local *lp = (struct arcnet_local *) (dev->priv);
/* Pull off the arcnet header. */
skb->mac.raw = skb->data;
skb_pull(skb, dev->hard_header_len);
head = (struct ClientData *) skb->mac.raw;
if (head->daddr == 0)
skb->pkt_type = PACKET_BROADCAST;
else if (dev->flags & IFF_PROMISC) {
/* if we're not sending to ourselves :) */
if (head->daddr != dev->dev_addr[0])
skb->pkt_type = PACKET_OTHERHOST;
}
/* now return the protocol number */
switch (head->protocol_id) {
case ARC_P_IP:
return htons(ETH_P_IP);
case ARC_P_ARP:
return htons(ETH_P_ARP);
case ARC_P_RARP:
return htons(ETH_P_RARP);
case ARC_P_IPX:
case ARC_P_NOVELL_EC:
return htons(ETH_P_802_3);
default:
lp->stats.rx_errors++;
lp->stats.rx_crc_errors++;
return 0;
}
return htons(ETH_P_IP);
}
#ifdef CONFIG_ARCNET_ETH
/****************************************************************************
* *
* Ethernet-Encap Support *
* *
****************************************************************************/
/* Initialize the arc0e device.
*/
static int arcnetE_init(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
ether_setup(dev); /* we're emulating ether here, not ARCnet */
dev->dev_addr[0] = 0;
dev->dev_addr[5] = lp->stationid;
dev->mtu = 512 - sizeof(struct archdr) - dev->hard_header_len - 1;
dev->open = arcnetE_open_close;
dev->stop = arcnetE_open_close;
dev->hard_start_xmit = arcnetE_send_packet;
return 0;
}
/* Bring up/down the arc0e device - we don't actually have to do anything,
* since our parent arc0 handles the card I/O itself.
*/
static int arcnetE_open_close(struct net_device *dev)
{
return 0;
}
/* Called by the kernel in order to transmit an ethernet-type packet.
*/
static int arcnetE_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
int bad, oldmask = 0;
u_char daddr;
short offset, length = skb->len + 1;
u_char proto = ARC_P_ETHER;
lp->intx++;
oldmask |= lp->intmask;
lp->intmask = 0;
SETMASK;
bad = arcnet_send_packet_bad(skb, dev);
if (bad) {
lp->intx--;
lp->intmask = oldmask;
SETMASK;
return bad;
}
/* arcnet_send_packet_pad has already set tbusy - don't bother here. */
lp->intmask = oldmask;
SETMASK;
if (length > XMTU) {
BUGMSG(D_NORMAL, "MTU must be <= 493 for ethernet encap (length=%d).\n",
length);
BUGMSG(D_NORMAL, "transmit aborted.\n");
dev_kfree_skb(skb);
lp->intx--;
return 0;
}
BUGMSG(D_DURING, "starting tx sequence...\n");
/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
if (((struct ethhdr *) (skb->data))->h_dest[0] == 0xFF)
daddr = 0;
else
daddr = ((struct ethhdr *) (skb->data))->h_dest[5];
/* load packet into shared memory */
offset = 512 - length;
if (length > MTU) { /* long/exception packet */
if (length < MinTU)
offset -= 3;
} else { /* short packet */
offset -= 256;
}
BUGMSG(D_DURING, " length=%Xh, offset=%Xh\n",
length, offset);
(*lp->prepare_tx) (dev, &proto, 1, skb->data, length - 1, daddr, 0,
offset);
dev_kfree_skb(skb);
if (arcnet_go_tx(dev, 1)) {
/* inform upper layers */
arcnet_tx_done(lp->adev, lp);
}
dev->trans_start = jiffies;
lp->intx--;
/* make sure we didn't ignore a TX IRQ while we were in here */
lp->intmask |= TXFREEflag;
SETMASK;
return 0;
}
/* Packet receiver for ethernet-encap packets.
*/
static void arcnetE_rx(struct net_device *dev, u_char * arcsoft,
int length, u_char saddr, u_char daddr)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
struct sk_buff *skb;
BUGMSG(D_DURING, "it's an ethernet-encap packet (length=%d)\n",
length);
skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
lp->stats.rx_dropped++;
return;
}
skb_put(skb, length);
skb->dev = dev;
memcpy(skb->data, (u_char *) arcsoft + 1, length - 1);
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
lp->stats.rx_bytes += skb->len;
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
}
#endif /* CONFIG_ARCNET_ETH */
#ifdef CONFIG_ARCNET_1051
/****************************************************************************
* *
* RFC1051 Support *
* *
****************************************************************************/
/* Initialize the arc0s device.
*/
static int arcnetS_init(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
arcnet_setup(dev);
/* And now fill particular fields with arcnet values */
dev->dev_addr[0] = lp->stationid;
dev->hard_header_len = sizeof(struct S_ClientData);
dev->mtu = 512 - sizeof(struct archdr) - dev->hard_header_len
+ S_EXTRA_CLIENTDATA;
dev->open = arcnetS_open_close;
dev->stop = arcnetS_open_close;
dev->hard_start_xmit = arcnetS_send_packet;
dev->hard_header = arcnetS_header;
dev->rebuild_header = arcnetS_rebuild_header;
return 0;
}
/* Bring up/down the arc0s device - we don't actually have to do anything,
* since our parent arc0 handles the card I/O itself.
*/
static int arcnetS_open_close(struct net_device *dev)
{
return 0;
}
/* Called by the kernel in order to transmit an RFC1051-type packet.
*/
static int arcnetS_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
int bad, length;
struct S_ClientData *hdr = (struct S_ClientData *) skb->data;
lp->intx++;
bad = arcnet_send_packet_bad(skb, dev);
if (bad) {
lp->intx--;
return bad;
}
/* arcnet_send_packet_pad has already set tbusy - don't bother here. */
length = 1 < skb->len ? skb->len : 1;
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx");
/* fits in one packet? */
if (length - S_EXTRA_CLIENTDATA <= XMTU) {
(*lp->prepare_tx) (dev,
skb->data + S_EXTRA_CLIENTDATA,
sizeof(struct S_ClientData) - S_EXTRA_CLIENTDATA,
skb->data + sizeof(struct S_ClientData),
length - sizeof(struct S_ClientData),
hdr->daddr, 0, 0);
/* done right away */
dev_kfree_skb(skb);
if (arcnet_go_tx(dev, 1)) {
/* inform upper layers */
arcnet_tx_done(lp->adev, lp);
}
} else { /* too big for one - not accepted */
BUGMSG(D_NORMAL, "packet too long (length=%d)\n",
length);
dev_kfree_skb(skb);
lp->stats.tx_dropped++;
arcnet_tx_done(lp->adev, lp);
}
dev->trans_start = jiffies;
lp->intx--;
/* make sure we didn't ignore a TX IRQ while we were in here */
lp->intmask |= TXFREEflag;
SETMASK;
return 0;
}
/* Packet receiver for RFC1051 packets;
*/
static void arcnetS_rx(struct net_device *dev, u_char * buf,
int length, u_char saddr, u_char daddr)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
struct sk_buff *skb;
struct S_ClientData *arcsoft, *soft;
arcsoft = (struct S_ClientData *) (buf - S_EXTRA_CLIENTDATA);
length += S_EXTRA_CLIENTDATA;
BUGMSG(D_DURING, "it's an RFC1051 packet (length=%d)\n",
length);
{ /* was "if not split" in A protocol, S is never split */
skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
lp->stats.rx_dropped++;
return;
}
soft = (struct S_ClientData *) skb->data;
skb_put(skb, length);
memcpy((u_char *) soft + sizeof(struct S_ClientData) - S_EXTRA_CLIENTDATA,
(u_char *) arcsoft + sizeof(struct S_ClientData) - S_EXTRA_CLIENTDATA,
length - sizeof(struct S_ClientData) + S_EXTRA_CLIENTDATA);
soft->protocol_id = arcsoft->protocol_id;
soft->daddr = daddr;
soft->saddr = saddr;
skb->dev = dev; /* is already lp->sdev */
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
lp->stats.rx_bytes += skb->len;
skb->protocol = arcnetS_type_trans(skb, dev);
netif_rx(skb);
}
}
/* Create the ARCnet ClientData header for an arbitrary protocol layer
* saddr=NULL means use device source address (always will anyway)
* daddr=NULL means leave destination address (eg unresolved arp)
*/
static int arcnetS_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr, unsigned len)
{
struct S_ClientData *head = (struct S_ClientData *)
skb_push(skb, dev->hard_header_len);
struct arcnet_local *lp = (struct arcnet_local *) (dev->priv);
/* set the protocol ID according to RFC1051 */
switch (type) {
case ETH_P_IP:
head->protocol_id = ARC_P_IP_RFC1051;
BUGMSG(D_DURING, "S_header: IP_RFC1051 packet.\n");
break;
case ETH_P_ARP:
head->protocol_id = ARC_P_ARP_RFC1051;
BUGMSG(D_DURING, "S_header: ARP_RFC1051 packet.\n");
break;
default:
BUGMSG(D_NORMAL, "I don't understand protocol %d (%Xh)\n",
type, type);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
return 0;
}
/*
* Set the source hardware address.
*
* This is pretty pointless for most purposes, but it can help
* in debugging. saddr is stored in the ClientData header and
* removed before sending the packet (since ARCnet does not allow
* us to change the source address in the actual packet sent)
*/
if (saddr)
head->saddr = ((u_char *) saddr)[0];
else
head->saddr = ((u_char *) (dev->dev_addr))[0];
/* supposedly if daddr is NULL, we should ignore it... */
if (daddr) {
head->daddr = ((u_char *) daddr)[0];
return dev->hard_header_len;
} else
head->daddr = 0; /* better fill one in anyway */
return -dev->hard_header_len;
}
/* Rebuild the ARCnet ClientData header. This is called after an ARP
* (or in future other address resolution) has completed on this
* sk_buff. We now let ARP fill in the other fields.
*/
static int arcnetS_rebuild_header(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
struct S_ClientData *head = (struct S_ClientData *) skb->data;
struct arcnet_local *lp = (struct arcnet_local *) (dev->priv);
/*
* Only ARP and IP are currently supported
*/
if (head->protocol_id != ARC_P_IP_RFC1051) {
BUGMSG(D_NORMAL, "I don't understand protocol type %d (%Xh) addresses!\n",
head->protocol_id, head->protocol_id);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
head->daddr = 0;
/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len); */
return 0;
}
/*
* Try to get ARP to resolve the header.
*/
#ifdef CONFIG_INET
return arp_find(&(head->daddr), skb) ? 1 : 0;
#else
return 0;
#endif
}
/* Determine a packet's protocol ID.
* With ARCnet we have to convert everything to Ethernet-style stuff.
*/
unsigned short arcnetS_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct S_ClientData *head;
struct arcnet_local *lp = (struct arcnet_local *) (dev->priv);
/* Pull off the arcnet header. */
skb->mac.raw = skb->data;
skb_pull(skb, dev->hard_header_len);
head = (struct S_ClientData *) skb->mac.raw;
if (head->daddr == 0)
skb->pkt_type = PACKET_BROADCAST;
else if (dev->flags & IFF_PROMISC) {
/* if we're not sending to ourselves :) */
if (head->daddr != dev->dev_addr[0])
skb->pkt_type = PACKET_OTHERHOST;
}
/* now return the protocol number */
switch (head->protocol_id) {
case ARC_P_IP_RFC1051:
return htons(ETH_P_IP);
case ARC_P_ARP_RFC1051:
return htons(ETH_P_ARP);
case ARC_P_ATALK:
return htons(ETH_P_ATALK); /* untested appletalk */
default:
lp->stats.rx_errors++;
lp->stats.rx_crc_errors++;
return 0;
}
return htons(ETH_P_IP);
}
#endif /* CONFIG_ARCNET_1051 */
/****************************************************************************
* *
* Kernel Loadable Module Support *
* *
****************************************************************************/
#ifdef MODULE
void cleanup_module(void)
{
printk("Generic arcnet support removed.\n");
}
void arcnet_use_count(int open)
{
if (open)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
#else
void arcnet_use_count(int open)
{
}
struct net_device arcnet_devs[MAX_ARCNET_DEVS];
int arcnet_num_devs = 0;
char arcnet_dev_names[MAX_ARCNET_DEVS][10];
int __init arcnet_init(void)
{
int c;
init_module();
/* Don't register_netdev here. The chain hasn't been initialised. */
#ifdef CONFIG_ARCNET_COM90xx
if ((!com90xx_explicit) && arcnet_num_devs < MAX_ARCNET_DEVS) {
arcnet_devs[arcnet_num_devs].init = arc90xx_probe;
arcnet_devs[arcnet_num_devs].name =
(char *) &arcnet_dev_names[arcnet_num_devs];
arcnet_num_devs++;
}
#endif
if (!arcnet_num_devs) {
printk("Don't forget to load the chipset driver.\n");
return 0;
}
/* Link into the device chain */
/* Q: Should we put ourselves at the beginning or the end of the chain? */
/* Probably the end, because we're not so fast, but... */
for (c = 0; c < (arcnet_num_devs - 1); c++)
arcnet_devs[c].next = &arcnet_devs[c + 1];
write_lock_bh(&dev_base_lock);
arcnet_devs[c].next = dev_base;
dev_base = &arcnet_devs[0];
write_unlock_bh(&dev_base_lock);
/* Give names to those without them */
for (c = 0; c < arcnet_num_devs; c++)
if (!arcnet_dev_names[c][0])
arcnet_makename((char *) &arcnet_dev_names[c]);
return 0;
}
#endif /* MODULE */
#ifdef MODULE
int init_module(void)
#else
static int __init init_module(void)
#endif
{
#ifdef ALPHA_WARNING
BUGLVL(D_EXTRA) {
printk("arcnet: ***\n");
printk("arcnet: * Read arcnet.txt for important release notes!\n");
printk("arcnet: *\n");
printk("arcnet: * This is an ALPHA version! (Last stable release: v2.56) E-mail me if\n");
printk("arcnet: * you have any questions, comments, or bug reports.\n");
printk("arcnet: ***\n");
}
#endif
printk("%sAvailable protocols: ARCnet RFC1201"
#ifdef CONFIG_ARCNET_ETH
", Ethernet-Encap"
#endif
#ifdef CONFIG_ARCNET_1051
", ARCnet RFC1051"
#endif
#ifdef MODULE
".\nDon't forget to load the chipset driver"
#endif
".\n", version);
return 0;
}
void arcnet_makename(char *device)
{
struct net_device *dev;
int arcnum;
arcnum = 0;
for (;;) {
sprintf(device, "arc%d", arcnum);
read_lock_bh(&dev_base_lock);
for (dev = dev_base; dev; dev = dev->next)
if (dev->name != device && !strcmp(dev->name, device))
break;
read_unlock_bh(&dev_base_lock);
if (!dev)
return;
arcnum++;
}
}
#
# Arcnet configuration
#
mainmenu_option next_comment
comment 'ARCnet devices'
tristate 'ARCnet support' CONFIG_ARCNET
if [ "$CONFIG_ARCNET" != "n" ]; then
dep_tristate 'Enable standard ARCNet packet format (RFC 1201)' CONFIG_ARCNET_1201 $CONFIG_ARCNET
dep_tristate 'Enable old ARCNet packet format (RFC 1051)' CONFIG_ARCNET_1051 $CONFIG_ARCNET
dep_tristate 'Enable raw mode packet interface' CONFIG_ARCNET_RAW $CONFIG_ARCNET
dep_tristate 'ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET
dep_tristate 'ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET
dep_tristate 'ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET
dep_tristate 'ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
if [ "$CONFIG_ARCNET_COM20020" != "n" ]; then
dep_tristate ' Support for COM20020 on ISA' CONFIG_ARCNET_COM20020_ISA $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
dep_tristate ' Support for COM20020 on PCI' CONFIG_ARCNET_COM20020_PCI $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
fi
fi
endmenu
# Makefile for linux/drivers/net/arcnet
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
SUB_DIRS :=
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS)
obj-y :=
obj-n :=
obj-m :=
obj- :=
export-objs := arcnet.o com20020.o
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_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
L_TARGET := arcnet.a
L_OBJS := $(filter-out $(export-objs), $(obj-y))
LX_OBJS := $(filter $(export-objs), $(obj-y))
M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
include $(TOPDIR)/Rules.make
/*
* 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 Public License as
* modified by SRC, incorporated herein by reference.
*
* **********************
*
* For more details, see drivers/net/arcnet.c
*
* **********************
*/
#include <linux/module.h>
#include <linux/config.h> /* for CONFIG_INET */
#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, 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 = {
'r',
XMTU,
rx,
build_header,
prepare_tx
};
void arcnet_raw_init(void)
{
int count;
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;
}
#ifdef MODULE
int __init init_module(void)
{
printk(VERSION);
arcnet_raw_init();
return 0;
}
void cleanup_module(void)
{
arcnet_unregister_proto(&rawmode_proto);
}
#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;
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 = 0;
netif_rx(skb);
}
/*
* Create the ARCnet hard/soft headers for raw mode.
* There aren't any soft headers in raw mode - not even the protocol id.
*/
static int build_header(struct sk_buff *skb, unsigned short type,
uint8_t daddr)
{
struct net_device *dev = skb->dev;
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 = (struct arcnet_local *)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 */
}
/*
* Linux ARCnet driver - "RIM I" (entirely mem-mapped) cards
*
* Written 1994-1999 by Avery Pennarun.
* Written 1999 by Martin Mares <mj@suse.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 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/ioport.h>
#include <linux/malloc.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_openclose(struct net_device *dev, bool open);
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;
}
if (check_mem_region(dev->mem_start, BUFFER_SIZE)) {
BUGMSG(D_NORMAL, "Card memory already allocated\n");
return -ENODEV;
}
if (dev->dev_addr[0] == 0) {
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;
u_long first_mirror, last_mirror, shmem;
int mirror_size;
/* reserve the irq */ {
if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (RIM I)", dev))
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;
dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0;
dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1;
/* initialize the rest of the device structure. */
lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (!lp) {
BUGMSG(D_NORMAL, "Can't allocate device data!\n");
goto err_free_irq;
}
lp->hw.command = arcrimi_command;
lp->hw.status = arcrimi_status;
lp->hw.intmask = arcrimi_setmask;
lp->hw.reset = arcrimi_reset;
lp->hw.open_close = arcrimi_openclose;
lp->hw.copy_to_card = arcrimi_copy_to_card;
lp->hw.copy_from_card = arcrimi_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_dev_priv;
}
/* Fill in the fields of the device structure with generic
* values.
*/
arcdev_setup(dev);
/* get and check the station ID from offset 1 in shmem */
dev->dev_addr[0] = readb(lp->mem_start + 1);
/* reserve the memory region - guaranteed to work by check_region */
request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)");
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);
return 0;
err_free_dev_priv:
kfree(dev->priv);
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 = (struct arcnet_local *) dev->priv;
void *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_openclose(struct net_device *dev, int open)
{
if (open)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
static void arcrimi_setmask(struct net_device *dev, int mask)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
void *ioaddr = lp->mem_start + 0x800;
AINTMASK(mask);
}
static int arcrimi_status(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
void *ioaddr = lp->mem_start + 0x800;
return ASTATUS();
}
static void arcrimi_command(struct net_device *dev, int cmd)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
void *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 = (struct arcnet_local *) dev->priv;
void *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 = (struct arcnet_local *) dev->priv;
void *memaddr = lp->mem_start + 0x800 + bufnum*512 + offset;
TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
}
#ifdef MODULE
static struct net_device *my_dev;
/* Module parameters */
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; /* use eg. device="arc1" to change name */
MODULE_PARM(node, "i");
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(device, "s");
int init_module(void)
{
struct net_device *dev;
int err;
dev = dev_alloc(device ? : "arc%d", &err);
if (!dev)
return err;
if (node && node != 0xff)
dev->dev_addr[0] = node;
dev->base_addr = io;
dev->irq = irq;
if (dev->irq == 2)
dev->irq = 9;
if (arcrimi_probe(dev))
return -EIO;
my_dev = dev;
return 0;
}
void cleanup_module(void)
{
struct net_device *dev = my_dev;
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
void *ioaddr = lp->mem_start + 0x800;
if (dev->start)
dev->stop(dev);
/* Flush TX and disable RX */
AINTMASK(0); /* disable IRQ's */
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
free_irq(dev->irq, dev);
iounmap(lp->mem_start);
release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
unregister_netdev(dev);
kfree(dev->priv);
kfree(dev);
}
#else
static int __init arcrimi_setup(char *s)
{
struct net_device *dev;
int ints[8];
s = get_options(s, 8, ints);
if (!ints[0])
return 1;
dev = alloc_bootmem(sizeof(struct net_device) + 10);
memset(dev, 0, sizeof(struct net_device) + 10);
dev->name = (char *)(dev+1);
dev->init = arcrimi_probe;
switch (ints[0]) {
default: /* ERROR */
printk("arcrimi: Too many arguments.\n");
case 3: /* Node ID */
dev->dev_addr[0] = ints[3];
case 2: /* IRQ */
dev->irq = ints[2];
case 1: /* IO address */
dev->mem_start = ints[1];
}
if (*s)
strncpy(dev->name, s, 9);
else
strcpy(dev->name, "arc%d");
if (register_netdev(dev))
printk(KERN_ERR "arc-rimi: Cannot register arcnet device\n");
return 1;
}
__setup("arcrimi=", arcrimi_setup);
#endif /* MODULE */
/*
* Linux ARCnet driver - device-independent routines
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
* Written 1999 by Martin Mares <mj@suse.cz>.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
* for sponsoring the further development of this driver.
*
* **********************
*
* The original copyright was as follows:
*
* skeleton.c Written 1993 by Donald Becker.
* Copyright 1993 United States Government as represented by the
* Director, National Security Agency. This software may only be used
* and distributed according to the terms of the GNU Public License as
* modified by SRC, incorporated herein by reference.
*
* **********************
*
* The change log is now in a file called ChangeLog in this directory.
*
* Sources:
* - Crynwr arcnet.com/arcether.com packet drivers.
* - arcnet.c v0.00 dated 1/1/94 and apparently by
* Donald Becker - it didn't work :)
* - skeleton.c v0.05 dated 11/16/93 by Donald Becker
* (from Linux Kernel 1.1.45)
* - RFC's 1201 and 1051 - re: TCP/IP over ARCnet
* - The official ARCnet COM9026 data sheets (!) thanks to
* Ken Cornetet <kcornete@nyx10.cs.du.edu>
* - The official ARCnet COM20020 data sheets.
* - Information on some more obscure ARCnet controller chips, thanks
* to the nice people at SMSC.
* - net/inet/eth.c (from kernel 1.1.50) for header-building info.
* - Alternate Linux ARCnet source by V.Shergin <vsher@sao.stavropol.su>
* - Textual information and more alternate source from Joachim Koenig
* <jojo@repas.de>
*/
#define VERSION "arcnet: v3.91 BETA 99/12/18 - by Avery Pennarun et al.\n"
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <net/arp.h>
#include <linux/init.h>
#include <linux/arcdevice.h>
/* "do nothing" functions for protocol drivers */
static void null_rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length);
static int null_build_header(struct sk_buff *skb, unsigned short type,
uint8_t daddr);
static int null_prepare_tx(struct net_device *dev, struct archdr *pkt,
int length, int bufnum);
/*
* one ArcProto per possible proto ID. None of the elements of
* arc_proto_map are allowed to be NULL; they will get set to
* arc_proto_default instead. It also must not be NULL; if you would like
* to set it to NULL, set it to &arc_proto_null instead.
*/
struct ArcProto *arc_proto_map[256], *arc_proto_default, *arc_bcast_proto;
struct ArcProto arc_proto_null = {
'?',
XMTU,
null_rx,
null_build_header,
null_prepare_tx
};
/* Exported function prototypes */
int arcnet_debug = ARCNET_DEBUG;
EXPORT_SYMBOL(arc_proto_map);
EXPORT_SYMBOL(arc_proto_default);
EXPORT_SYMBOL(arc_bcast_proto);
EXPORT_SYMBOL(arc_proto_null);
EXPORT_SYMBOL(arcnet_unregister_proto);
EXPORT_SYMBOL(arcnet_debug);
EXPORT_SYMBOL(arcdev_setup);
EXPORT_SYMBOL(arcnet_interrupt);
/* Internal function prototypes */
static int arcnet_open(struct net_device *dev);
static int arcnet_close(struct net_device *dev);
static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev);
static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr,
unsigned len);
static int arcnet_rebuild_header(struct sk_buff *skb);
static struct net_device_stats *arcnet_get_stats(struct net_device *dev);
static int go_tx(struct net_device *dev);
void __init arcnet_init(void)
{
static int arcnet_inited __initdata = 0;
int count;
if (arcnet_inited++)
return;
printk(VERSION);
#ifdef ALPHA_WARNING
BUGLVL(D_EXTRA)
{
printk("arcnet: ***\n"
"arcnet: * Read arcnet.txt for important release notes!\n"
"arcnet: *\n"
"arcnet: * This is an ALPHA version! (Last stable release: v3.02) E-mail\n"
"arcnet: * me if you have any questions, comments, or bug reports.\n"
"arcnet: ***\n");
}
#endif
/* initialize the protocol map */
arc_proto_default = arc_bcast_proto = &arc_proto_null;
for (count = 0; count < 256; count++)
arc_proto_map[count] = arc_proto_default;
BUGLVL(D_DURING)
printk("arcnet: struct sizes: %d %d %d %d %d\n",
sizeof(struct arc_hardware), sizeof(struct arc_rfc1201),
sizeof(struct arc_rfc1051), sizeof(struct arc_eth_encap),
sizeof(struct archdr));
#ifdef CONFIG_ARCNET /* We're not built as a module */
printk("arcnet: Available protocols:");
#ifdef CONFIG_ARCNET_1201
printk(" RFC1201");
arcnet_rfc1201_init();
#endif
#ifdef CONFIG_ARCNET_1051
printk(" RFC1051");
arcnet_rfc1051_init();
#endif
#ifdef CONFIG_ARCNET_RAW
printk(" RAW");
arcnet_raw_init();
#endif
printk("\n");
#ifdef CONFIG_ARCNET_COM90xx
com90xx_probe(NULL);
#endif
#ifdef CONFIG_ARCNET_COM20020_PCI
com20020pci_probe_all();
#endif
#endif
}
#ifdef MODULE
static int debug = ARCNET_DEBUG;
MODULE_PARM(debug, "i");
int __init init_module(void)
{
arcnet_debug = debug;
arcnet_init();
return 0;
}
void cleanup_module(void)
{
}
#endif
/*
* Dump the contents of an sk_buff
*/
#if ARCNET_DEBUG_MAX & D_SKB
void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc)
{
int i;
long flags;
save_flags(flags);
cli();
printk(KERN_DEBUG "%6s: skb dump (%s) follows:", dev->name, desc);
for (i = 0; i < skb->len; i++)
{
if (i % 16 == 0)
printk("\n" KERN_DEBUG "[%04X] ", i);
printk("%02X ", ((u_char *) skb->data)[i]);
}
printk("\n");
restore_flags(flags);
}
EXPORT_SYMBOL(arcnet_dump_skb);
#endif
/*
* Dump the contents of an ARCnet buffer
*/
#if (ARCNET_DEBUG_MAX & (D_RX | D_TX))
void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int i, length;
long flags;
static uint8_t buf[512];
save_flags(flags);
cli();
lp->hw.copy_from_card(dev, bufnum, 0, buf, 512);
/* if the offset[0] byte is nonzero, this is a 256-byte packet */
length = (buf[2] ? 256 : 512);
printk(KERN_DEBUG "%6s: packet dump (%s) follows:", dev->name, desc);
for (i = 0; i < length; i++)
{
if (i % 16 == 0)
printk("\n" KERN_DEBUG "[%04X] ", i);
printk("%02X ", buf[i]);
}
printk("\n");
restore_flags(flags);
}
EXPORT_SYMBOL(arcnet_dump_packet);
#endif
/*
* Unregister a protocol driver from the arc_proto_map. Protocol drivers
* are responsible for registering themselves, but the unregister routine
* is pretty generic so we'll do it here.
*/
void arcnet_unregister_proto(struct ArcProto *proto)
{
int count;
if (arc_proto_default == proto)
arc_proto_default = &arc_proto_null;
if (arc_bcast_proto == proto)
arc_bcast_proto = arc_proto_default;
for (count = 0; count < 256; count++)
{
if (arc_proto_map[count] == proto)
arc_proto_map[count] = arc_proto_default;
}
}
/*
* Add a buffer to the queue. Only the interrupt handler is allowed to do
* this, unless interrupts are disabled.
*
* Note: we don't check for a full queue, since there aren't enough buffers
* to more than fill it.
*/
static void release_arcbuf(struct net_device *dev, int bufnum)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int i;
lp->buf_queue[lp->first_free_buf++] = bufnum;
lp->first_free_buf %= 5;
BUGLVL(D_DURING)
{
BUGMSG(D_DURING, "release_arcbuf: freed #%d; buffer queue is now: ",
bufnum);
for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5)
BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]);
BUGMSG2(D_DURING, "\n");
}
}
/*
* Get a buffer from the queue. If this returns -1, there are no buffers
* available.
*/
static int get_arcbuf(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int buf = -1, i;
if (!atomic_dec_and_test(&lp->buf_lock)) /* already in this function */
BUGMSG(D_NORMAL, "get_arcbuf: overlap (%d)!\n", lp->buf_lock.counter);
else /* we can continue */
{
if (lp->next_buf >= 5)
lp->next_buf -= 5;
if (lp->next_buf == lp->first_free_buf)
BUGMSG(D_NORMAL, "get_arcbuf: BUG: no buffers are available??\n");
else
{
buf = lp->buf_queue[lp->next_buf++];
lp->next_buf %= 5;
}
}
BUGLVL(D_DURING)
{
BUGMSG(D_DURING, "get_arcbuf: got #%d; buffer queue is now: ", buf);
for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5)
BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]);
BUGMSG2(D_DURING, "\n");
}
atomic_inc(&lp->buf_lock);
return buf;
}
static int choose_mtu(void)
{
int count, mtu = 65535;
/* choose the smallest MTU of all available encaps */
for (count = 0; count < 256; count++)
{
if (arc_proto_map[count] != &arc_proto_null
&& arc_proto_map[count]->mtu < mtu)
{
mtu = arc_proto_map[count]->mtu;
}
}
return mtu == 65535 ? XMTU : mtu;
}
/* Setup a struct device for ARCnet. */
void arcdev_setup(struct net_device *dev)
{
dev->type = ARPHRD_ARCNET;
dev->hard_header_len = sizeof(struct archdr);
dev->mtu = choose_mtu();
dev->addr_len = 1;
dev->tx_queue_len = 30;
dev->broadcast[0] = 0x00; /* for us, broadcasts are address 0 */
/* New-style flags. */
dev->flags = IFF_BROADCAST;
/*
* Put in this stuff here, so we don't have to export the symbols to
* the chipset drivers.
*/
dev->open = arcnet_open;
dev->stop = arcnet_close;
dev->hard_start_xmit = arcnet_send_packet;
dev->get_stats = arcnet_get_stats;
dev->hard_header = arcnet_header;
dev->rebuild_header = arcnet_rebuild_header;
dev_init_buffers(dev);
}
/*
* Open/initialize the board. This is called sometime after booting when
* the 'ifconfig' program is run.
*
* This routine should set everything up anew at each open, even registers
* that "should" only need to be set once at boot, so that there is
* non-reboot way to recover if something goes wrong.
*/
static int arcnet_open(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int count, newmtu;
BUGLVL(D_PROTO)
{
int count;
BUGMSG(D_PROTO, "protocol map (default is '%c'): ",
arc_proto_default->suffix);
for (count = 0; count < 256; count++)
BUGMSG2(D_PROTO, "%c", arc_proto_map[count]->suffix);
BUGMSG2(D_PROTO, "\n");
}
BUGMSG(D_INIT, "arcnet_open: resetting card.\n");
/* try to put the card in a defined state - if it fails the first
* time, actually reset it.
*/
if (ARCRESET(0) && ARCRESET(1))
return -ENODEV;
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 0;
newmtu = choose_mtu();
if (newmtu < dev->mtu)
dev->mtu = newmtu;
/* autodetect the encapsulation for each host. */
memset(lp->default_proto, 0, sizeof(lp->default_proto));
/* the broadcast address is special - use the 'bcast' protocol */
for (count = 0; count < 256; count++)
{
if (arc_proto_map[count] == arc_bcast_proto)
{
lp->default_proto[0] = count;
break;
}
}
/* initialize buffers */
atomic_set(&lp->buf_lock, 1);
lp->next_buf = lp->first_free_buf = 0;
release_arcbuf(dev, 0);
release_arcbuf(dev, 1);
release_arcbuf(dev, 2);
release_arcbuf(dev, 3);
lp->cur_tx = lp->next_tx = -1;
lp->cur_rx = -1;
lp->rfc1201.sequence = 1;
/* bring up the hardware driver */
ARCOPEN(1);
if (dev->dev_addr[0] == 0)
BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved "
"for broadcasts!\n");
else if (dev->dev_addr[0] == 255)
BUGMSG(D_NORMAL, "WARNING! Station address FF may confuse "
"DOS networking programs!\n");
if (ASTATUS() & RESETflag)
ACOMMAND(CFLAGScmd | RESETclear);
/* we're started */
dev->start = 1;
/* make sure we're ready to receive IRQ's. */
AINTMASK(0);
udelay(1); /* give it time to set the mask before
* we reset it again. (may not even be
* necessary)
*/
lp->intmask = NORXflag | RECONflag;
AINTMASK(lp->intmask);
return 0;
}
/* The inverse routine to arcnet_open - shuts down the card. */
static int arcnet_close(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
/* flush TX and disable RX */
AINTMASK(0);
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
mdelay(1);
dev->tbusy = 1;
dev->start = 0;
dev->interrupt = 0;
/* shut down the card */
ARCOPEN(0);
return 0;
}
static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr,
unsigned len)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
uint8_t _daddr, proto_num;
struct ArcProto *proto;
BUGMSG(D_DURING,
"create header from %d to %d; protocol %d (%Xh); size %u.\n",
saddr ? *(uint8_t *)saddr : -1,
daddr ? *(uint8_t *)daddr : -1,
type, type, len);
if (len != skb->len)
BUGMSG(D_NORMAL, "arcnet_header: Yikes! skb->len(%d) != len(%d)!\n",
skb->len, len);
/*
* if the dest addr isn't provided, we can't choose an encapsulation!
* Store the packet type (eg. ETH_P_IP) for now, and we'll push on a
* real header when we do rebuild_header.
*/
if (!daddr)
{
*(uint16_t *)skb_push(skb, 2) = type;
if (skb->nh.raw - skb->mac.raw != 2)
BUGMSG(D_NORMAL, "arcnet_header: Yikes! diff (%d) is not 2!\n",
skb->nh.raw - skb->mac.raw);
return -2; /* return error -- can't transmit yet! */
}
/* otherwise, we can just add the header as usual. */
_daddr = *(uint8_t *)daddr;
proto_num = lp->default_proto[_daddr];
proto = arc_proto_map[proto_num];
BUGMSG(D_DURING, "building header for %02Xh using protocol '%c'\n",
proto_num, proto->suffix);
if (proto == &arc_proto_null && arc_bcast_proto != proto)
{
BUGMSG(D_DURING, "actually, let's use '%c' instead.\n",
arc_bcast_proto->suffix);
proto = arc_bcast_proto;
}
return proto->build_header(skb, type, _daddr);
}
/*
* Rebuild the ARCnet hard header. This is called after an ARP (or in the
* future other address resolution) has completed on this sk_buff. We now
* let ARP fill in the destination field.
*/
static int arcnet_rebuild_header(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int status = 0; /* default is failure */
unsigned short type;
uint8_t daddr;
if (skb->nh.raw - skb->mac.raw != 2)
{
BUGMSG(D_NORMAL,
"rebuild_header: shouldn't be here! (hdrsize=%d)\n",
skb->nh.raw - skb->mac.raw);
return 0;
}
type = *(uint16_t *)skb_pull(skb, 2);
if (type == ETH_P_IP)
{
#ifdef CONFIG_INET
BUGMSG(D_DURING, "rebuild header for ethernet protocol %Xh\n", type);
status = arp_find(&daddr, skb) ? 1 : 0;
BUGMSG(D_DURING, " rebuilt: dest is %d; protocol %Xh\n",
daddr, type);
#endif
}
else
{
BUGMSG(D_NORMAL,
"I don't understand ethernet protocol %Xh addresses!\n", type);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
}
/* if we couldn't resolve the address... give up. */
if (!status)
return 0;
/* add the _real_ header this time! */
arc_proto_map[lp->default_proto[daddr]]->build_header(skb, type, daddr);
return 1; /* success */
}
/* Called by the kernel in order to transmit a packet. */
static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct archdr *pkt;
struct arc_rfc1201 *soft;
struct ArcProto *proto;
int txbuf;
BUGMSG(D_DURING,
"transmit requested (status=%Xh, txbufs=%d/%d, len=%d)\n",
ASTATUS(), lp->cur_tx, lp->next_tx, skb->len);
if (dev->tbusy)
{
/*
* If we get here, some higher level has decided we are broken.
* There should really be a "kick me" function call instead.
*/
unsigned long flags;
int tickssofar = jiffies - dev->trans_start, status = ASTATUS();
if (tickssofar < TX_TIMEOUT)
{
BUGMSG(D_DURING, "premature kickme! (status=%Xh ticks=%d)\n",
status, tickssofar);
return 1; /* means "try again" */
}
save_flags(flags);
cli();
if (status & TXFREEflag) /* transmit _DID_ finish */
{
BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n",
status, tickssofar, lp->intmask, lp->lasttrans_dest);
lp->stats.tx_errors++;
}
else
{
BUGMSG(D_EXTRA, "tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n",
status, tickssofar, lp->intmask, lp->lasttrans_dest);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
ACOMMAND(NOTXcmd | (lp->cur_tx << 3));
}
/*
* interrupt handler will set dev->tbusy = 0 when it notices the
* transmit has been canceled.
*/
/* make sure we didn't miss a TX IRQ */
AINTMASK(0);
lp->intmask |= TXFREEflag;
AINTMASK(lp->intmask);
restore_flags(flags);
return 1;
}
pkt = (struct archdr *)skb->data;
soft = &pkt->soft.rfc1201;
proto = arc_proto_map[soft->proto];
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx");
/* fits in one packet? */
if (skb->len - ARC_HDR_SIZE > XMTU && !proto->continue_tx)
{
BUGMSG(D_NORMAL, "fixme: packet too large: compensating badly!\n");
dev_kfree_skb(skb);
return 0; /* don't try again */
}
/*
* Block a timer-based transmit from overlapping. This could better be
* done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
if (test_and_set_bit(0, (int *)&dev->tbusy))
{
BUGMSG(D_NORMAL, "transmitter called with busy bit set! "
"(status=%Xh, tickssofar=%ld)\n",
ASTATUS(), jiffies - dev->trans_start);
lp->stats.tx_errors++;
lp->stats.tx_fifo_errors++;
return 0; /* don't try again */
}
AINTMASK(0);
txbuf = get_arcbuf(dev);
if (txbuf != -1)
{
if (proto->prepare_tx(dev, pkt, skb->len, txbuf))
{
/* done right away */
lp->stats.tx_bytes += skb->len;
dev_kfree_skb(skb);
}
else
{
/* do it the 'split' way */
lp->outgoing.proto = proto;
lp->outgoing.skb = skb;
lp->outgoing.pkt = pkt;
if (!proto->continue_tx)
BUGMSG(D_NORMAL, "bug! prep_tx==0, but no continue_tx!\n");
else if (proto->continue_tx(dev, txbuf))
{
BUGMSG(D_NORMAL,
"bug! continue_tx finished the first time! "
"(proto='%c')\n", proto->suffix);
}
}
lp->next_tx = txbuf;
}
else
dev_kfree_skb(skb);
/* make sure we didn't ignore a TX IRQ while we were in here */
AINTMASK(0);
lp->intmask |= TXFREEflag;
AINTMASK(lp->intmask);
return 0; /* no need to try again */
}
/*
* Actually start transmitting a packet that was loaded into a buffer
* by prepare_tx. This should _only_ be called by the interrupt handler.
*/
static int go_tx(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, next_tx=%d, cur_tx=%d\n",
ASTATUS(), lp->intmask, lp->next_tx, lp->cur_tx);
if (lp->cur_tx != -1 || lp->next_tx == -1)
return 0;
BUGLVL(D_TX) arcnet_dump_packet(dev, lp->next_tx, "go_tx");
lp->cur_tx = lp->next_tx;
lp->next_tx = -1;
/* start sending */
ACOMMAND(TXcmd | (lp->cur_tx << 3));
dev->trans_start = jiffies;
lp->stats.tx_packets++;
lp->lasttrans_dest = lp->lastload_dest;
lp->lastload_dest = 0;
lp->intmask |= TXFREEflag;
return 1;
}
/*
* The typical workload of the driver: Handle the network interface
* interrupts. Establish which device needs attention, and call the correct
* chipset interrupt handler.
*/
void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct arcnet_local *lp;
int recbuf, status, didsomething, boguscount;
BUGMSG(D_DURING, "\n");
if (dev == NULL)
{
BUGMSG(D_DURING, "arcnet: irq %d for unknown device.\n", irq);
return;
}
BUGMSG(D_DURING, "in arcnet_interrupt\n");
lp = (struct arcnet_local *)dev->priv;
if (!lp)
{
BUGMSG(D_DURING, "arcnet: irq ignored due to missing lp.\n");
return;
}
/*
* RESET flag was enabled - if !dev->start, we must clear it right
* away (but nothing else).
*/
if (!dev->start)
{
if (ASTATUS() & RESETflag)
ACOMMAND(CFLAGScmd | RESETclear);
AINTMASK(0);
return;
}
if (dev->interrupt)
{
BUGMSG(D_NORMAL, "DRIVER PROBLEM! Nested arcnet interrupts!\n");
return; /* don't even try. */
}
dev->interrupt = 1;
BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
ASTATUS(), lp->intmask);
boguscount = 3;
do
{
status = ASTATUS();
didsomething = 0;
/*
* RESET flag was enabled - card is resetting and if RX is
* disabled, it's NOT because we just got a packet.
*
* The card is in an undefined state. Clear it out and start over.
*/
if (status & RESETflag)
{
BUGMSG(D_NORMAL, "spurious reset (status=%Xh)\n", status);
arcnet_close(dev);
arcnet_open(dev);
/* get out of the interrupt handler! */
break;
}
/*
* RX is inhibited - we must have received something. Prepare to
* receive into the next buffer.
*
* We don't actually copy the received packet from the card until
* after the transmit handler runs (and possibly launches the next
* tx); this should improve latency slightly if we get both types
* of interrupts at once.
*/
recbuf = -1;
if (status & lp->intmask & NORXflag)
{
recbuf = lp->cur_rx;
BUGMSG(D_DURING, "Buffer #%d: receive irq (status=%Xh)\n",
recbuf, status);
lp->cur_rx = get_arcbuf(dev);
if (lp->cur_rx != -1)
{
BUGMSG(D_DURING, "enabling receive to buffer #%d\n",
lp->cur_rx);
ACOMMAND(RXcmd | (lp->cur_rx << 3) | RXbcasts);
}
didsomething++;
}
/* a transmit finished, and we're interested in it. */
if (status & lp->intmask & TXFREEflag)
{
lp->intmask &= ~TXFREEflag;
BUGMSG(D_DURING, "TX IRQ (stat=%Xh)\n", status);
if (lp->cur_tx != -1 && !(status & TXACKflag))
{
if (lp->lasttrans_dest != 0)
{
BUGMSG(D_EXTRA, "transmit was not acknowledged! "
"(status=%Xh, dest=%02Xh)\n",
status, lp->lasttrans_dest);
lp->stats.tx_errors++;
lp->stats.tx_carrier_errors++;
}
else
{
BUGMSG(D_DURING,
"broadcast was not acknowledged; that's normal "
"(status=%Xh, dest=%02Xh)\n",
status, lp->lasttrans_dest);
}
}
if (lp->cur_tx != -1)
release_arcbuf(dev, lp->cur_tx);
lp->cur_tx = -1;
didsomething++;
/* send another packet if there is one */
go_tx(dev);
/* continue a split packet, if any */
if (lp->outgoing.proto && lp->outgoing.proto->continue_tx)
{
int txbuf = get_arcbuf(dev);
if (txbuf != -1)
{
if (lp->outgoing.proto->continue_tx(dev, txbuf))
{
/* that was the last segment */
lp->stats.tx_bytes += lp->outgoing.skb->len;
dev_kfree_skb(lp->outgoing.skb);
lp->outgoing.proto = NULL;
}
lp->next_tx = txbuf;
}
}
/* inform upper layers of idleness, if necessary */
if (lp->cur_tx == -1)
{
dev->tbusy = 0;
mark_bh(NET_BH);
}
}
/* now process the received packet, if any */
if (recbuf != -1)
{
BUGLVL(D_RX) arcnet_dump_packet(dev, recbuf, "rx irq");
arcnet_rx(dev, recbuf);
release_arcbuf(dev, recbuf);
didsomething++;
}
if (status & lp->intmask & RECONflag)
{
ACOMMAND(CFLAGScmd | CONFIGclear);
lp->stats.tx_carrier_errors++;
BUGMSG(D_RECON, "Network reconfiguration detected (status=%Xh)\n",
status);
/* is the RECON info empty or old? */
if (!lp->first_recon || !lp->last_recon ||
jiffies - lp->last_recon > HZ * 10)
{
if (lp->network_down)
BUGMSG(D_NORMAL, "reconfiguration detected: cabling restored?\n");
lp->first_recon = lp->last_recon = jiffies;
lp->num_recons = lp->network_down = 0;
BUGMSG(D_DURING, "recon: clearing counters.\n");
}
else
{ /* add to current RECON counter */
lp->last_recon = jiffies;
lp->num_recons++;
BUGMSG(D_DURING, "recon: counter=%d, time=%lds, net=%d\n",
lp->num_recons,
(lp->last_recon - lp->first_recon) / HZ,
lp->network_down);
/* if network is marked up;
* and first_recon and last_recon are 60+ apart;
* and the average no. of recons counted is
* > RECON_THRESHOLD/min;
* then print a warning message.
*/
if (!lp->network_down
&& (lp->last_recon - lp->first_recon) <= HZ * 60
&& lp->num_recons >= RECON_THRESHOLD)
{
lp->network_down = 1;
BUGMSG(D_NORMAL, "many reconfigurations detected: cabling problem?\n");
}
else if (!lp->network_down
&& lp->last_recon - lp->first_recon > HZ * 60)
{
/* reset counters if we've gone for over a minute. */
lp->first_recon = lp->last_recon;
lp->num_recons = 1;
}
}
}
else if (lp->network_down && jiffies - lp->last_recon > HZ * 10)
{
if (lp->network_down)
BUGMSG(D_NORMAL, "cabling restored?\n");
lp->first_recon = lp->last_recon = 0;
lp->num_recons = lp->network_down = 0;
BUGMSG(D_DURING, "not recon: clearing counters anyway.\n");
}
}
while (--boguscount && didsomething);
BUGMSG(D_DURING, "arcnet_interrupt complete (status=%Xh, count=%d)\n",
ASTATUS(), boguscount);
BUGMSG(D_DURING, "\n");
AINTMASK(0);
udelay(1);
AINTMASK(lp->intmask);
dev->interrupt = 0;
}
/*
* This is a generic packet receiver that calls arcnet??_rx depending on the
* protocol ID found.
*/
void arcnet_rx(struct net_device *dev, int bufnum)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct archdr pkt;
struct arc_rfc1201 *soft;
int length, ofs;
soft = &pkt.soft.rfc1201;
lp->hw.copy_from_card(dev, bufnum, 0, &pkt, sizeof(ARC_HDR_SIZE));
if (pkt.hard.offset[0])
{
ofs = pkt.hard.offset[0];
length = 256 - ofs;
}
else
{
ofs = pkt.hard.offset[1];
length = 512 - ofs;
}
/* get the full header, if possible */
if (sizeof(pkt.soft) < length)
lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(pkt.soft));
else
{
memset(&pkt.soft, 0, sizeof(pkt.soft));
lp->hw.copy_from_card(dev, bufnum, ofs, soft, length);
}
BUGMSG(D_DURING, "Buffer #%d: received packet from %02Xh to %02Xh "
"(%d+4 bytes)\n",
bufnum, pkt.hard.source, pkt.hard.dest, length);
lp->stats.rx_packets++;
lp->stats.rx_bytes += length + ARC_HDR_SIZE;
/* call the right receiver for the protocol */
if (arc_proto_map[soft->proto] != &arc_proto_null)
{
BUGLVL(D_PROTO)
{
struct ArcProto
*oldp = arc_proto_map[lp->default_proto[pkt.hard.source]],
*newp = arc_proto_map[soft->proto];
if (oldp != newp)
{
BUGMSG(D_PROTO,
"got protocol %02Xh; encap for host %02Xh is now '%c'"
" (was '%c')\n", soft->proto, pkt.hard.source,
newp->suffix, oldp->suffix);
}
}
/* broadcasts will always be done with the last-used encap. */
lp->default_proto[0] = soft->proto;
/* in striking contrast, the following isn't a hack. */
lp->default_proto[pkt.hard.source] = soft->proto;
}
/* call the protocol-specific receiver. */
arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length);
/*
* If any worthwhile packets have been received, a mark_bh(NET_BH) has
* been done by netif_rx and Linux will handle them after we return.
*/
}
/*
* Get the current statistics. This may be called with the card open or
* closed.
*/
static struct net_device_stats *arcnet_get_stats(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
return &lp->stats;
}
static void null_rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length)
{
BUGMSG(D_PROTO,
"rx: don't know how to deal with proto %02Xh from host %02Xh.\n",
pkthdr->soft.rfc1201.proto, pkthdr->hard.source);
}
static int null_build_header(struct sk_buff *skb, unsigned short type,
uint8_t daddr)
{
struct net_device *dev = skb->dev;
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
BUGMSG(D_PROTO,
"tx: can't build header for encap %02Xh; load a protocol driver.\n",
lp->default_proto[daddr]);
/* always fails */
return 0;
}
/* the "do nothing" prepare_tx function warns that there's nothing to do. */
static int null_prepare_tx(struct net_device *dev, struct archdr *pkt,
int length, int bufnum)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct arc_hardware newpkt;
BUGMSG(D_PROTO, "tx: no encap for this host; load a protocol driver.\n");
/* send a packet to myself -- will never get received, of course */
newpkt.source = newpkt.dest = dev->dev_addr[0];
/* only one byte of actual data (and it's random) */
newpkt.offset[0] = 0xFF;
lp->hw.copy_to_card(dev, bufnum, 0, &newpkt, ARC_HDR_SIZE);
return 1; /* done */
}
/*
* Linux ARCnet driver - COM20020 chipset support
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
* Written 1999 by Martin Mares <mj@suse.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 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/malloc.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;
#ifndef MODULE
arcnet_init();
#endif
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 (check_region(ioaddr, ARCNET_TOTAL_SIZE))
{
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);
return -ENODEV;
}
if (com20020_check(dev))
return -ENODEV;
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");
return -ENODEV;
}
}
}
return com20020_found(dev, 0);
}
#ifdef MODULE
static struct net_device *my_dev;
/* Module parameters */
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; /* use eg. device="arc1" to change name */
static int timeout = 3;
static int backplane = 0;
static int clock = 0;
MODULE_PARM(node, "i");
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(device, "s");
MODULE_PARM(timeout, "i");
MODULE_PARM(backplane, "i");
MODULE_PARM(clock, "i");
static void com20020isa_open_close(struct net_device *dev, bool open)
{
if (open)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
int init_module(void)
{
struct net_device *dev;
struct arcnet_local *lp;
int err;
dev = dev_alloc(device ? : "arc%d", &err);
if (!dev)
return err;
lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (!lp)
return -ENOMEM;
memset(lp, 0, sizeof(struct arcnet_local));
if (node && node != 0xff)
dev->dev_addr[0] = node;
lp->backplane = backplane;
lp->clock = clock & 7;
lp->timeout = timeout & 3;
lp->hw.open_close_ll = com20020isa_open_close;
dev->base_addr = io;
dev->irq = irq;
if (dev->irq == 2)
dev->irq = 9;
if (com20020isa_probe(dev))
return -EIO;
my_dev = dev;
return 0;
}
void cleanup_module(void)
{
struct net_device *dev = my_dev;
if (dev->start)
dev->stop(dev);
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
unregister_netdev(dev);
kfree(dev->priv);
kfree(dev);
}
#else
static int __init com20020isa_setup(char *s)
{
struct net_device *dev;
struct arcnet_local *lp;
int ints[8];
s = get_options(s, 8, ints);
if (!ints[0])
return 1;
dev = alloc_bootmem(sizeof(struct net_device) + sizeof(struct arcnet_local) + 10);
memset(dev, 0, sizeof(struct net_device) + sizeof(struct arcnet_local) + 10);
lp = dev->priv = (struct arcnet_local *)(dev+1);
dev->name = (char *)(lp+1);
dev->init = com20020isa_probe;
switch (ints[0]) {
default: /* ERROR */
printk("com90xx: Too many arguments.\n");
case 6: /* Timeout */
lp->timeout = ints[6];
case 5: /* CKP value */
lp->clock = ints[5];
case 4: /* Backplane flag */
lp->backplane = ints[4];
case 3: /* Node ID */
dev->dev_addr[0] = ints[3];
case 2: /* IRQ */
dev->irq = ints[2];
case 1: /* IO address */
dev->base_addr = ints[1];
}
if (*s)
strncpy(dev->name, s, 9);
else
strcpy(dev->name, "arc%d");
if (register_netdev(dev))
printk(KERN_ERR "com20020: Cannot register arcnet device\n");
return 1;
}
__setup("com20020=", com20020isa_setup);
#endif /* MODULE */
/*
* Linux ARCnet driver - COM20020 PCI support (Contemporary Controls PCI20)
*
* Written 1994-1999 by Avery Pennarun,
* based on an ISA version by David Woodhouse.
* Written 1999 by Martin Mares <mj@suse.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 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/malloc.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"
#ifdef MODULE
static struct net_device *cards[16];
static int numcards;
#endif
static void com20020pci_open_close(struct net_device *dev, bool open)
{
if (open)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
/*
* No need to probe for PCI cards - just ask the PCI layer and launch all the
* ones we find.
*/
static int __init com20020pci_probe(char *name_template, int node, int backplane, int clock, int timeout)
{
struct net_device *dev;
struct arcnet_local *lp;
struct pci_dev *pdev = NULL;
int ioaddr, gotone = 0, err;
BUGLVL(D_NORMAL) printk(VERSION);
while ((pdev = pci_find_device(0x1571, 0xa004, pdev)))
{
if (pci_enable_device(pdev))
continue;
dev = dev_alloc(name_template ? : "arc%d", &err);
if (!dev)
return err;
lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (!lp)
return -ENOMEM;
memset(lp, 0, sizeof(struct arcnet_local));
ioaddr = pdev->resource[2].start;
dev->base_addr = ioaddr;
dev->irq = pdev->irq;
dev->dev_addr[0] = node;
lp->backplane = backplane;
lp->clock = clock;
lp->timeout = timeout;
lp->hw.open_close_ll = com20020pci_open_close;
BUGMSG(D_INIT, "PCI BIOS reports a device at %Xh, IRQ %d\n",
ioaddr, dev->irq);
if (check_region(ioaddr, ARCNET_TOTAL_SIZE))
{
BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n",
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
continue;
}
if (ASTATUS() == 0xFF)
{
BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, "
"but seems empty!\n", ioaddr);
continue;
}
if (com20020_check(dev))
continue;
if (!com20020_found(dev, SA_SHIRQ))
{
#ifdef MODULE
cards[numcards++] = dev;
#endif
gotone++;
}
}
return gotone ? 0 : -ENODEV;
}
#ifdef MODULE
/* Module parameters */
static int node = 0;
static char *device; /* use eg. device="arc1" to change name */
static int timeout = 3;
static int backplane = 0;
static int clock = 0;
MODULE_PARM(node, "i");
MODULE_PARM(device, "s");
MODULE_PARM(timeout, "i");
MODULE_PARM(backplane, "i");
MODULE_PARM(clock, "i");
int init_module(void)
{
return com20020pci_probe(device, node, backplane, clock & 7, timeout & 3);
}
void cleanup_module(void)
{
struct net_device *dev;
int count;
for (count = 0; count < numcards; count++)
{
dev = cards[count];
if (dev->start)
dev->stop(dev);
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
unregister_netdev(dev);
kfree(dev->priv);
kfree(dev);
}
}
#else
void __init com20020pci_probe_all(void)
{
com20020pci_probe(NULL, 0, 0, 0, 3);
}
#endif /* MODULE */
/*
* Linux ARCnet driver - COM20020 chipset support
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
* Written 1999 by Martin Mares <mj@suse.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 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/malloc.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[] =
{"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_openclose(struct net_device *dev, bool open);
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_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 __init com20020_check(struct net_device *dev)
{
int ioaddr = dev->base_addr, status;
struct arcnet_local *lp = dev->priv;
ARCRESET0;
mdelay(RESETtime);
lp->setup = lp->clock << 1;
REGSETUP;
SETCONF(lp->config);
outb(lp->setup, ioaddr + 7);
lp->config = 0x21 | (lp->timeout << 3) | (lp->backplane << 2);
/* set node ID to 0x42 (but transmitter is disabled, so it's okay) */
SETCONF(lp->config);
outb(0x42, ioaddr + 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 + 8), ioaddr + 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 __init 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 = (struct arcnet_local *)dev->priv;
lp->hw.command = com20020_command;
lp->hw.status = com20020_status;
lp->hw.intmask = com20020_setmask;
lp->hw.reset = com20020_reset;
lp->hw.open_close = com20020_openclose;
lp->hw.copy_to_card = com20020_copy_to_card;
lp->hw.copy_from_card = com20020_copy_from_card;
dev->set_multicast_list = com20020_set_mc_list;
/* Fill in the fields of the device structure with generic
* values.
*/
arcdev_setup(dev);
if (!dev->dev_addr[0])
dev->dev_addr[0] = inb(ioaddr + 8); /* FIXME: do this some other way! */
lp->setup = lp->clock << 1;
REGSETUP;
SETCONF(lp->config);
outb(lp->setup, ioaddr + 7);
lp->config = 0x20 | (lp->timeout << 3) | (lp->backplane << 2) | 1;
/* Default 0x38 + register: Node ID */
SETCONF(lp->config);
outb(dev->dev_addr[0], ioaddr + 7);
/* 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;
}
/* reserve the I/O region - guaranteed to work by check_region */
request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)");
dev->base_addr = ioaddr;
BUGMSG(D_NORMAL, "COM20020: station %02Xh found at %03lXh, IRQ %d.\n",
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);
if (lp->setup)
{
BUGMSG(D_NORMAL, "Using CKP %d - data rate %s.\n",
lp->setup >> 1, clockrates[lp->setup >> 1]);
}
if (!dev->init && register_netdev(dev))
{
free_irq(dev->irq, dev);
release_region(ioaddr, ARCNET_TOTAL_SIZE);
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 = (struct arcnet_local *)dev->priv;
short ioaddr = dev->base_addr;
u_char inbyte;
BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n",
dev->name, ASTATUS());
lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2);
/* power-up defaults */
SETCONF(lp->config);
if (really_reset)
{
/* reset the card */
ARCRESET;
mdelay(RESETtime * 2); /* COM20020 seems to be slower sometimes */
}
/* clear flags & end reset */
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
/* verify that the ARCnet signature byte is present */
com20020_copy_from_card(dev, 0, 0, &inbyte, 1);
if (inbyte != 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 com20020_setmask(struct net_device *dev, int mask)
{
short ioaddr = dev->base_addr;
AINTMASK(mask);
}
static void com20020_command(struct net_device *dev, int cmd)
{
short ioaddr = dev->base_addr;
ACOMMAND(cmd);
}
static int com20020_status(struct net_device *dev)
{
short ioaddr = dev->base_addr;
return ASTATUS();
}
static void com20020_openclose(struct net_device *dev, bool open)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr = dev->base_addr;
if (open)
MOD_INC_USE_COUNT;
else
{
/* disable transmitter */
lp->config &= ~TXENcfg;
SETCONF(lp->config);
MOD_DEC_USE_COUNT;
}
lp->hw.open_close_ll(dev, open);
}
/* 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");
REGSETUP;
SETCONF(lp->config);
lp->setup |= PROMISCset;
outb(lp->setup, _SETUP);
}
else
/* Disable promiscuous mode, use normal mode */
{
if ((lp->setup & PROMISCset))
BUGMSG(D_NORMAL, "Resetting promiscuous flag...\n");
REGSETUP;
SETCONF(lp->config);
lp->setup &= ~PROMISCset;
outb(lp->setup, _SETUP);
}
}
/*
* FIXME: put this somewhere!
*
if ((dstatus = inb(_DIAGSTAT)) & NEWNXTIDflag)
{
REGNXTID;
SETCONF(lp->config);
BUGMSG(D_EXTRA, "New NextID detected: %X\n", inb(ioaddr + 7));
}
*/
#ifdef MODULE
EXPORT_SYMBOL(com20020_check);
EXPORT_SYMBOL(com20020_found);
int init_module(void)
{
BUGLVL(D_NORMAL) printk(VERSION);
return 0;
}
void cleanup_module(void)
{
}
#endif /* MODULE */
/*
* Linux ARCnet driver - COM90xx chipset (IO-mapped buffers)
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
* Written 1999 by Martin Mares <mj@suse.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 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/ioport.h>
#include <linux/malloc.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_openclose(struct net_device *dev, bool open);
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;
#ifndef MODULE
arcnet_init();
#endif
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 (check_region(ioaddr, ARCNET_TOTAL_SIZE)) {
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);
return -ENODEV;
}
inb(_RESET);
mdelay(RESETtime);
status = ASTATUS();
if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
BUGMSG(D_INIT_REASONS, "Status invalid (%Xh).\n", status);
return -ENODEV;
}
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);
return -ENODEV;
}
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);
return -ENODEV;
}
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");
return -ENODEV;
}
}
return com90io_found(dev);
}
/* 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;
/* 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 */
request_region(dev->base_addr, ARCNET_TOTAL_SIZE, "arcnet (COM90xx-IO)");
/* Initialize the rest of the device structure. */
dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (!dev->priv) {
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
return -ENOMEM;
}
memset(dev->priv, 0, sizeof(struct arcnet_local));
lp = (struct arcnet_local *) (dev->priv);
lp->hw.command = com90io_command;
lp->hw.status = com90io_status;
lp->hw.intmask = com90io_setmask;
lp->hw.reset = com90io_reset;
lp->hw.open_close = com90io_openclose;
lp->hw.copy_to_card = com90io_copy_to_card;
lp->hw.copy_from_card = com90io_copy_from_card;
/*
* Fill in the fields of the device structure with generic
* values.
*/
arcdev_setup(dev);
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);
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 = (struct arcnet_local *) 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_openclose(struct net_device *dev, int open)
{
if (open)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
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));
}
#ifdef MODULE
static struct net_device *my_dev;
/* Module parameters */
static int io = 0x0; /* use the insmod io= irq= shmem= options */
static int irq = 0;
static char *device; /* use eg. device=arc1 to change name */
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(device, "s");
int init_module(void)
{
struct net_device *dev;
int err;
dev = dev_alloc(device ? : "arc%d", &err);
if (!dev)
return err;
dev->base_addr = io;
dev->irq = irq;
if (dev->irq == 2)
dev->irq = 9;
if (com90io_probe(dev))
return -EIO;
my_dev = dev;
return 0;
}
void cleanup_module(void)
{
struct net_device *dev = my_dev;
int ioaddr = dev->base_addr;
if (dev->start)
dev->stop(dev);
/* Flush TX and disable RX */
AINTMASK(0); /* disable IRQ's */
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
/* 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);
unregister_netdev(dev);
kfree(dev->priv);
kfree(dev);
}
#else
static int __init com90io_setup(char *s)
{
struct net_device *dev;
int ints[4];
s = get_options(s, 4, ints);
if (!ints[0])
return 1;
dev = alloc_bootmem(sizeof(struct net_device) + 10);
memset(dev, 0, sizeof(struct net_device) + 10);
dev->name = (char *)(dev+1);
dev->init = com90io_probe;
switch (ints[0]) {
default: /* ERROR */
printk("com90io: Too many arguments.\n");
case 2: /* IRQ */
dev->irq = ints[2];
case 1: /* IO address */
dev->base_addr = ints[1];
}
if (*s)
strncpy(dev->name, s, 9);
else
strcpy(dev->name, "arc%d");
if (register_netdev(dev))
printk(KERN_ERR "com90io: Cannot register arcnet device\n");
return 1;
}
__setup("com90io=", com90io_setup);
#endif /* MODULE */
/*
* Linux ARCnet driver - COM90xx chipset (memory-mapped buffers)
*
* Written 1994-1999 by Avery Pennarun.
* Written 1999 by Martin Mares <mj@suse.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 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/ioport.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/bootmem.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(struct net_device *dev, 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_openclose(struct net_device *dev, bool open);
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;
int __init com90xx_probe(struct net_device *dev)
{
int count, status, ioaddr, numprint, airq, retval = -ENODEV, 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 *shmem;
if (!dev && com90xx_skip_probe)
return -ENODEV;
#ifndef MODULE
arcnet_init();
#endif
BUGLVL(D_NORMAL) printk(VERSION);
/* set up the arrays where we'll store the possible probe addresses */
numports = numshmems = 0;
if (dev && dev->base_addr)
ports[numports++] = dev->base_addr;
else
for (count = 0x200; count <= 0x3f0; count += 16)
ports[numports++] = count;
if (dev && dev->mem_start)
shmems[numshmems++] = dev->mem_start;
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");
BUGMSG(D_INIT, "S1: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
ioaddr = *port;
if (check_region(*port, ARCNET_TOTAL_SIZE))
{
BUGMSG2(D_INIT_REASONS, "(check_region)\n");
BUGMSG(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
port--;
continue;
}
if (ASTATUS() == 0xFF)
{
BUGMSG2(D_INIT_REASONS, "(empty)\n");
BUGMSG(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
port--;
continue;
}
inb(_RESET); /* begin resetting card */
BUGMSG2(D_INIT_REASONS, "\n");
BUGMSG(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
}
BUGMSG2(D_INIT, "\n");
if (!numports)
{
BUGMSG(D_NORMAL, "S1: No ARCnet cards found.\n");
return -ENODEV;
}
/* 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");
BUGMSG(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 (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++)
{
u_long ptr = *shmem;
numprint++;
numprint %= 8;
if (!numprint)
{
BUGMSG2(D_INIT, "\n");
BUGMSG(D_INIT, "S3: ");
}
BUGMSG2(D_INIT, "%lXh ", *shmem);
if (check_mem_region(*shmem, BUFFER_SIZE))
{
BUGMSG2(D_INIT_REASONS, "(check_mem_region)\n");
BUGMSG(D_INIT_REASONS, "Stage 3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*shmem = shmems[numshmems - 1];
numshmems--;
shmem--;
continue;
}
if (isa_readb(ptr) != TESTvalue)
{
BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n",
isa_readb(ptr), TESTvalue);
BUGMSG(D_INIT_REASONS, "S3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*shmem = shmems[numshmems - 1];
numshmems--;
shmem--;
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");
BUGMSG(D_INIT_REASONS, "S3: ");
*shmem = shmems[numshmems - 1];
numshmems--;
shmem--;
continue;
}
BUGMSG2(D_INIT_REASONS, "\n");
BUGMSG(D_INIT_REASONS, "S3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
}
BUGMSG2(D_INIT, "\n");
if (!numshmems)
{
BUGMSG(D_NORMAL, "S3: No ARCnet cards found.\n");
return -ENODEV;
}
/* Stage 4: something of a dummy, to report the shmems that are
* still possible after stage 3.
*/
numprint = -1;
for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++)
{
numprint++;
numprint %= 8;
if (!numprint)
{
BUGMSG2(D_INIT, "\n");
BUGMSG(D_INIT, "S4: ");
}
BUGMSG2(D_INIT, "%lXh ", *shmem);
}
BUGMSG2(D_INIT, "\n");
/* Stage 5: for any ports that have the correct status, can disable
* the RESET flag, and (if no irq is given) generate an autoirq,
* register an ARCnet device.
*
* Currently, we can only register one device per probe, so quit
* after the first one is found.
*/
numprint = -1;
for (port = &ports[0]; port - ports < numports; port++)
{
numprint++;
numprint %= 8;
if (!numprint)
{
BUGMSG2(D_INIT, "\n");
BUGMSG(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);
BUGMSG(D_INIT_REASONS, "S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
port--;
continue;
}
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
status = ASTATUS();
if (status & RESETflag)
{
BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n",
status);
BUGMSG(D_INIT_REASONS, "S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
port--;
continue;
}
/* skip this completely if an IRQ was given, because maybe
* we're on a machine that locks during autoirq!
*/
if (!dev || !dev->irq)
{
/* if we do this, we're sure to get an IRQ since the
* card has just reset and the NORXflag is on until
* we tell it to start receiving.
*/
airqmask = probe_irq_on();
AINTMASK(NORXflag);
udelay(1);
AINTMASK(0);
airq = probe_irq_off(airqmask);
if (airq <= 0)
{
BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq);
BUGMSG(D_INIT_REASONS, "S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
port--;
continue;
}
}
else
{
airq = dev->irq;
}
BUGMSG2(D_INIT, "(%d,", airq);
openparen = 1;
/* Everything seems okay. But which shmem, if any, puts
* back its signature byte when the card is reset?
*
* If there are multiple cards installed, there might be
* multiple shmems still in the list.
*/
#ifdef FAST_PROBE
if (numports > 1 || numshmems > 1)
{
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 (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++)
{
u_long ptr = *shmem;
if (isa_readb(ptr) == TESTvalue)
{ /* found one */
BUGMSG2(D_INIT, "%lXh)\n", *shmem);
openparen = 0;
/* register the card */
retval = com90xx_found(dev, *port, airq, *shmem);
numprint = -1;
/* remove shmem from the list */
*shmem = shmems[numshmems - 1];
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;
}
*port = ports[numports - 1];
numports--;
port--;
}
BUGLVL(D_INIT_REASONS) printk("\n");
/* Now put back TESTvalue on all leftover shmems. */
for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++)
isa_writeb(TESTvalue, *shmem);
if (retval && dev && !numcards)
BUGMSG(D_NORMAL, "S5: No ARCnet cards found.\n");
return retval;
}
/* Set up the struct net_device associated with this card. Called after
* probing succeeds.
*/
static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq,
u_long shmem)
{
struct net_device *dev = dev0;
struct arcnet_local *lp;
u_long first_mirror, last_mirror;
int mirror_size, err;
/* allocate struct net_device if we don't have one yet */
if (!dev && !(dev = dev_alloc("arc%d", &err)))
{
BUGMSG(D_NORMAL, "Can't allocate device!\n");
return err;
}
lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (!lp)
{
BUGMSG(D_NORMAL, "Can't allocate device data!\n");
goto err_free_dev;
}
/* find the real shared memory start/end points, including mirrors */
/* guess the actual size of one "memory mirror" - the number of
* bytes between copies of the shared memory. On most cards, it's
* 2k (or there are no mirrors at all) but on some, it's 4k.
*/
mirror_size = MIRROR_SIZE;
if (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;
dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0;
dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1;
/* Initialize the rest of the device structure. */
memset(lp, 0, sizeof(struct arcnet_local));
lp->hw.command = com90xx_command;
lp->hw.status = com90xx_status;
lp->hw.intmask = com90xx_setmask;
lp->hw.reset = com90xx_reset;
lp->hw.open_close = com90xx_openclose;
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_dev_priv;
}
/* Fill in the fields of the device structure with generic values. */
arcdev_setup(dev);
/* get and check the station ID from offset 1 in shmem */
dev->dev_addr[0] = readb(lp->mem_start + 1);
/* 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_unmap;
}
dev->irq = airq;
/* reserve the I/O and memory regions - guaranteed to work by check_region */
request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (90xx)");
request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)");
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 (!dev0 && register_netdev(dev))
goto err_release;
cards[numcards++] = dev;
return 0;
err_release:
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
err_unmap:
iounmap(lp->mem_start);
err_free_dev_priv:
kfree(dev->priv);
err_free_dev:
if (!dev0)
kfree(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 = (struct arcnet_local *) 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);
}
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)
{
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_openclose(struct net_device *dev, bool open)
{
if (open)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
void *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 = (struct arcnet_local *) dev->priv;
void *memaddr = lp->mem_start + bufnum*512 + offset;
TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
}
#ifdef MODULE
/* Module parameters */
static int io = 0x0; /* use the insmod io= irq= shmem= options */
static int irq = 0;
static int shmem = 0;
static char *device; /* use eg. device=arc1 to change name */
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(shmem, "i");
MODULE_PARM(device, "s");
int init_module(void)
{
struct net_device *dev;
int err;
if (io || irq || shmem || device)
{
dev = dev_alloc(device ? : "arc%d", &err);
if (!dev)
return err;
dev->base_addr = io;
dev->irq = irq;
if (dev->irq == 2)
dev->irq = 9;
dev->mem_start = shmem;
com90xx_probe(dev);
}
else com90xx_probe(NULL);
if (!numcards)
return -EIO;
return 0;
}
void cleanup_module(void)
{
struct net_device *dev;
struct arcnet_local *lp;
int count;
for (count = 0; count < numcards; count++)
{
dev = cards[count];
lp = (struct arcnet_local *) dev->priv;
if (dev->start)
dev->stop(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);
unregister_netdev(dev);
kfree(dev->priv);
kfree(dev);
}
}
#else
static int __init com90xx_setup(char *s)
{
struct net_device *dev;
int ints[8];
com90xx_skip_probe = 1;
s = get_options(s, 8, ints);
if (!ints[0] && !*s) {
printk("com90xx: Disabled.\n");
return 1;
}
dev = alloc_bootmem(sizeof(struct net_device) + 10);
memset(dev, 0, sizeof(struct net_device) + 10);
dev->name = (char *)(dev+1);
dev->init = com90xx_probe;
switch (ints[0]) {
default: /* ERROR */
printk("com90xx: Too many arguments.\n");
case 3: /* Mem address */
dev->mem_start = ints[3];
case 2: /* IRQ */
dev->irq = ints[2];
case 1: /* IO address */
dev->base_addr = ints[1];
}
if (*s)
strncpy(dev->name, s, 9);
else
strcpy(dev->name, "arc%d");
if (register_netdev(dev))
printk(KERN_ERR "com90xx: Cannot register arcnet device\n");
return 1;
}
__setup("com90xx=", com90xx_setup);
#endif /* MODULE */
/*
* 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 Public License as
* modified by SRC, incorporated herein by reference.
*
* **********************
*
* For more details, see drivers/net/arcnet.c
*
* **********************
*/
#include <linux/module.h>
#include <linux/config.h> /* for CONFIG_INET */
#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, 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 = {
's',
XMTU - RFC1051_HDR_SIZE,
rx,
build_header,
prepare_tx
};
void __init arcnet_rfc1051_init(void)
{
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;
}
#ifdef MODULE
int __init init_module(void)
{
printk(VERSION);
arcnet_rfc1051_init();
return 0;
}
void cleanup_module(void)
{
arcnet_unregister_proto(&rfc1051_proto);
}
#endif /* MODULE */
/*
* 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 = (struct arcnet_local *)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 = (struct arcnet_local *)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);
}
/*
* Create the ARCnet hard/soft headers for RFC1051.
*/
static int build_header(struct sk_buff *skb, unsigned short type,
uint8_t daddr)
{
struct net_device *dev = skb->dev;
struct arcnet_local *lp = (struct arcnet_local *)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 = (struct arcnet_local *)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 */
}
/*
* 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 Public License as
* modified by SRC, incorporated herein by reference.
*
* **********************
*
* For more details, see drivers/net/arcnet.c
*
* **********************
*/
#include <linux/module.h>
#include <linux/config.h> /* for CONFIG_INET */
#include <linux/init.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/arcdevice.h>
#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, 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 = {
'a',
1500, /* could be more, but some receivers can't handle it... */
rx,
build_header,
prepare_tx,
continue_tx
};
void __init arcnet_rfc1201_init(void)
{
arc_proto_map[ARC_P_IP]
= 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;
}
#ifdef MODULE
int __init init_module(void)
{
printk(VERSION);
arcnet_rfc1201_init();
return 0;
}
void cleanup_module(void)
{
arcnet_unregister_proto(&rfc1201_proto);
}
#endif /* MODULE */
/*
* 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 = (struct arcnet_local *)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_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 = (struct arcnet_local *)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;
kfree_skb(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);
}
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);
kfree_skb(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++;
kfree_skb(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->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->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;
kfree_skb(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;
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
skb->protocol = type_trans(skb, dev);
netif_rx(skb);
}
}
}
/* Create the ARCnet hard/soft headers for RFC1201. */
static int build_header(struct sk_buff *skb, unsigned short type,
uint8_t daddr)
{
struct net_device *dev = skb->dev;
struct arcnet_local *lp = (struct arcnet_local *)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_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 = (struct arcnet_local *)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 = { soft->proto, 0xFF, 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 = (struct arcnet_local *)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 = (struct arcnet_local *)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;
}
/* $Id: com20020.c,v 1.6 1997/11/09 11:04:58 mj Exp $
Written 1997 by David Woodhouse <dwmw2@cam.ac.uk>
Derived from the original arcnet.c,
Written 1994-1996 by Avery Pennarun,
which was in turn derived from skeleton.c by Donald Becker.
**********************
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 Public License as
modified by SRC, incorporated herein by reference.
**********************
For more details, see drivers/net/arcnet.c
**********************
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/if_arcnet.h>
#include <linux/arcdevice.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <net/arp.h>
/* Internal function declarations */
static int arc20020_probe(struct net_device *dev);
static void arc20020_rx(struct net_device *dev,int recbuf);
static int arc20020_found(struct net_device *dev,int ioaddr,int airq);
static void arc20020_inthandler (struct net_device *dev);
static int arc20020_reset (struct net_device *dev, int reset_delay);
static void arc20020_setmask (struct net_device *dev, u_char mask);
static void arc20020_command (struct net_device *dev, u_char command);
static u_char arc20020_status (struct net_device *dev);
static void arc20020_en_dis_able_TX (struct net_device *dev, int enable);
static void arc20020_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen,
char *data,int length,int daddr,int exceptA, int offset);
static void arc20020_openclose(int open);
static void arc20020_set_mc_list(struct net_device *dev);
static u_char get_buffer_byte (struct net_device *dev, unsigned offset);
static void put_buffer_byte (struct net_device *dev, unsigned offset, u_char datum);
static void get_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest);
static void put_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest);
/* Module parameters */
#ifdef MODULE
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; /* use eg. device="arc1" to change name */
static int timeout=3;
static int backplane=0;
static int clock=0;
MODULE_PARM(node,"i");
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(device, "s");
MODULE_PARM(timeout,"i");
MODULE_PARM(backplane,"i");
MODULE_PARM(clock,"i");
#else
void __init com20020_setup (char *str, int *ints);
extern struct net_device arcnet_devs[];
extern char arcnet_dev_names[][10];
extern int arcnet_num_devs;
#endif
/* Handy defines for ARCnet specific stuff */
static char *clockrates[]={"2.5 Mb/s","1.25Mb/s","625 Kb/s","312.5 Kb/s",
"156.25 Kb/s", "Reserved", "Reserved",
"Reserved"};
/* The number of low I/O ports used by the card. */
#define ARCNET_TOTAL_SIZE 9
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define _CONFIG (ioaddr+6) /* Configuration register */
#define _DIAGSTAT (ioaddr+1) /* Diagnostic status register */
#define _MEMDATA (ioaddr+4) /* Data port for IO-mapped memory */
#define _ADDR_HI (ioaddr+2) /* Control registers for said */
#define _ADDR_LO (ioaddr+3)
#define RDDATAflag 0x80 /* Next access is a read/~write */
#define NEWNXTIDflag 0x02 /* ID to which token is passed has changed */
#define TXENflag 0x20 /* Enable TX (in CONFIG register) */
#define PROMISCflag 0x10 /* Enable RCV_ALL (in SETUP register) */
#define REGTENTID (lp->config &= ~3);
#define REGNID (lp->config = (lp->config&~2)|1);
#define REGSETUP (lp->config = (lp->config&~1)|2);
#define REGNXTID (lp->config |= 3);
#define ARCRESET { outb(lp->config | 0x80, _CONFIG); \
udelay(5); \
outb(lp->config , _CONFIG); \
}
#define ARCRESET0 { outb(0x18 | 0x80, _CONFIG); \
udelay(5); \
outb(0x18 , _CONFIG); \
}
#define ARCSTATUS inb(_STATUS)
#define ACOMMAND(cmd) outb((cmd),_COMMAND)
#define AINTMASK(msk) outb((msk),_INTMASK)
#define SETCONF outb((lp->config),_CONFIG)
/****************************************************************************
* *
* IO-mapped operation routines *
* *
****************************************************************************/
u_char get_buffer_byte (struct net_device *dev, unsigned offset)
{
int ioaddr=dev->base_addr;
outb(offset >> 8 | RDDATAflag, _ADDR_HI);
outb(offset & 0xff, _ADDR_LO);
return inb(_MEMDATA);
}
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);
}
#undef ONE_AT_A_TIME_TX
#undef ONE_AT_A_TIME_RX
void get_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest)
{
int ioaddr=dev->base_addr;
outb( (offset >> 8) | AUTOINCflag | RDDATAflag, _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
}
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
}
static const char *version =
"com20020.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
/****************************************************************************
* *
* Probe and initialization *
* *
****************************************************************************/
/* 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
*/
int __init arc20020_probe(struct net_device *dev)
{
int ioaddr=dev->base_addr,status,delayval;
unsigned long airqmask;
BUGLVL(D_NORMAL) printk(version);
if (ioaddr<0x200)
{
BUGMSG(D_NORMAL,"No autoprobe for IO mapped cards; you "
"must specify the base address!\n");
return -ENODEV;
}
if (check_region(ioaddr, ARCNET_TOTAL_SIZE))
{
BUGMSG(D_NORMAL,"IO region %xh-%xh already allocated.\n",
ioaddr,ioaddr+ARCNET_TOTAL_SIZE-1);
return -ENXIO;
}
if (ARCSTATUS == 0xFF)
{
BUGMSG(D_NORMAL,"IO address %x empty\n",ioaddr);
return -ENODEV;
}
ARCRESET0;
JIFFER(RESETtime);
status=ARCSTATUS;
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+8),ioaddr+7);
ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear);
BUGMSG(D_INIT_REASONS,"Status after reset acknowledged: %X\n",status);
/* Reset card. */
outb(0x98,_CONFIG);
udelay(5);
outb(0x18,_CONFIG);
/* Read first loc'n of memory */
outb(0 | RDDATAflag | AUTOINCflag ,_ADDR_HI);
outb(0,_ADDR_LO);
if ((status=inb(_MEMDATA)) != 0xd1)
{
BUGMSG(D_NORMAL,"Signature byte not found.\n");
return -ENODEV;
}
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 %d:\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");
return -ENODEV;
}
}
}
return arc20020_found(dev,dev->base_addr,dev->irq);
}
/* Set up the struct net_device associated with this card. Called after
* probing succeeds.
*/
int __init arc20020_found(struct net_device *dev,int ioaddr,int airq)
{
struct arcnet_local *lp;
/* reserve the irq */
if (request_irq(airq,&arcnet_interrupt,0,"arcnet (COM20020)",dev))
{
BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq);
return -ENODEV;
}
dev->irq=airq;
/* reserve the I/O region - guaranteed to work by check_region */
request_region(ioaddr,ARCNET_TOTAL_SIZE,"arcnet (COM20020)");
dev->base_addr=ioaddr;
dev->mem_start=dev->mem_end=dev->rmem_start=dev->rmem_end=(long)NULL;
/* Initialize the rest of the device structure. */
dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (dev->priv == NULL)
{
free_irq(airq,dev);
release_region(ioaddr,ARCNET_TOTAL_SIZE);
return -ENOMEM;
}
memset(dev->priv,0,sizeof(struct arcnet_local));
lp=(struct arcnet_local *)(dev->priv);
lp->card_type = ARC_20020;
lp->card_type_str = "COM 20020";
lp->arcnet_reset=arc20020_reset;
lp->asetmask=arc20020_setmask;
lp->astatus=arc20020_status;
lp->acommand=arc20020_command;
lp->en_dis_able_TX=arc20020_en_dis_able_TX;
lp->openclose_device=arc20020_openclose;
lp->prepare_tx=arc20020_prepare_tx;
lp->inthandler=arc20020_inthandler;
dev->set_multicast_list = arc20020_set_mc_list;
/* Fill in the fields of the device structure with generic
* values.
*/
arcnet_setup(dev);
/* And now fill particular fields with arcnet values */
dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
dev->hard_header_len=sizeof(struct ClientData);
lp->sequence=1;
lp->recbuf=0;
BUGMSG(D_DURING,"ClientData header size is %d.\n",
sizeof(struct ClientData));
BUGMSG(D_DURING,"HardHeader size is %d.\n",
sizeof(struct archdr));
/* get and check the station ID from offset 1 in shmem */
lp->timeout = dev->dev_addr[3] & 3; dev->dev_addr[3]=0;
lp->backplane =dev->dev_addr[1] & 1; dev->dev_addr[1]=0;
lp->setup = (dev->dev_addr[2] & 7) << 1; dev->dev_addr[2]=0;
if (dev->dev_addr[0])
lp->stationid=dev->dev_addr[0];
else
lp->stationid=inb(ioaddr+8); /* FIX ME - We should check that
this is valid before using it */
lp->config = 0x21 | (lp->timeout << 3) | (lp->backplane << 2);
/* Default 0x38 + register: Node ID */
SETCONF;
outb(lp->stationid, ioaddr+7);
REGSETUP;
SETCONF;
outb(lp->setup, ioaddr+7);
if (!lp->stationid)
BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved "
"for broadcasts!\n");
else if (lp->stationid==255)
BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse "
"DOS networking programs!\n");
dev->dev_addr[0]=lp->stationid;
BUGMSG(D_NORMAL,"ARCnet COM20020: station %02Xh found at %03lXh, IRQ %d.\n",
lp->stationid, 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);
if (lp->setup)
{
BUGMSG (D_NORMAL, "Using CKP %d - Data rate %s.\n",
lp->setup >>1,clockrates[lp->setup >> 1] );
}
return 0;
}
/****************************************************************************
* *
* Utility routines *
* *
****************************************************************************/
/* 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 arc20020_reset(struct net_device *dev,int reset_delay)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
short ioaddr=dev->base_addr;
int delayval,recbuf=lp->recbuf;
if (reset_delay==3)
{
ARCRESET;
return 0;
}
/* no IRQ's, please! */
lp->intmask=0;
SETMASK;
BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
dev->name,ARCSTATUS);
lp->config = 0x20 | (lp->timeout<<3) | (lp->backplane<<2);
/* power-up defaults */
SETCONF;
if (reset_delay)
{
/* reset the card */
ARCRESET;
JIFFER(RESETtime);
}
ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd|CONFIGclear);
/* verify that the ARCnet signature byte is present */
if (get_buffer_byte(dev,0) != TESTvalue)
{
BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n");
return 1;
}
/* clear out status variables */
recbuf=lp->recbuf=0;
lp->txbuf=2;
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd|EXTconf);
/* and enable receive of our first packet to the first buffer */
EnableReceiver();
/* re-enable interrupts */
lp->intmask|=NORXflag;
#ifdef DETECT_RECONFIGS
lp->intmask|=RECONflag;
#endif
SETMASK;
/* done! return success. */
return 0;
}
/* 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.
* FIX ME - do multicast stuff, not just promiscuous.
*/
static void
arc20020_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 & PROMISCflag))
BUGMSG(D_NORMAL, "Setting promiscuous flag...\n");
REGSETUP;
SETCONF;
lp->setup|=PROMISCflag;
outb(lp->setup,ioaddr+7);
} else
/* Disable promiscuous mode, use normal mode */
{
if ((lp->setup & PROMISCflag))
BUGMSG(D_NORMAL, "Resetting promiscuous flag...\n");
REGSETUP;
SETCONF;
lp->setup &= ~PROMISCflag;
outb(lp->setup,ioaddr+7);
}
}
static void arc20020_openclose(int open)
{
if (open)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
static void arc20020_en_dis_able_TX(struct net_device *dev, int enable)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr;
lp->config=enable?(lp->config | TXENflag):(lp->config & ~TXENflag);
SETCONF;
}
static void arc20020_setmask(struct net_device *dev, u_char mask)
{
short ioaddr=dev->base_addr;
AINTMASK(mask);
}
static u_char arc20020_status(struct net_device *dev)
{
short ioaddr=dev->base_addr;
return ARCSTATUS;
}
static void arc20020_command(struct net_device *dev, u_char cmd)
{
short ioaddr=dev->base_addr;
ACOMMAND(cmd);
}
/* The actual interrupt handler routine - handle various IRQ's generated
* by the card.
*/
static void
arc20020_inthandler(struct net_device *dev)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr, status, boguscount = 3, didsomething,
dstatus;
AINTMASK(0);
BUGMSG(D_DURING,"in arc20020_inthandler (status=%Xh, intmask=%Xh)\n",
ARCSTATUS,lp->intmask);
do
{
status = ARCSTATUS;
didsomething=0;
/* RESET flag was enabled - card is resetting and if RX
* is disabled, it's NOT because we just got a packet.
*/
if (status & RESETflag)
{
BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
status);
arc20020_reset(dev,0);
/* all other flag values are just garbage */
break;
}
/* RX is inhibited - we must have received something. */
if (status & lp->intmask & NORXflag)
{
int recbuf=lp->recbuf=!lp->recbuf;
int oldaddr=0;
BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
status);
/* enable receive of our next packet */
EnableReceiver();
if (lp->intx)
oldaddr=(inb(_ADDR_HI)<<8) | inb(_ADDR_LO);
/* Got a packet. */
arc20020_rx(dev,!recbuf);
if (lp->intx)
{
outb( (oldaddr >> 8), _ADDR_HI);
outb( oldaddr & 0xff, _ADDR_LO);
}
didsomething++;
}
/* it can only be an xmit-done irq if we're xmitting :) */
/*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
if (status & lp->intmask & TXFREEflag)
{
struct Outgoing *out=&(lp->outgoing);
int was_sending=lp->sending;
lp->intmask &= ~TXFREEflag;
lp->in_txhandler++;
if (was_sending) lp->sending--;
BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
status,out->numsegs,out->segnum,out->skb);
if (was_sending && !(status&TXACKflag))
{
if (lp->lasttrans_dest != 0)
{
BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n",
status,lp->lasttrans_dest);
lp->stats.tx_errors++;
lp->stats.tx_carrier_errors++;
}
else
{
BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n",
status,
lp->lasttrans_dest);
}
}
/* send packet if there is one */
arcnet_go_tx(dev,0);
didsomething++;
if (lp->intx)
{
BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
ARCSTATUS,lp->intx);
lp->in_txhandler--;
continue;
}
if (!lp->outgoing.skb)
{
BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
lp->in_txhandler--;
continue;
}
/* if more than one segment, and not all segments
* are done, then continue xmit.
*/
if (out->segnum<out->numsegs)
arcnetA_continue_tx(dev);
arcnet_go_tx(dev,0);
/* if segnum==numsegs, the transmission is finished;
* free the skb.
*/
if (out->segnum>=out->numsegs)
{
/* transmit completed */
out->segnum++;
if (out->skb)
{
lp->stats.tx_bytes += out->skb->len;
dev_kfree_skb(out->skb);
}
out->skb=NULL;
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
}
didsomething++;
lp->in_txhandler--;
}
else if (lp->txready && !lp->sending && !lp->intx)
{
BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n",
status);
arcnet_go_tx(dev,0);
didsomething++;
}
if ((dstatus=inb(_DIAGSTAT)) & NEWNXTIDflag)
{
REGNXTID;
SETCONF;
BUGMSG(D_EXTRA,"New NextID detected: %X\n",inb(ioaddr+7));
}
#ifdef DETECT_RECONFIGS
if (status & (lp->intmask) & RECONflag)
{
ACOMMAND(CFLAGScmd|CONFIGclear);
lp->stats.tx_carrier_errors++;
#ifdef SHOW_RECONFIGS
BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh, diag status=%Xh, config=%X)\n",
status,dstatus,lp->config);
#endif /* SHOW_RECONFIGS */
#ifdef RECON_THRESHOLD
/* is the RECON info empty or old? */
if (!lp->first_recon || !lp->last_recon ||
jiffies-lp->last_recon > HZ*10)
{
if (lp->network_down)
BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
lp->first_recon=lp->last_recon=jiffies;
lp->num_recons=lp->network_down=0;
BUGMSG(D_DURING,"recon: clearing counters.\n");
}
else /* add to current RECON counter */
{
lp->last_recon=jiffies;
lp->num_recons++;
BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
lp->num_recons,
(lp->last_recon-lp->first_recon)/HZ,
lp->network_down);
/* if network is marked up;
* and first_recon and last_recon are 60+ sec
* apart;
* and the average no. of recons counted is
* > RECON_THRESHOLD/min;
* then print a warning message.
*/
if (!lp->network_down
&& (lp->last_recon-lp->first_recon)<=HZ*60
&& lp->num_recons >= RECON_THRESHOLD)
{
lp->network_down=1;
BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
}
else if (!lp->network_down
&& lp->last_recon-lp->first_recon > HZ*60)
{
/* reset counters if we've gone for
* over a minute.
*/
lp->first_recon=lp->last_recon;
lp->num_recons=1;
}
}
}
else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
{
if (lp->network_down)
BUGMSG(D_NORMAL,"cabling restored?\n");
lp->first_recon=lp->last_recon=0;
lp->num_recons=lp->network_down=0;
BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
#endif
}
#endif /* DETECT_RECONFIGS */
} while (--boguscount && didsomething);
BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
ARCSTATUS,boguscount);
BUGMSG(D_DURING,"\n");
SETMASK; /* put back interrupt mask */
}
/* A packet has arrived; grab it from the buffers and pass it to the generic
* arcnet_rx routing to deal with it.
*/
static void
arc20020_rx(struct net_device *dev,int recbuf)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr;
union ArcPacket packetbuf;
union ArcPacket *arcpacket=&packetbuf;
u_char *arcsoft;
short length,offset;
u_char daddr,saddr;
lp->stats.rx_packets++;
get_whole_buffer(dev,recbuf*512,4,(char *)arcpacket);
saddr=arcpacket->hardheader.source;
/* if source is 0, it's a "used" packet! */
if (saddr==0)
{
BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n",
ARCSTATUS);
lp->stats.rx_errors++;
return;
}
/* Set source address to zero to mark it as old */
put_buffer_byte(dev,recbuf*512,0);
arcpacket->hardheader.source=0;
daddr=arcpacket->hardheader.destination;
if (arcpacket->hardheader.offset1) /* Normal Packet */
{
offset=arcpacket->hardheader.offset1;
arcsoft=&arcpacket->raw[offset];
length=256-offset;
}
else /* ExtendedPacket or ExceptionPacket */
{
offset=arcpacket->hardheader.offset2;
arcsoft=&arcpacket->raw[offset];
length=512-offset;
}
get_whole_buffer(dev,recbuf*512+offset,length,(char *)arcpacket+offset);
arcnet_rx(lp, arcsoft, length, saddr, daddr);
BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx");
}
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnet_go_tx.
*/
static void
arc20020_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen,
char *data,int length,int daddr,int exceptA, int offset)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
length+=hdrlen;
BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr,length,data);
put_buffer_byte(dev, lp->txbuf*512+1, daddr);
/* load packet into shared memory */
if (length<=MTU) /* Normal (256-byte) Packet */
put_buffer_byte(dev, lp->txbuf*512+2, offset=offset?offset:256-length);
else if (length>=MinTU || offset) /* Extended (512-byte) Packet */
{
put_buffer_byte(dev, lp->txbuf*512+2, 0);
put_buffer_byte(dev, lp->txbuf*512+3, offset=offset?offset:512-length);
}
else if (exceptA) /* RFC1201 Exception Packet */
{
put_buffer_byte(dev, lp->txbuf*512+2, 0);
put_buffer_byte(dev, lp->txbuf*512+3, offset=512-length-4);
/* exception-specific stuff - these four bytes
* make the packet long enough to fit in a 512-byte
* frame.
*/
put_buffer_byte(dev, lp->txbuf*512+offset,hdr[0]);
put_whole_buffer(dev, lp->txbuf*512+offset+1,3,"\377\377\377");
offset+=4;
}
else /* "other" Exception packet */
{
/* RFC1051 - set 4 trailing bytes to 0 */
put_whole_buffer(dev,lp->txbuf*512+508,4,"\0\0\0\0");
/* now round up to MinTU */
put_buffer_byte(dev, lp->txbuf*512+2, 0);
put_buffer_byte(dev, lp->txbuf*512+3, offset=512-MinTU);
}
/* copy the packet into ARCnet shmem
* - the first bytes of ClientData header are skipped
*/
put_whole_buffer(dev, 512*lp->txbuf+offset, hdrlen,(u_char *)hdr);
put_whole_buffer(dev, 512*lp->txbuf+offset+hdrlen,length-hdrlen,data);
BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
daddr,length);
lp->lastload_dest=daddr;
lp->txready=lp->txbuf; /* packet is ready for sending */
}
/****************************************************************************
* *
* Kernel Loadable Module Support *
* *
****************************************************************************/
#ifdef MODULE
static struct net_device *cards[16]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
int init_module(void)
{
struct net_device *dev;
cards[0]=dev=(struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL);
if (!dev)
return -ENOMEM;
memset(dev, 0, sizeof(struct net_device));
dev->name=(char *)kmalloc(9, GFP_KERNEL);
if (!dev->name)
{
kfree(dev);
return -ENOMEM;
}
dev->init=arc20020_probe;
if (device)
strcpy(dev->name,device);
else arcnet_makename(dev->name);
if (node && node != 0xff)
dev->dev_addr[0]=node;
if (backplane) dev->dev_addr[1]=backplane?1:0;
if (clock) dev->dev_addr[2]=clock&7;
dev->dev_addr[3]=timeout&3;
dev->base_addr=io;
dev->irq=irq;
if (dev->irq==2) dev->irq=9;
if (register_netdev(dev) != 0)
return -EIO;
/* Increase use count of arcnet.o */
arcnet_use_count(1);
return 0;
}
void cleanup_module(void)
{
struct net_device *dev=cards[0];
int ioaddr=dev->base_addr;
if (dev->start) (*dev->stop)(dev);
/* Flush TX and disable RX */
if (ioaddr)
{
AINTMASK(0); /* disable IRQ's */
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
}
if (dev->irq)
{
free_irq(dev->irq,dev);
}
if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
/* Decrease use count of arcnet.o */
arcnet_use_count(0);
}
#else
void __init com20020_setup (char *str, int *ints)
{
struct net_device *dev;
if (arcnet_num_devs == MAX_ARCNET_DEVS)
{
printk("com20020: Too many ARCnet devices registered (max %d).\n",
MAX_ARCNET_DEVS);
return;
}
dev=&arcnet_devs[arcnet_num_devs];
if (ints[0] < 1)
{
printk("com20020: You must give an IO address.\n");
return;
}
dev->dev_addr[3]=3;
dev->init=arc20020_probe;
switch(ints[0])
{
case 7: /* ERROR */
printk("com20020: Too many arguments.\n");
case 6: /* Timeout */
dev->dev_addr[3]=(u_char)ints[6];
case 5: /* CKP value */
dev->dev_addr[2]=(u_char)ints[5];
case 4: /* Backplane flag */
dev->dev_addr[1]=(u_char)ints[4];
case 3: /* Node ID */
dev->dev_addr[0]=(u_char)ints[3];
case 2: /* IRQ */
dev->irq=ints[2];
case 1: /* IO address */
dev->base_addr=ints[1];
}
dev->name = (char *)&arcnet_dev_names[arcnet_num_devs];
if (str)
strncpy(dev->name, str, 9);
arcnet_num_devs++;
}
#endif /* MODULE */
/* $Id: com90io.c,v 1.6 1997/11/09 11:04:59 mj Exp $
Written 1997 by David Woodhouse <dwmw2@cam.ac.uk>
Derived from the original arcnet.c,
Written 1994-1996 by Avery Pennarun,
which was in turn derived from skeleton.c by Donald Becker.
**********************
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 Public License as
modified by SRC, incorporated herein by reference.
**********************
For more details, see drivers/net/arcnet.c
**********************
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/if_arcnet.h>
#include <linux/arcdevice.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <net/arp.h>
/* Internal function declarations */
static int arc90io_probe(struct net_device *dev);
static void arc90io_rx(struct net_device *dev,int recbuf);
static int arc90io_found(struct net_device *dev,int ioaddr,int airq);
static void arc90io_inthandler (struct net_device *dev);
static int arc90io_reset (struct net_device *dev, int reset_delay);
static void arc90io_setmask (struct net_device *dev, u_char mask);
static void arc90io_command (struct net_device *dev, u_char command);
static u_char arc90io_status (struct net_device *dev);
static void arc90io_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen,
char *data,int length,int daddr,int exceptA, int offset);
static void arc90io_openclose(int open);
static u_char get_buffer_byte (struct net_device *dev, unsigned offset);
static void put_buffer_byte (struct net_device *dev, unsigned offset, u_char datum);
static void get_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest);
static void put_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest);
/* Module parameters */
#ifdef MODULE
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; /* use eg. device="arc1" to change name */
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(device, "s");
#else
void __init com90io_setup (char *str, int *ints);
extern struct net_device arcnet_devs[];
extern char arcnet_dev_names[][10];
extern int arcnet_num_devs;
#endif
/* 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 */
#define ARCSTATUS inb(_STATUS)
#define ACOMMAND(cmd) outb((cmd),_COMMAND)
#define AINTMASK(msk) outb((msk),_INTMASK)
#define ARCRESET inb(_RESET)
#define SETCONF outb((lp->config),_CONFIG)
/****************************************************************************
* *
* IO-mapped operation routines *
* *
****************************************************************************/
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);
}
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);
}
#undef ONE_AT_A_TIME_TX
#undef ONE_AT_A_TIME_RX
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
}
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
}
static const char *version =
"com90io.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
/****************************************************************************
* *
* Probe and initialization *
* *
****************************************************************************/
/* 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
*/
int __init arc90io_probe(struct net_device *dev)
{
int ioaddr=dev->base_addr,status,delayval;
unsigned long airqmask;
BUGLVL(D_NORMAL) printk(version);
if (ioaddr<0x200)
{
BUGMSG(D_NORMAL,"No autoprobe for IO mapped cards; you "
"must specify the base address!\n");
return -ENODEV;
}
if (check_region(ioaddr, ARCNET_TOTAL_SIZE))
{
BUGMSG(D_INIT_REASONS,"IO check_region %x-%x failed.\n",
ioaddr,ioaddr+ARCNET_TOTAL_SIZE-1);
return -ENXIO;
}
if (ARCSTATUS == 0xFF)
{
BUGMSG(D_INIT_REASONS,"IO address %x empty\n",ioaddr);
return -ENODEV;
}
ARCRESET;
JIFFER(RESETtime);
status=ARCSTATUS;
if ((status & 0x9D)
!= (NORXflag|RECONflag|TXFREEflag|RESETflag))
{
BUGMSG(D_INIT_REASONS,"Status invalid (%Xh).\n",status);
return -ENODEV;
}
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=ARCSTATUS;
if (status & RESETflag)
{
BUGMSG(D_INIT_REASONS,"Eternal reset (status=%Xh)\n",status);
return -ENODEV;
}
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);
return -ENODEV;
}
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");
return -ENODEV;
}
}
return arc90io_found(dev,dev->base_addr,dev->irq);
}
/* Set up the struct net_device associated with this card. Called after
* probing succeeds.
*/
int __init arc90io_found(struct net_device *dev,int ioaddr,int airq)
{
struct arcnet_local *lp;
/* reserve the irq */
if (request_irq(airq,&arcnet_interrupt,0,"arcnet (COM90xx-IO)",dev))
{
BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq);
return -ENODEV;
}
dev->irq=airq;
/* reserve the I/O region - guaranteed to work by check_region */
request_region(ioaddr,ARCNET_TOTAL_SIZE,"arcnet (COM90xx-IO)");
dev->base_addr=ioaddr;
dev->mem_start=dev->mem_end=dev->rmem_start=dev->rmem_end=(long)NULL;
/* Initialize the rest of the device structure. */
dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (dev->priv == NULL)
{
free_irq(airq,dev);
release_region(ioaddr,ARCNET_TOTAL_SIZE);
return -ENOMEM;
}
memset(dev->priv,0,sizeof(struct arcnet_local));
lp=(struct arcnet_local *)(dev->priv);
lp->card_type = ARC_90xx_IO;
lp->card_type_str = "COM 90xx (IO)";
lp->arcnet_reset=arc90io_reset;
lp->asetmask=arc90io_setmask;
lp->astatus=arc90io_status;
lp->acommand=arc90io_command;
lp->openclose_device=arc90io_openclose;
lp->prepare_tx=arc90io_prepare_tx;
lp->inthandler=arc90io_inthandler;
/* Fill in the fields of the device structure with generic
* values.
*/
arcnet_setup(dev);
/* And now fill particular fields with arcnet values */
dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
dev->hard_header_len=sizeof(struct ClientData);
lp->sequence=1;
lp->recbuf=0;
BUGMSG(D_DURING,"ClientData header size is %d.\n",
sizeof(struct ClientData));
BUGMSG(D_DURING,"HardHeader size is %d.\n",
sizeof(struct archdr));
lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag;
SETCONF;
/* get and check the station ID from offset 1 in shmem */
lp->stationid = get_buffer_byte(dev,1);
if (!lp->stationid)
BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved "
"for broadcasts!\n");
else if (lp->stationid==255)
BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse "
"DOS networking programs!\n");
dev->dev_addr[0]=lp->stationid;
BUGMSG(D_NORMAL,"ARCnet COM90xx in IO-mapped mode: "
"station %02Xh found at %03lXh, IRQ %d.\n",
lp->stationid,
dev->base_addr,dev->irq);
return 0;
}
/****************************************************************************
* *
* Utility routines *
* *
****************************************************************************/
/* 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 arc90io_reset(struct net_device *dev,int reset_delay)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
short ioaddr=dev->base_addr;
int delayval,recbuf=lp->recbuf;
if (reset_delay==3)
{
ARCRESET;
return 0;
}
/* no IRQ's, please! */
lp->intmask=0;
SETMASK;
BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
dev->name,ARCSTATUS);
/* Set the thing to IO-mapped, 8-bit mode */
lp->config = (0x1C|IOMAPflag) & ~ENABLE16flag;
SETCONF;
if (reset_delay)
{
/* reset the card */
ARCRESET;
JIFFER(RESETtime);
}
ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd|CONFIGclear);
/* verify that the ARCnet signature byte is present */
if (get_buffer_byte(dev,0) != TESTvalue)
{
BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n");
return 1;
}
/* clear out status variables */
recbuf=lp->recbuf=0;
lp->txbuf=2;
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd|EXTconf);
/* and enable receive of our first packet to the first buffer */
EnableReceiver();
/* re-enable interrupts */
lp->intmask|=NORXflag;
#ifdef DETECT_RECONFIGS
lp->intmask|=RECONflag;
#endif
SETMASK;
/* done! return success. */
return 0;
}
static void arc90io_openclose(int open)
{
if (open)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
static void arc90io_setmask(struct net_device *dev, u_char mask)
{
short ioaddr=dev->base_addr;
AINTMASK(mask);
}
static u_char arc90io_status(struct net_device *dev)
{
short ioaddr=dev->base_addr;
return ARCSTATUS;
}
static void arc90io_command(struct net_device *dev, u_char cmd)
{
short ioaddr=dev->base_addr;
ACOMMAND(cmd);
}
/* The actual interrupt handler routine - handle various IRQ's generated
* by the card.
*/
static void
arc90io_inthandler(struct net_device *dev)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr, status, boguscount = 3, didsomething;
AINTMASK(0);
BUGMSG(D_DURING,"in arc90io_inthandler (status=%Xh, intmask=%Xh)\n",
ARCSTATUS,lp->intmask);
do
{
status = ARCSTATUS;
didsomething=0;
/* RESET flag was enabled - card is resetting and if RX
* is disabled, it's NOT because we just got a packet.
*/
if (status & RESETflag)
{
BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
status);
arc90io_reset(dev,0);
/* all other flag values are just garbage */
break;
}
/* RX is inhibited - we must have received something. */
if (status & lp->intmask & NORXflag)
{
int recbuf=lp->recbuf=!lp->recbuf;
int oldaddr=0;
BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
status);
/* enable receive of our next packet */
EnableReceiver();
if (lp->intx)
oldaddr=(inb(_ADDR_HI)<<8) | inb(_ADDR_LO);
/* Got a packet. */
arc90io_rx(dev,!recbuf);
if (lp->intx)
{
outb( (oldaddr >> 8), _ADDR_HI);
outb( oldaddr & 0xff, _ADDR_LO);
}
didsomething++;
}
/* it can only be an xmit-done irq if we're xmitting :) */
/*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
if (status & lp->intmask & TXFREEflag)
{
struct Outgoing *out=&(lp->outgoing);
int was_sending=lp->sending;
lp->intmask &= ~TXFREEflag;
lp->in_txhandler++;
if (was_sending) lp->sending--;
BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
status,out->numsegs,out->segnum,out->skb);
if (was_sending && !(status&TXACKflag))
{
if (lp->lasttrans_dest != 0)
{
BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n",
status,lp->lasttrans_dest);
lp->stats.tx_errors++;
lp->stats.tx_carrier_errors++;
}
else
{
BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n",
status,
lp->lasttrans_dest);
}
}
/* send packet if there is one */
arcnet_go_tx(dev,0);
didsomething++;
if (lp->intx)
{
BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
ARCSTATUS,lp->intx);
lp->in_txhandler--;
continue;
}
if (!lp->outgoing.skb)
{
BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
lp->in_txhandler--;
continue;
}
/* if more than one segment, and not all segments
* are done, then continue xmit.
*/
if (out->segnum<out->numsegs)
arcnetA_continue_tx(dev);
arcnet_go_tx(dev,0);
/* if segnum==numsegs, the transmission is finished;
* free the skb.
*/
if (out->segnum>=out->numsegs)
{
/* transmit completed */
out->segnum++;
if (out->skb)
{
lp->stats.tx_bytes += out->skb->len;
dev_kfree_skb(out->skb);
}
out->skb=NULL;
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
}
didsomething++;
lp->in_txhandler--;
}
else if (lp->txready && !lp->sending && !lp->intx)
{
BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n",
status);
arcnet_go_tx(dev,0);
didsomething++;
}
#ifdef DETECT_RECONFIGS
if (status & (lp->intmask) & RECONflag)
{
ACOMMAND(CFLAGScmd|CONFIGclear);
lp->stats.tx_carrier_errors++;
#ifdef SHOW_RECONFIGS
BUGMSG(D_NORMAL,"Network reconfiguration detected"
" (status=%Xh, config=%X)\n",
status,lp->config);
#endif /* SHOW_RECONFIGS */
#ifdef RECON_THRESHOLD
/* is the RECON info empty or old? */
if (!lp->first_recon || !lp->last_recon ||
jiffies-lp->last_recon > HZ*10)
{
if (lp->network_down)
BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
lp->first_recon=lp->last_recon=jiffies;
lp->num_recons=lp->network_down=0;
BUGMSG(D_DURING,"recon: clearing counters.\n");
}
else /* add to current RECON counter */
{
lp->last_recon=jiffies;
lp->num_recons++;
BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
lp->num_recons,
(lp->last_recon-lp->first_recon)/HZ,
lp->network_down);
/* if network is marked up;
* and first_recon and last_recon are 60+ sec
* apart;
* and the average no. of recons counted is
* > RECON_THRESHOLD/min;
* then print a warning message.
*/
if (!lp->network_down
&& (lp->last_recon-lp->first_recon)<=HZ*60
&& lp->num_recons >= RECON_THRESHOLD)
{
lp->network_down=1;
BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
}
else if (!lp->network_down
&& lp->last_recon-lp->first_recon > HZ*60)
{
/* reset counters if we've gone for
* over a minute.
*/
lp->first_recon=lp->last_recon;
lp->num_recons=1;
}
}
}
else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
{
if (lp->network_down)
BUGMSG(D_NORMAL,"cabling restored?\n");
lp->first_recon=lp->last_recon=0;
lp->num_recons=lp->network_down=0;
BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
#endif
}
#endif /* DETECT_RECONFIGS */
} while (--boguscount && didsomething);
BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
ARCSTATUS,boguscount);
BUGMSG(D_DURING,"\n");
SETMASK; /* put back interrupt mask */
}
/* A packet has arrived; grab it from the buffers and pass it to the generic
* arcnet_rx routing to deal with it.
*/
static void
arc90io_rx(struct net_device *dev,int recbuf)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr;
union ArcPacket packetbuf;
union ArcPacket *arcpacket=&packetbuf;
u_char *arcsoft;
short length,offset;
u_char daddr,saddr;
lp->stats.rx_packets++;
get_whole_buffer(dev,recbuf*512,4,(char *)arcpacket);
saddr=arcpacket->hardheader.source;
/* if source is 0, it's a "used" packet! */
if (saddr==0)
{
BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n",
ARCSTATUS);
lp->stats.rx_errors++;
return;
}
/* Set source address to zero to mark it as old */
put_buffer_byte(dev,recbuf*512,0);
arcpacket->hardheader.source=0;
daddr=arcpacket->hardheader.destination;
if (arcpacket->hardheader.offset1) /* Normal Packet */
{
offset=arcpacket->hardheader.offset1;
arcsoft=&arcpacket->raw[offset];
length=256-offset;
}
else /* ExtendedPacket or ExceptionPacket */
{
offset=arcpacket->hardheader.offset2;
arcsoft=&arcpacket->raw[offset];
length=512-offset;
}
get_whole_buffer(dev,recbuf*512+offset,length,(char *)arcpacket+offset);
arcnet_rx(lp, arcsoft, length, saddr, daddr);
BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx");
}
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnet_go_tx.
*/
static void
arc90io_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen,
char *data,int length,int daddr,int exceptA, int offset)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
length+=hdrlen;
BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr,length,data);
put_buffer_byte(dev, lp->txbuf*512+1, daddr);
/* load packet into shared memory */
if (length<=MTU) /* Normal (256-byte) Packet */
put_buffer_byte(dev, lp->txbuf*512+2, offset=offset?offset:256-length);
else if (length>=MinTU || offset) /* Extended (512-byte) Packet */
{
put_buffer_byte(dev, lp->txbuf*512+2, 0);
put_buffer_byte(dev, lp->txbuf*512+3, offset=offset?offset:512-length);
}
else if (exceptA) /* RFC1201 Exception Packet */
{
put_buffer_byte(dev, lp->txbuf*512+2, 0);
put_buffer_byte(dev, lp->txbuf*512+3, offset=512-length-4);
/* exception-specific stuff - these four bytes
* make the packet long enough to fit in a 512-byte
* frame.
*/
put_buffer_byte(dev, lp->txbuf*512+offset,hdr[0]);
put_whole_buffer(dev, lp->txbuf*512+offset+1,3,"\377\377\377");
offset+=4;
}
else /* "other" Exception packet */
{
/* RFC1051 - set 4 trailing bytes to 0 */
put_whole_buffer(dev,lp->txbuf*512+508,4,"\0\0\0\0");
/* now round up to MinTU */
put_buffer_byte(dev, lp->txbuf*512+2, 0);
put_buffer_byte(dev, lp->txbuf*512+3, offset=512-MinTU);
}
/* copy the packet into ARCnet shmem
* - the first bytes of ClientData header are skipped
*/
put_whole_buffer(dev, 512*lp->txbuf+offset, hdrlen,(u_char *)hdr);
put_whole_buffer(dev, 512*lp->txbuf+offset+hdrlen,length-hdrlen,data);
BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
daddr,length);
lp->lastload_dest=daddr;
lp->txready=lp->txbuf; /* packet is ready for sending */
}
/****************************************************************************
* *
* Kernel Loadable Module Support *
* *
****************************************************************************/
#ifdef MODULE
static struct net_device *cards[16]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
int init_module(void)
{
struct net_device *dev=cards[0];
cards[0]=dev=(struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL);
if (!dev)
return -ENOMEM;
memset(dev, 0, sizeof(struct net_device));
dev->name=(char *)kmalloc(9, GFP_KERNEL);
if (!dev->name)
{
kfree(dev);
return -ENOMEM;
}
dev->init=arc90io_probe;
if (device)
strcpy(dev->name,device);
else arcnet_makename(dev->name);
dev->base_addr=io;
dev->irq=irq;
if (dev->irq==2) dev->irq=9;
if (register_netdev(dev) != 0)
return -EIO;
/* Increase use count of arcnet.o */
arcnet_use_count(1);
return 0;
}
void cleanup_module(void)
{
struct net_device *dev=cards[0];
int ioaddr=dev->base_addr;
if (dev->start) (*dev->stop)(dev);
/* Flush TX and disable RX */
if (ioaddr)
{
AINTMASK(0); /* disable IRQ's */
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
/* Set the thing back to MMAP mode, in case the old
driver is loaded later */
outb( (inb(_CONFIG)&~IOMAPflag),_CONFIG);
}
if (dev->irq)
{
free_irq(dev->irq,dev);
}
if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
/* Decrease use count of arcnet.o */
arcnet_use_count(0);
}
#else
void __init com90io_setup (char *str, int *ints)
{
struct net_device *dev;
if (arcnet_num_devs == MAX_ARCNET_DEVS)
{
printk("com90xx IO-MAP: Too many ARCnet devices registered (max %d).\n",
MAX_ARCNET_DEVS);
return;
}
dev=&arcnet_devs[arcnet_num_devs];
if (ints[0] < 1)
{
printk("com90xx IO-MAP: You must give an IO address.\n");
return;
}
dev->init=arc90io_probe;
switch(ints[0])
{
case 3: /* ERROR */
printk("com90xx IO-MAP: Too many arguments.\n");
case 2: /* IRQ */
dev->irq=ints[2];
case 1: /* IO address */
dev->base_addr=ints[1];
}
dev->name = (char *)&arcnet_dev_names[arcnet_num_devs];
if (str)
strncpy(dev->name, str, 9);
arcnet_num_devs++;
}
#endif /* MODULE */
/* $Id: com90xx.c,v 1.9 1998/03/21 18:02:51 alan Exp $
Derived from the original arcnet.c,
Written 1994-1996 by Avery Pennarun,
which was in turn derived from skeleton.c by Donald Becker.
**********************
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 Public License as
modified by SRC, incorporated herein by reference.
**********************
For more details, see drivers/net/arcnet.c
**********************
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/if_arcnet.h>
#include <linux/arcdevice.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <net/arp.h>
/**************************************************************************/
/* On a fast computer, the buffer copy from memory to the ARCnet card during
* a transmit can hog the bus just a little too long. SLOW_XMIT_COPY
* replaces the fast memcpy() with a slower for() loop that seems to solve
* my problems with ftape.
*
* Probably a better solution would be to use memcpy_toio (more portable
* anyway) and modify that routine to support REALLY_SLOW_IO-style
* defines; ARCnet probably is not the only driver that can screw up an
* ftape DMA transfer.
*
* Turn this on if you have timing-sensitive DMA (ie. a tape drive) and
* would like to sacrifice a little bit of network speed to reduce tape
* write retries or some related problem.
*/
#undef SLOW_XMIT_COPY
/* 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 */
#ifdef MODULE
static
#endif
int arc90xx_probe(struct net_device *dev);
static void arc90xx_rx(struct net_device *dev, int recbuf);
static int arc90xx_found(struct net_device *dev, int ioaddr, int airq, void * shmem, int more);
static void arc90xx_inthandler(struct net_device *dev);
static int arc90xx_reset(struct net_device *dev, int reset_delay);
static void arc90xx_setmask(struct net_device *dev, u_char mask);
static void arc90xx_command(struct net_device *dev, u_char command);
static u_char arc90xx_status(struct net_device *dev);
static void arc90xx_prepare_tx(struct net_device *dev, u_char * hdr, int hdrlen,
char *data, int length, int daddr, int exceptA, int offset);
static void arc90xx_openclose(int open);
/* Module parameters */
#ifdef MODULE
static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
static int irq = 0; /* or use the insmod io= irq= shmem= options */
static int shmem = 0;
static char *device; /* use eg. device="arc1" to change name */
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(shmem, "i");
MODULE_PARM(device, "s");
#else
void __init com90xx_setup(char *str, int *ints);
char __initdata com90xx_explicit = 0;
extern struct net_device arcnet_devs[];
extern char arcnet_dev_names[][10];
extern int arcnet_num_devs;
#endif
/* 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 */
#define RDDATAflag 0x00 /* Next access is a read/~write */
#define ARCSTATUS inb(_STATUS)
#define ACOMMAND(cmd) outb((cmd),_COMMAND)
#define AINTMASK(msk) outb((msk),_INTMASK)
#define SETCONF outb(lp->config,_CONFIG)
#define ARCRESET inb(_RESET)
static const char *version =
"com90xx.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
/****************************************************************************
* *
* Probe and initialization *
* *
****************************************************************************/
/* Check for an ARCnet network adaptor, and return '0' if one exists.
* If dev->base_addr == 0, probe all likely locations.
* If dev->base_addr == 1, always return failure.
* If dev->base_addr == 2, allocate space for the device and return success
* (detachable devices only).
*
* NOTE: the list of possible ports/shmems is static, so it is retained
* across calls to arcnet_probe. So, if more than one ARCnet probe is made,
* values that were discarded once will not even be tried again.
*
* FIXME: grab all devices in one shot and eliminate the big static array.
*/
static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata = {
0
};
static void * shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata = {
0
};
int __init arc90xx_probe(struct net_device *dev)
{
static int init_once = 0;
static int numports = sizeof(ports) / sizeof(ports[0]), numshmems = sizeof(shmems) / sizeof(shmems[0]);
int count, status, delayval, ioaddr, numprint, airq, retval = -ENODEV,
openparen = 0;
unsigned long airqmask;
int *port;
void **shmem;
if (!init_once) {
for (count = 0x200; count <= 0x3f0; count += 16)
ports[(count - 0x200) / 16] = count;
for (count = 0xA0000; count <= 0xFF800; count += 2048)
shmems[(count - 0xA0000) / 2048] = ioremap(count, 2048);
BUGLVL(D_NORMAL) printk(version);
BUGMSG(D_DURING, "space used for probe buffers: %d+%d=%d bytes\n",
sizeof(ports), sizeof(shmems),
sizeof(ports) + sizeof(shmems));
}
init_once++;
BUGMSG(D_INIT, "given: base %lXh, IRQ %d, shmem %lXh\n",
dev->base_addr, dev->irq, dev->mem_start);
if (dev->base_addr > 0x1ff) { /* Check a single specified port */
ports[0] = dev->base_addr;
numports = 1;
} else if (dev->base_addr > 0) /* Don't probe at all. */
return -ENXIO;
if (dev->mem_start) {
shmems[0] = ioremap(dev->mem_start, 2048);
numshmems = 1;
}
/* Stage 1: abandon any reserved ports, or ones with status==0xFF
* (empty), and reset any others by reading the reset port.
*/
BUGMSG(D_INIT, "Stage 1: ");
numprint = 0;
for (port = &ports[0]; port - ports < numports; port++) {
numprint++;
if (numprint > 8) {
BUGMSG2(D_INIT, "\n");
BUGMSG(D_INIT, "Stage 1: ");
numprint = 1;
}
BUGMSG2(D_INIT, "%Xh ", *port);
ioaddr = *port;
if (check_region(*port, ARCNET_TOTAL_SIZE)) {
BUGMSG2(D_INIT_REASONS, "(check_region)\n");
BUGMSG(D_INIT_REASONS, "Stage 1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
port--;
continue;
}
if (ARCSTATUS == 0xFF) {
BUGMSG2(D_INIT_REASONS, "(empty)\n");
BUGMSG(D_INIT_REASONS, "Stage 1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
port--;
continue;
}
ARCRESET; /* begin resetting card */
BUGMSG2(D_INIT_REASONS, "\n");
BUGMSG(D_INIT_REASONS, "Stage 1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
}
BUGMSG2(D_INIT, "\n");
if (!numports) {
BUGMSG(D_NORMAL, "Stage 1: No ARCnet cards found.\n");
return -ENODEV;
}
/* Stage 2: we have now reset any possible ARCnet cards, so we can't
* do anything until they finish. If D_INIT, print the list of
* cards that are left.
*/
BUGMSG(D_INIT, "Stage 2: ");
numprint = 0;
for (port = &ports[0]; port - ports < numports; port++) {
numprint++;
if (numprint > 8) {
BUGMSG2(D_INIT, "\n");
BUGMSG(D_INIT, "Stage 2: ");
numprint = 1;
}
BUGMSG2(D_INIT, "%Xh ", *port);
}
BUGMSG2(D_INIT, "\n");
JIFFER(RESETtime);
/* Stage 3: abandon any shmem addresses that don't have the signature
* 0xD1 byte in the right place, or are read-only.
*/
BUGMSG(D_INIT, "Stage 3: ");
numprint = 0;
for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) {
void * ptr;
numprint++;
if (numprint > 8) {
BUGMSG2(D_INIT, "\n");
BUGMSG(D_INIT, "Stage 3: ");
numprint = 1;
}
BUGMSG2(D_INIT, "%ph ", *shmem);
ptr = *shmem;
if (readb(ptr) != TESTvalue) {
BUGMSG2(D_INIT_REASONS, "(mem=%02Xh, not %02Xh)\n",
readb(ptr), TESTvalue);
BUGMSG(D_INIT_REASONS, "Stage 3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*shmem = shmems[numshmems - 1];
numshmems--;
shmem--;
continue;
}
/* By writing 0x42 to the TESTvalue location, we also make
* sure no "mirror" shmem areas show up - if they occur
* in another pass through this loop, they will be discarded
* because *cptr != TESTvalue.
*/
writeb(0x42, ptr);
if (readb(ptr) != 0x42) {
BUGMSG2(D_INIT_REASONS, "(read only)\n");
BUGMSG(D_INIT_REASONS, "Stage 3: ");
*shmem = shmems[numshmems - 1];
numshmems--;
shmem--;
continue;
}
BUGMSG2(D_INIT_REASONS, "\n");
BUGMSG(D_INIT_REASONS, "Stage 3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
}
BUGMSG2(D_INIT, "\n");
if (!numshmems) {
BUGMSG(D_NORMAL, "Stage 3: No ARCnet cards found.\n");
return -ENODEV;
}
/* Stage 4: something of a dummy, to report the shmems that are
* still possible after stage 3.
*/
BUGMSG(D_INIT, "Stage 4: ");
numprint = 0;
for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) {
numprint++;
if (numprint > 8) {
BUGMSG2(D_INIT, "\n");
BUGMSG(D_INIT, "Stage 4: ");
numprint = 1;
}
BUGMSG2(D_INIT, "%ph ", *shmem);
}
BUGMSG2(D_INIT, "\n");
/* Stage 5: for any ports that have the correct status, can disable
* the RESET flag, and (if no irq is given) generate an autoirq,
* register an ARCnet device.
*
* Currently, we can only register one device per probe, so quit
* after the first one is found.
*/
BUGMSG(D_INIT, "Stage 5: ");
numprint = 0;
for (port = &ports[0]; port - ports < numports; port++) {
numprint++;
if (numprint > 8) {
BUGMSG2(D_INIT, "\n");
BUGMSG(D_INIT, "Stage 5: ");
numprint = 1;
}
BUGMSG2(D_INIT, "%Xh ", *port);
ioaddr = *port;
status = ARCSTATUS;
if ((status & 0x9D)
!= (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status);
BUGMSG(D_INIT_REASONS, "Stage 5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
port--;
continue;
}
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
status = ARCSTATUS;
if (status & RESETflag) {
BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n",
status);
BUGMSG(D_INIT_REASONS, "Stage 5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
port--;
continue;
}
/* skip this completely if an IRQ was given, because maybe
* we're on a machine that locks during autoirq!
*/
if (!dev->irq) {
/* if we do this, we're sure to get an IRQ since the
* card has just reset and the NORXflag is on until
* we tell it to start receiving.
*/
airqmask = probe_irq_on();
AINTMASK(NORXflag);
mdelay(1);
AINTMASK(0);
airq = probe_irq_off(airqmask);
if (airq <= 0) {
BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq);
BUGMSG(D_INIT_REASONS, "Stage 5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
port--;
continue;
}
} else {
airq = dev->irq;
}
BUGMSG2(D_INIT, "(%d,", airq);
openparen = 1;
/* Everything seems okay. But which shmem, if any, puts
* back its signature byte when the card is reset?
*
* If there are multiple cards installed, there might be
* multiple shmems still in the list.
*/
#ifdef FAST_PROBE
if (numports > 1 || numshmems > 1) {
ARCRESET;
JIFFER(RESETtime);
} else {
/* just one shmem and port, assume they match */
writeb(TESTvalue, shmems[0]);
}
#else
ARCRESET;
JIFFER(RESETtime);
#endif
for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) {
void * ptr;
ptr = *shmem;
if (readb(ptr) == TESTvalue) { /* found one */
int probe_more;
BUGMSG2(D_INIT, "%ph)\n", *shmem);
openparen = 0;
/* register the card */
if (init_once == 1 && numshmems > 1)
probe_more = numshmems - 1;
else
probe_more = 0;
retval = arc90xx_found(dev, *port, airq, *shmem, probe_more);
if (retval)
openparen = 0;
/* remove shmem from the list */
*shmem = shmems[numshmems - 1];
numshmems--;
break;
} else {
BUGMSG2(D_INIT_REASONS, "%Xh-", readb(ptr));
}
}
if (openparen) {
BUGMSG2(D_INIT, "no matching shmem)\n");
BUGMSG(D_INIT_REASONS, "Stage 5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
}
*port = ports[numports - 1];
numports--;
port--;
if (!retval)
break;
}
BUGMSG(D_INIT_REASONS, "\n");
/* Now put back TESTvalue on all leftover shmems.
*/
for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++)
writeb(TESTvalue, *shmem);
if (retval)
BUGMSG(D_NORMAL, "Stage 5: No ARCnet cards found.\n");
return retval;
}
/* Set up the struct net_device associated with this card. Called after
* probing succeeds.
*/
static int __init arc90xx_found(struct net_device *dev, int ioaddr, int airq, void * shmem, int more)
{
struct arcnet_local *lp;
void *first_mirror, *last_mirror;
int mirror_size;
/* reserve the irq */
if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) {
BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq);
return -ENODEV;
}
dev->irq = airq;
/* reserve the I/O region - guaranteed to work by check_region */
request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (90xx)");
dev->base_addr = ioaddr;
/* find the real shared memory start/end points, including mirrors */
#define BUFFER_SIZE (512)
#define MIRROR_SIZE (BUFFER_SIZE*4)
/* guess the actual size of one "memory mirror" - the number of
* bytes between copies of the shared memory. On most cards, it's
* 2k (or there are no mirrors at all) but on some, it's 4k.
*/
mirror_size = MIRROR_SIZE;
if (readb(shmem) == TESTvalue
&& readb(shmem - mirror_size) != TESTvalue
&& readb(shmem - 2 * mirror_size) == TESTvalue)
mirror_size *= 2;
first_mirror = last_mirror = shmem;
while (readb(first_mirror) == TESTvalue)
first_mirror -= mirror_size;
first_mirror += mirror_size;
while (readb(last_mirror) == TESTvalue)
last_mirror += mirror_size;
last_mirror -= mirror_size;
dev->mem_start = (unsigned long) first_mirror;
dev->mem_end = (unsigned long) last_mirror + MIRROR_SIZE - 1;
dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0;
dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1;
/* Initialize the rest of the device structure. */
dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (dev->priv == NULL) {
free_irq(airq, dev);
release_region(ioaddr, ARCNET_TOTAL_SIZE);
return -ENOMEM;
}
memset(dev->priv, 0, sizeof(struct arcnet_local));
lp = (struct arcnet_local *) (dev->priv);
lp->card_type = ARC_90xx;
lp->card_type_str = "COM 90xx";
lp->arcnet_reset = arc90xx_reset;
lp->asetmask = arc90xx_setmask;
lp->astatus = arc90xx_status;
lp->acommand = arc90xx_command;
lp->openclose_device = arc90xx_openclose;
lp->prepare_tx = arc90xx_prepare_tx;
lp->inthandler = arc90xx_inthandler;
/* Fill in the fields of the device structure with generic
* values.
*/
arcnet_setup(dev);
/* And now fill particular fields with arcnet values */
dev->mtu = 1500; /* completely arbitrary - agrees with ether, though */
dev->hard_header_len = sizeof(struct ClientData);
lp->sequence = 1;
lp->recbuf = 0;
BUGMSG(D_DURING, "ClientData header size is %d.\n",
sizeof(struct ClientData));
BUGMSG(D_DURING, "HardHeader size is %d.\n",
sizeof(struct archdr));
/* get and check the station ID from offset 1 in shmem */
lp->stationid = readb(first_mirror + 1);
if (lp->stationid == 0)
BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved "
"for broadcasts!\n");
else if (lp->stationid == 255)
BUGMSG(D_NORMAL, "WARNING! Station address FF may confuse "
"DOS networking programs!\n");
dev->dev_addr[0] = lp->stationid;
BUGMSG(D_NORMAL, "ARCnet COM90xx: station %02Xh found at %03lXh, IRQ %d, "
"ShMem %lXh (%ld*%xh).\n",
lp->stationid,
dev->base_addr, dev->irq, dev->mem_start,
(dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size);
/* OK. We're finished. If there are probably other cards, add other
* COM90xx drivers to the device chain, so they get probed later.
*/
#ifndef MODULE
while (!com90xx_explicit && more--) {
if (arcnet_num_devs < MAX_ARCNET_DEVS) {
arcnet_devs[arcnet_num_devs].next = dev->next;
dev->next = &arcnet_devs[arcnet_num_devs];
dev = dev->next;
dev->name = (char *) &arcnet_dev_names[arcnet_num_devs];
arcnet_num_devs++;
} else {
BUGMSG(D_NORMAL, "Too many arcnet devices - no more will be probed for.\n");
return 0;
}
arcnet_makename(dev->name);
dev->init = arc90xx_probe;
}
#endif
return 0;
}
/* Do a hardware reset on the card, and set up necessary registers.
* This should be called as little as possible, because it disrupts the
* token on the network (causes a RECON) and requires a significant delay.
*
* However, it does make sure the card is in a defined state.
*/
int arc90xx_reset(struct net_device *dev, int reset_delay)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
short ioaddr = dev->base_addr;
int delayval, recbuf = lp->recbuf;
if (reset_delay == 3) {
ARCRESET;
return 0;
}
/* no IRQ's, please! */
lp->intmask = 0;
SETMASK;
BUGMSG(D_INIT, "Resetting %s (status=%Xh)\n",
dev->name, ARCSTATUS);
if (reset_delay) {
/* reset the card */
ARCRESET;
JIFFER(RESETtime);
}
ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd | CONFIGclear);
/* verify that the ARCnet signature byte is present */
if (readb(dev->mem_start) != TESTvalue) {
BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
return 1;
}
/* clear out status variables */
recbuf = lp->recbuf = 0;
lp->txbuf = 2;
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd | EXTconf);
#ifndef SLOW_XMIT_COPY
/* clean out all the memory to make debugging make more sense :) */
BUGLVL(D_DURING)
memset_io(dev->mem_start, 0x42, 2048);
#endif
/* and enable receive of our first packet to the first buffer */
EnableReceiver();
/* re-enable interrupts */
lp->intmask |= NORXflag;
#ifdef DETECT_RECONFIGS
lp->intmask |= RECONflag;
#endif
SETMASK;
/* done! return success. */
return 0;
}
static void arc90xx_openclose(int open)
{
if (open)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
static void arc90xx_setmask(struct net_device *dev, u_char mask)
{
short ioaddr = dev->base_addr;
AINTMASK(mask);
}
static u_char arc90xx_status(struct net_device *dev)
{
short ioaddr = dev->base_addr;
return ARCSTATUS;
}
static void arc90xx_command(struct net_device *dev, u_char cmd)
{
short ioaddr = dev->base_addr;
ACOMMAND(cmd);
}
/* The actual interrupt handler routine - handle various IRQ's generated
* by the card.
*/
static void arc90xx_inthandler(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
int ioaddr = dev->base_addr, status, boguscount = 3, didsomething;
AINTMASK(0);
BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
ARCSTATUS, lp->intmask);
do {
status = ARCSTATUS;
didsomething = 0;
/* RESET flag was enabled - card is resetting and if RX
* is disabled, it's NOT because we just got a packet.
*/
if (status & RESETflag) {
BUGMSG(D_NORMAL, "spurious reset (status=%Xh)\n",
status);
arc90xx_reset(dev, 0);
/* all other flag values are just garbage */
break;
}
/* RX is inhibited - we must have received something. */
if (status & lp->intmask & NORXflag) {
int recbuf = lp->recbuf = !lp->recbuf;
BUGMSG(D_DURING, "receive irq (status=%Xh)\n",
status);
/* enable receive of our next packet */
EnableReceiver();
/* Got a packet. */
arc90xx_rx(dev, !recbuf);
didsomething++;
}
/* it can only be an xmit-done irq if we're xmitting :) */
/*if (status&TXFREEflag && !lp->in_txhandler && lp->sending) */
if (status & lp->intmask & TXFREEflag) {
struct Outgoing *out = &(lp->outgoing);
int was_sending = lp->sending;
lp->intmask &= ~TXFREEflag;
lp->in_txhandler++;
if (was_sending)
lp->sending--;
BUGMSG(D_DURING, "TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
status, out->numsegs, out->segnum, out->skb);
if (was_sending && !(status & TXACKflag)) {
if (lp->lasttrans_dest != 0) {
BUGMSG(D_EXTRA, "transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n",
status, lp->lasttrans_dest);
lp->stats.tx_errors++;
lp->stats.tx_carrier_errors++;
} else {
BUGMSG(D_DURING, "broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n",
status,
lp->lasttrans_dest);
}
}
/* send packet if there is one */
arcnet_go_tx(dev, 0);
didsomething++;
if (lp->intx) {
BUGMSG(D_DURING, "TXDONE while intx! (status=%Xh, intx=%d)\n",
ARCSTATUS, lp->intx);
lp->in_txhandler--;
continue;
}
if (!lp->outgoing.skb) {
BUGMSG(D_DURING, "TX IRQ done: no split to continue.\n");
/* inform upper layers */
if (!lp->txready)
arcnet_tx_done(dev, lp);
lp->in_txhandler--;
continue;
}
/* if more than one segment, and not all segments
* are done, then continue xmit.
*/
if (out->segnum < out->numsegs)
arcnetA_continue_tx(dev);
arcnet_go_tx(dev, 0);
/* if segnum==numsegs, the transmission is finished;
* free the skb.
*/
if (out->segnum >= out->numsegs) {
/* transmit completed */
out->segnum++;
if (out->skb) {
lp->stats.tx_bytes += out->skb->len;
dev_kfree_skb(out->skb);
}
out->skb = NULL;
/* inform upper layers */
if (!lp->txready)
arcnet_tx_done(dev, lp);
}
didsomething++;
lp->in_txhandler--;
} else if (lp->txready && !lp->sending && !lp->intx) {
BUGMSG(D_NORMAL, "recovery from silent TX (status=%Xh)\n",
status);
arcnet_go_tx(dev, 0);
didsomething++;
}
#ifdef DETECT_RECONFIGS
if (status & (lp->intmask) & RECONflag) {
ACOMMAND(CFLAGScmd | CONFIGclear);
lp->stats.tx_carrier_errors++;
#ifdef SHOW_RECONFIGS
BUGMSG(D_NORMAL, "Network reconfiguration detected (status=%Xh)\n",
status);
#endif /* SHOW_RECONFIGS */
#ifdef RECON_THRESHOLD
/* is the RECON info empty or old? */
if (!lp->first_recon || !lp->last_recon ||
jiffies - lp->last_recon > HZ * 10) {
if (lp->network_down)
BUGMSG(D_NORMAL, "reconfiguration detected: cabling restored?\n");
lp->first_recon = lp->last_recon = jiffies;
lp->num_recons = lp->network_down = 0;
BUGMSG(D_DURING, "recon: clearing counters.\n");
} else { /* add to current RECON counter */
lp->last_recon = jiffies;
lp->num_recons++;
BUGMSG(D_DURING, "recon: counter=%d, time=%lds, net=%d\n",
lp->num_recons,
(lp->last_recon - lp->first_recon) / HZ,
lp->network_down);
/* if network is marked up;
* and first_recon and last_recon are 60+ sec
* apart;
* and the average no. of recons counted is
* > RECON_THRESHOLD/min;
* then print a warning message.
*/
if (!lp->network_down
&& (lp->last_recon - lp->first_recon) <= HZ * 60
&& lp->num_recons >= RECON_THRESHOLD) {
lp->network_down = 1;
BUGMSG(D_NORMAL, "many reconfigurations detected: cabling problem?\n");
} else if (!lp->network_down
&& lp->last_recon - lp->first_recon > HZ * 60) {
/* reset counters if we've gone for
* over a minute.
*/
lp->first_recon = lp->last_recon;
lp->num_recons = 1;
}
}
} else if (lp->network_down && jiffies - lp->last_recon > HZ * 10) {
if (lp->network_down)
BUGMSG(D_NORMAL, "cabling restored?\n");
lp->first_recon = lp->last_recon = 0;
lp->num_recons = lp->network_down = 0;
BUGMSG(D_DURING, "not recon: clearing counters anyway.\n");
#endif
}
#endif /* DETECT_RECONFIGS */
} while (--boguscount && didsomething);
BUGMSG(D_DURING, "net_interrupt complete (status=%Xh, count=%d)\n",
ARCSTATUS, boguscount);
BUGMSG(D_DURING, "\n");
SETMASK; /* put back interrupt mask */
}
/* A packet has arrived; grab it from the buffers and pass it to the generic
* arcnet_rx routing to deal with it.
*/
static void arc90xx_rx(struct net_device *dev, int recbuf)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
int ioaddr = dev->base_addr;
union ArcPacket *arcpacket =
(union ArcPacket *) phys_to_virt(dev->mem_start + recbuf * 512);
u_char *arcsoft;
short length, offset;
u_char daddr, saddr;
lp->stats.rx_packets++;
saddr = arcpacket->hardheader.source;
/* if source is 0, it's a "used" packet! */
if (saddr == 0) {
BUGMSG(D_NORMAL, "discarding old packet. (status=%Xh)\n",
ARCSTATUS);
lp->stats.rx_errors++;
return;
}
/* Set source address to zero to mark it as old */
arcpacket->hardheader.source = 0;
daddr = arcpacket->hardheader.destination;
if (arcpacket->hardheader.offset1) { /* Normal Packet */
offset = arcpacket->hardheader.offset1;
arcsoft = &arcpacket->raw[offset];
length = 256 - offset;
} else { /* ExtendedPacket or ExceptionPacket */
offset = arcpacket->hardheader.offset2;
arcsoft = &arcpacket->raw[offset];
length = 512 - offset;
}
arcnet_rx(lp, arcsoft, length, saddr, daddr);
BUGLVL(D_RX) arcnet_dump_packet(lp->adev, arcpacket->raw, length > 240, "rx");
#ifndef SLOW_XMIT_COPY
/* clean out the page to make debugging make more sense :) */
BUGLVL(D_DURING)
memset((void *) arcpacket->raw, 0x42, 512);
#endif
}
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnet_go_tx.
*/
static void arc90xx_prepare_tx(struct net_device *dev, u_char * hdr, int hdrlen,
char *data, int length, int daddr, int exceptA, int offset)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
union ArcPacket *arcpacket =
(union ArcPacket *) phys_to_virt(dev->mem_start + 512 * (lp->txbuf ^ 1));
#ifdef SLOW_XMIT_COPY
char *iptr, *iend, *optr;
#endif
lp->txbuf = lp->txbuf ^ 1; /* XOR with 1 to alternate between 2 and 3 */
length += hdrlen;
BUGMSG(D_TX, "arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr, length, data);
#ifndef SLOW_XMIT_COPY
/* clean out the page to make debugging make more sense :) */
BUGLVL(D_DURING)
memset_io(dev->mem_start + lp->txbuf * 512, 0x42, 512);
#endif
arcpacket->hardheader.destination = daddr;
/* load packet into shared memory */
if (length <= MTU) /* Normal (256-byte) Packet */
arcpacket->hardheader.offset1 = offset = offset ? offset : 256 - length;
else if (length >= MinTU || offset) { /* Extended (512-byte) Packet */
arcpacket->hardheader.offset1 = 0;
arcpacket->hardheader.offset2 = offset = offset ? offset : 512 - length;
} else if (exceptA) { /* RFC1201 Exception Packet */
arcpacket->hardheader.offset1 = 0;
arcpacket->hardheader.offset2 = offset = 512 - length - 4;
/* exception-specific stuff - these four bytes
* make the packet long enough to fit in a 512-byte
* frame.
*/
arcpacket->raw[offset + 0] = hdr[0];
arcpacket->raw[offset + 1] = 0xFF; /* FF flag */
arcpacket->raw[offset + 2] = 0xFF; /* FF padding */
arcpacket->raw[offset + 3] = 0xFF; /* FF padding */
offset += 4;
} else { /* "other" Exception packet */
/* RFC1051 - set 4 trailing bytes to 0 */
memset(&arcpacket->raw[508], 0, 4);
/* now round up to MinTU */
arcpacket->hardheader.offset1 = 0;
arcpacket->hardheader.offset2 = offset = 512 - MinTU;
}
/* copy the packet into ARCnet shmem
* - the first bytes of ClientData header are skipped
*/
memcpy((u_char *) arcpacket + offset, (u_char *) hdr, hdrlen);
#ifdef SLOW_XMIT_COPY
for (iptr = data, iend = iptr + length - hdrlen, optr = (char *) arcpacket + offset + hdrlen;
iptr < iend; iptr++, optr++) {
*optr = *iptr;
/*udelay(5); */
}
#else
memcpy((u_char *) arcpacket + offset + hdrlen, data, length - hdrlen);
#endif
BUGMSG(D_DURING, "transmitting packet to station %02Xh (%d bytes)\n",
daddr, length);
BUGLVL(D_TX) arcnet_dump_packet(dev, arcpacket->raw, length > MTU, "tx");
lp->lastload_dest = daddr;
lp->txready = lp->txbuf; /* packet is ready for sending */
}
/****************************************************************************
* *
* Kernel Loadable Module Support *
* *
****************************************************************************/
#ifdef MODULE
static char devicename[9] = "";
static struct net_device thiscard =
{
devicename, /* device name is inserted by linux/drivers/net/net_init.c */
0, 0, 0, 0,
0, 0, /* I/O address, IRQ */
0, 0, 0, NULL, arc90xx_probe
};
int init_module(void)
{
struct net_device *dev = &thiscard;
if (device)
strcpy(dev->name, device);
else
arcnet_makename(dev->name);
dev->base_addr = io;
dev->irq = irq;
if (dev->irq == 2)
dev->irq = 9;
if (shmem) {
dev->mem_start = shmem;
dev->mem_end = thiscard.mem_start + 512 * 4 - 1;
dev->rmem_start = thiscard.mem_start + 512 * 0;
dev->rmem_end = thiscard.mem_start + 512 * 2 - 1;
}
if (register_netdev(dev) != 0)
return -EIO;
arcnet_use_count(1);
return 0;
}
void cleanup_module(void)
{
struct net_device *dev = &thiscard;
int ioaddr = dev->mem_start;
if (dev->start)
(*dev->stop) (dev);
/* Flush TX and disable RX */
if (ioaddr) {
AINTMASK(0); /* disable IRQ's */
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
#if defined(IO_MAPPED_BUFFERS) && !defined(COM20020)
/* Set the thing back to MMAP mode, in case the old
driver is loaded later */
outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG);
#endif
}
if (dev->irq) {
free_irq(dev->irq, dev);
}
if (dev->base_addr)
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
arcnet_use_count(0);
}
#else
void __init com90xx_setup(char *str, int *ints)
{
struct net_device *dev;
if (arcnet_num_devs == MAX_ARCNET_DEVS) {
printk("com90xx: Too many ARCnet devices registered (max %d).\n",
MAX_ARCNET_DEVS);
return;
}
if (!ints[0] && (!str || !*str)) {
printk("com90xx: Disabled.\n");
com90xx_explicit++;
return;
}
dev = &arcnet_devs[arcnet_num_devs];
dev->dev_addr[3] = 3;
dev->init = arc90xx_probe;
switch (ints[0]) {
case 4: /* ERROR */
printk("com20020: Too many arguments.\n");
case 3: /* Mem address */
dev->mem_start = ints[3];
case 2: /* IRQ */
dev->irq = ints[2];
case 1: /* IO address */
dev->base_addr = ints[1];
}
dev->name = (char *) &arcnet_dev_names[arcnet_num_devs];
if (str)
strncpy(dev->name, str, 9);
arcnet_num_devs++;
}
#endif /* MODULE */
......@@ -14,7 +14,8 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
dep_tristate ' New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA
dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA
dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA
dep_tristate ' Aironet 4500/4800 PCMCIA support ' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA
dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA
dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA
if [ "$CONFIG_CARDBUS" = "y" ]; then
dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m
......
......@@ -30,6 +30,7 @@ obj-$(CONFIG_PCMCIA_NMCLAN) += nmclan_cs.o
obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o
obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o
obj-$(CONFIG_PCMCIA_XIRC2PS) += xirc2ps_cs.o
obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o
# 16-bit wireless client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
......
/*
* Linux ARCnet driver - COM20020 PCMCIA support
*
* Written 1994-1999 by Avery Pennarun,
* based on an ISA version by David Woodhouse.
* Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4)
* which was derived from pcnet_cs.c by David Hinds.
* Some additional portions derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
* for sponsoring the further development of this driver.
*
* **********************
*
* The original copyright of skeleton.c was as follows:
*
* skeleton.c Written 1993 by Donald Becker.
* Copyright 1993 United States Government as represented by the
* Director, National Security Agency. This software may only be used
* and distributed according to the terms of the GNU Public License as
* modified by SRC, incorporated herein by reference.
*
* **********************
*
* For more details, see drivers/net/arcnet.c
*
* **********************
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/system.h>
#include <linux/netdevice.h>
#include <linux/arcdevice.h>
#include <linux/com20020.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
#ifdef PCMCIA_DEBUG
static int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i");
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static void regdump(struct net_device *dev)
{
int ioaddr = dev->base_addr;
int count;
printk("com20020 register dump:\n");
for (count = ioaddr; count < ioaddr + 16; count++)
{
if (!(count % 16))
printk("\n%04X: ", count);
printk("%02X ", inb(count));
}
printk("\n");
printk("buffer0 dump:\n");
/* set up the address register */
count = 0;
outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
outb(count & 0xff, _ADDR_LO);
for (count = 0; count < 256+32; count++)
{
if (!(count % 16))
printk("\n%04X: ", count);
/* copy the data */
printk("%02X ", inb(_MEMDATA));
}
printk("\n");
}
#else
#define DEBUG(n, args...) do { } while (0)
static inline void regdump(struct net_device *dev) { }
#endif
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
static int node = 0;
static int timeout = 3;
static int backplane = 0;
static int clock = 0;
MODULE_PARM(node, "i");
MODULE_PARM(timeout, "i");
MODULE_PARM(backplane, "i");
MODULE_PARM(clock, "i");
/* Bit map of interrupts to choose from */
static u_int irq_mask = 0xdeb8;
static int irq_list[4] = { -1 };
MODULE_PARM(irq_mask, "i");
MODULE_PARM(irq_list, "1-4i");
/*====================================================================*/
static void com20020_config(dev_link_t *link);
static void com20020_release(u_long arg);
static int com20020_event(event_t event, int priority,
event_callback_args_t *args);
static dev_info_t dev_info = "com20020_cs";
static dev_link_t *com20020_attach(void);
static void com20020_detach(dev_link_t *);
static dev_link_t *dev_list = NULL;
/*====================================================================*/
typedef struct com20020_dev_t {
struct net_device *dev;
int dev_configured;
dev_node_t node;
} com20020_dev_t;
/*======================================================================
This bit of code is used to avoid unregistering network devices
at inappropriate times. 2.2 and later kernels are fairly picky
about when this can happen.
======================================================================*/
static void flush_stale_links(void)
{
dev_link_t *link, *next;
for (link = dev_list; link; link = next) {
next = link->next;
if (link->state & DEV_STALE_LINK)
com20020_detach(link);
}
}
/*====================================================================*/
static void cs_error(client_handle_t handle, int func, int ret)
{
error_info_t err = { func, ret };
CardServices(ReportError, handle, &err);
}
/*======================================================================
com20020_attach() creates an "instance" of the driver, allocating
local data structures for one device. The device is registered
with Card Services.
======================================================================*/
static void com20020cs_open_close(struct net_device *dev, bool open)
{
if (open)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
static dev_link_t *com20020_attach(void)
{
client_reg_t client_reg;
dev_link_t *link;
com20020_dev_t *info;
struct net_device *dev;
int i, ret;
struct arcnet_local *lp;
DEBUG(0, "com20020_attach()\n");
flush_stale_links();
/* Create new network device */
link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
if (!link)
return NULL;
memset(link, 0, sizeof(struct dev_link_t));
link->release.function = &com20020_release;
link->release.data = (u_long)link;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts1 = 16;
link->io.IOAddrLines = 16;
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
if (irq_list[0] == -1)
link->irq.IRQInfo2 = irq_mask;
else
for (i = 0; i < 4; i++)
link->irq.IRQInfo2 |= 1 << irq_list[i];
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.Vcc = 50;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.Present = PRESENT_OPTION;
info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
if (!info)
return NULL;
memset(info, 0, sizeof(struct com20020_dev_t));
dev = dev_alloc("arc%d", &ret);
if (!dev)
return NULL;
lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (!lp)
return NULL;
memset(lp, 0, sizeof(struct arcnet_local));
/* fill in our module parameters as defaults */
dev->dev_addr[0] = node;
lp->timeout = timeout;
lp->backplane = backplane;
lp->clock = clock;
lp->hw.open_close_ll = com20020cs_open_close;
link->irq.Instance = info->dev = dev;
link->priv = info;
/* Register with Card Services */
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
client_reg.EventMask =
CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.event_handler = &com20020_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = CardServices(RegisterClient, &link->handle, &client_reg);
if (ret != 0) {
cs_error(link->handle, RegisterClient, ret);
com20020_detach(link);
return NULL;
}
return link;
} /* com20020_attach */
/*======================================================================
This deletes a driver "instance". The device is de-registered
with Card Services. If it has been released, all local data
structures are freed. Otherwise, the structures will be freed
when the device is released.
======================================================================*/
static void com20020_detach(dev_link_t *link)
{
struct com20020_dev_t *info = link->priv;
dev_link_t **linkp;
struct net_device *dev;
DEBUG(1,"detach...\n");
DEBUG(0, "com20020_detach(0x%p)\n", link);
/* Locate device structure */
for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
if (*linkp == link) break;
if (*linkp == NULL)
return;
dev = info->dev;
if (link->state & DEV_CONFIG) {
com20020_release((u_long)link);
if (link->state & DEV_STALE_CONFIG) {
link->state |= DEV_STALE_LINK;
return;
}
}
if (link->handle)
CardServices(DeregisterClient, link->handle);
/* Unlink device structure, free bits */
DEBUG(1,"unlinking...\n");
*linkp = link->next;
if (link->priv)
{
dev = info->dev;
if (dev)
{
if (info->dev_configured)
{
DEBUG(1,"unregister...\n");
if (dev->start)
dev->stop(dev);
/*
* this is necessary because we register our IRQ separately
* from card services.
*/
if (dev->irq)
free_irq(dev->irq, dev);
/* ...but I/O ports are done automatically by card services */
unregister_netdev(dev);
MOD_DEC_USE_COUNT;
}
DEBUG(1,"kfree...\n");
kfree(dev->priv);
kfree(dev);
}
DEBUG(1,"kfree2...\n");
kfree_s(info, sizeof(struct com20020_dev_t));
}
DEBUG(1,"kfree3...\n");
kfree_s(link, sizeof(struct dev_link_t));
} /* com20020_detach */
/*======================================================================
com20020_config() is scheduled to run after a CARD_INSERTION event
is received, to configure the PCMCIA socket, and to make the
device available to the system.
======================================================================*/
#define CS_CHECK(fn, args...) \
while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
static void com20020_config(dev_link_t *link)
{
client_handle_t handle;
tuple_t tuple;
cisparse_t parse;
com20020_dev_t *info;
struct net_device *dev;
int i, last_ret, last_fn;
u_char buf[64];
int ioaddr;
handle = link->handle;
info = link->priv;
dev = info->dev;
DEBUG(1,"config...\n");
DEBUG(0, "com20020_config(0x%p)\n", link);
tuple.Attributes = 0;
tuple.TupleData = buf;
tuple.TupleDataMax = 64;
tuple.TupleOffset = 0;
tuple.DesiredTuple = CISTPL_CONFIG;
CS_CHECK(GetFirstTuple, handle, &tuple);
CS_CHECK(GetTupleData, handle, &tuple);
CS_CHECK(ParseTuple, handle, &tuple, &parse);
link->conf.ConfigBase = parse.config.base;
/* Configure card */
link->state |= DEV_CONFIG;
strcpy(info->node.dev_name, dev->name);
DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1);
i = !CS_SUCCESS;
if (!link->io.BasePort1)
{
for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
{
link->io.BasePort1 = ioaddr;
i = CardServices(RequestIO, link->handle, &link->io);
if (i == CS_SUCCESS)
break;
}
}
else
i = CardServices(RequestIO, link->handle, &link->io);
if (i != CS_SUCCESS)
{
DEBUG(1,"arcnet: requestIO failed totally!\n");
goto failed;
}
ioaddr = dev->base_addr = link->io.BasePort1;
DEBUG(1,"arcnet: got ioaddr %Xh\n", ioaddr);
DEBUG(1,"arcnet: request IRQ %d (%Xh/%Xh)\n",
link->irq.AssignedIRQ,
link->irq.IRQInfo1, link->irq.IRQInfo2);
i = CardServices(RequestIRQ, link->handle, &link->irq);
if (i != CS_SUCCESS)
{
DEBUG(1,"arcnet: requestIRQ failed totally!\n");
goto failed;
}
dev->irq = link->irq.AssignedIRQ;
CS_CHECK(RequestConfiguration, link->handle, &link->conf);
if (com20020_check(dev))
{
regdump(dev);
goto failed;
}
MOD_INC_USE_COUNT;
i = com20020_found(dev, 0);
if (i != 0) {
DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n");
goto failed;
}
info->dev_configured = 1;
link->dev = &info->node;
link->state &= ~DEV_CONFIG_PENDING;
DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n",
dev->name, dev->base_addr, dev->irq);
return;
cs_failed:
cs_error(link->handle, last_fn, last_ret);
failed:
DEBUG(1,"com20020_config failed...\n");
com20020_release((u_long)link);
} /* com20020_config */
/*======================================================================
After a card is removed, com20020_release() will unregister the net
device, and release the PCMCIA configuration. If the device is
still open, this will be postponed until it is closed.
======================================================================*/
static void com20020_release(u_long arg)
{
dev_link_t *link = (dev_link_t *)arg;
DEBUG(1,"release...\n");
DEBUG(0, "com20020_release(0x%p)\n", link);
if (link->open) {
DEBUG(1,"postpone...\n");
DEBUG(1, "com20020_cs: release postponed, device stll open\n");
link->state |= DEV_STALE_CONFIG;
return;
}
CardServices(ReleaseConfiguration, link->handle);
CardServices(ReleaseIO, link->handle, &link->io);
CardServices(ReleaseIRQ, link->handle, &link->irq);
link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
} /* com20020_release */
/*======================================================================
The card status event handler. Mostly, this schedules other
stuff to run after an event is received. A CARD_REMOVAL event
also sets some flags to discourage the net drivers from trying
to talk to the card any more.
======================================================================*/
static int com20020_event(event_t event, int priority,
event_callback_args_t *args)
{
dev_link_t *link = args->client_data;
com20020_dev_t *info = link->priv;
struct net_device *dev = info->dev;
DEBUG(1, "com20020_event(0x%06x)\n", event);
switch (event) {
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
dev->tbusy = 1; dev->start = 0;
link->release.expires = jiffies + HZ/20;
link->state |= DEV_RELEASE_PENDING;
add_timer(&link->release);
}
break;
case CS_EVENT_CARD_INSERTION:
link->state |= DEV_PRESENT;
com20020_config(link);
break;
case CS_EVENT_PM_SUSPEND:
link->state |= DEV_SUSPEND;
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
if (link->open) {
dev->tbusy = 1; dev->start = 0;
}
CardServices(ReleaseConfiguration, link->handle);
}
break;
case CS_EVENT_PM_RESUME:
link->state &= ~DEV_SUSPEND;
/* Fall through... */
case CS_EVENT_CARD_RESET:
if (link->state & DEV_CONFIG) {
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
int ioaddr = dev->base_addr;
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
ARCRESET;
}
}
break;
}
return 0;
} /* com20020_event */
/*====================================================================*/
static int __init init_com20020_cs(void)
{
servinfo_t serv;
DEBUG(0, "%s\n", VERSION);
CardServices(GetCardServicesInfo, &serv);
if (serv.Revision != CS_RELEASE_CODE) {
printk(KERN_NOTICE "com20020_cs: Card Services release "
"does not match!\n");
return -1;
}
register_pccard_driver(&dev_info, &com20020_attach, &com20020_detach);
return 0;
}
static void __exit exit_com20020_cs(void)
{
DEBUG(0, "com20020_cs: unloading\n");
unregister_pccard_driver(&dev_info);
while (dev_list != NULL)
com20020_detach(dev_list);
}
module_init(init_com20020_cs);
module_exit(exit_com20020_cs);
......@@ -1464,6 +1464,9 @@ tulip_up(struct net_device *dev)
outl(tp->csr0, ioaddr + CSR0);
udelay(2);
if (tulip_tbl[tp->chip_id].flags & HAS_ACPI)
pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0x00000000);
/* Clear the tx ring */
for (i = 0; i < TX_RING_SIZE; i++) {
tp->tx_skbuff[i] = 0;
......
......@@ -1687,12 +1687,6 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base,
parport_pc_write_data(p, 0);
parport_pc_data_forward (p);
parport_pc_write_control(p, PARPORT_CONTROL_SELECT);
udelay (50);
parport_pc_write_control(p,
PARPORT_CONTROL_SELECT
| PARPORT_CONTROL_INIT);
udelay (50);
/* Now that we've told the sharing engine about the port, and
found out its characteristics, let the high-level drivers
......
......@@ -95,6 +95,14 @@ static void call_driver_chain(int attach, struct parport *port)
}
}
/* Ask kmod for some lowlevel drivers. */
static void get_lowlevel_driver (void)
{
/* There is no actual module called this: you should set
* up an alias for modutils. */
request_module ("parport_lowlevel");
}
int parport_register_driver (struct parport_driver *drv)
{
struct parport *port;
......@@ -107,12 +115,8 @@ int parport_register_driver (struct parport_driver *drv)
for (port = portlist; port; port = port->next)
drv->attach (port);
/* For compatibility with 2.2, check the (obsolete) parport_lowlevel
* alias in case some people haven't changed to post-install rules
* yet. parport_enumerate (itself deprecated) will printk a
* friendly reminder. */
if (!portlist)
parport_enumerate ();
get_lowlevel_driver ();
return 0;
}
......@@ -123,12 +127,21 @@ void parport_unregister_driver (struct parport_driver *arg)
while (drv) {
if (drv == arg) {
struct parport *port;
spin_lock (&driverlist_lock);
if (olddrv)
olddrv->next = drv->next;
else
driver_chain = drv->next;
spin_unlock (&driverlist_lock);
/* Call the driver's detach routine for each
* port to clean up any resources that the
* attach routine acquired. */
for (port = portlist; port; port = port->next)
drv->detach (port);
return;
}
olddrv = drv;
......@@ -136,20 +149,12 @@ void parport_unregister_driver (struct parport_driver *arg)
}
}
/* Return a list of all the ports we know about. */
/* Return a list of all the ports we know about. This function shouldn't
* really be used -- use parport_register_driver instead. */
struct parport *parport_enumerate(void)
{
/* Attempt to make things work on 2.2 systems. */
if (!portlist) {
request_module ("parport_lowlevel");
if (portlist)
/* The user has a parport_lowlevel alias in
* modules.conf. Warn them that it won't work
* for long. */
printk (KERN_WARNING
"parport: 'parport_lowlevel' is deprecated; "
"see parport.txt\n");
}
if (!portlist)
get_lowlevel_driver ();
return portlist;
}
......
......@@ -131,7 +131,7 @@ MODULE_PARM(io_speed, "i");
/*====================================================================*/
static socket_state_t dead_socket = {
socket_state_t dead_socket = {
0, SS_DETECT, 0, 0, 0
};
......@@ -276,29 +276,16 @@ static int set_mem_map(socket_info_t *s, struct pccard_mem_map *mem)
return s->ss_entry->set_mem_map(s->sock, mem);
}
/*======================================================================
Reset a socket to the default state
======================================================================*/
static void init_socket(socket_info_t *s)
static int suspend_socket(socket_info_t *s)
{
int i;
pccard_io_map io = { 0, 0, 0, 0, 1 };
pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
s->socket = dead_socket;
return s->ss_entry->suspend(s->sock);
}
mem.sys_stop = s->cap.map_size;
s->socket = dead_socket;
set_socket(s, &s->socket);
for (i = 0; i < 2; i++) {
io.map = i;
set_io_map(s, &io);
}
for (i = 0; i < 5; i++) {
mem.map = i;
set_mem_map(s, &mem);
}
static int init_socket(socket_info_t *s)
{
s->socket = dead_socket;
return s->ss_entry->init(s->sock);
}
/*====================================================================*/
......@@ -704,7 +691,7 @@ static int handle_apm_event(apm_event_t event)
if ((s->state & SOCKET_PRESENT) &&
!(s->state & SOCKET_SUSPEND)){
send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
set_socket(s, &dead_socket);
suspend_socket(s);
s->state |= SOCKET_SUSPEND;
}
}
......@@ -1972,7 +1959,7 @@ int pcmcia_suspend_card(client_handle_t handle, client_req_t *req)
DEBUG(1, "cs: suspending socket %d\n", i);
send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
set_socket(s, &dead_socket);
suspend_socket(s);
s->state |= SOCKET_SUSPEND;
return CS_SUCCESS;
......
......@@ -2664,7 +2664,33 @@ static int pcic_set_bridge(unsigned int sock, struct cb_bridge_map *m)
#endif
}
static int pcic_init(unsigned int s)
{
int i;
pccard_io_map io = { 0, 0, 0, 0, 1 };
pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
mem.sys_stop = 0x1000;
pcic_set_socket(s, &dead_socket);
for (i = 0; i < 2; i++) {
io.map = i;
pcic_set_io_map(s, &io);
}
for (i = 0; i < 5; i++) {
mem.map = i;
pcic_set_mem_map(s, &mem);
}
return 0;
}
static int pcic_suspend(unsigned int sock)
{
return pcic_set_socket(sock, &dead_socket);
}
static struct pccard_operations pcic_operations = {
pcic_init,
pcic_suspend,
pcic_register_callback,
pcic_inquire_socket,
pcic_get_status,
......
......@@ -42,11 +42,24 @@ static struct pci_simple_probe_entry controller_list[] = {
#define MAX_SOCKETS (8)
static pci_socket_t pci_socket_array[MAX_SOCKETS];
/*
* Work in progress. I need to distill the _real_ differences in
* carbus drivers, and change the cardbus "op" list to match. This
* is just a direct 1:1 mapping of the pccard operations.
*/
static int pci_init_socket(unsigned int sock)
{
pci_socket_t *socket = pci_socket_array + sock;
if (socket->op && socket->op->init)
return socket->op->init(socket);
return -EINVAL;
}
static int pci_suspend_socket(unsigned int sock)
{
pci_socket_t *socket = pci_socket_array + sock;
if (socket->op && socket->op->suspend)
return socket->op->suspend(socket);
return -EINVAL;
}
static int pci_register_callback(unsigned int sock, void (*handler)(void *, unsigned int), void * info)
{
pci_socket_t *socket = pci_socket_array + sock;
......@@ -160,6 +173,8 @@ static void pci_proc_setup(unsigned int sock, struct proc_dir_entry *base)
}
static struct pccard_operations pci_socket_operations = {
pci_init_socket,
pci_suspend_socket,
pci_register_callback,
pci_inquire_socket,
pci_get_status,
......
......@@ -20,6 +20,8 @@ struct pci_socket_ops {
int (*open)(struct pci_socket *);
void (*close)(struct pci_socket *);
int (*init)(struct pci_socket *);
int (*suspend)(struct pci_socket *);
int (*inquire)(struct pci_socket *, socket_cap_t *cap);
int (*get_status)(struct pci_socket *, unsigned int *);
int (*get_socket)(struct pci_socket *, socket_state_t *);
......
......@@ -929,18 +929,44 @@ static int tcic_set_mem_map(unsigned int lsock, struct pccard_mem_map *mem)
/*====================================================================*/
int tcic_get_bridge(unsigned int sock, struct cb_bridge_map *m)
static int tcic_get_bridge(unsigned int sock, struct cb_bridge_map *m)
{
return -EINVAL;
}
#define tcic_set_bridge tcic_get_bridge
void tcic_proc_setup(unsigned int sock, struct proc_dir_entry *base)
static void tcic_proc_setup(unsigned int sock, struct proc_dir_entry *base)
{
}
static int tcic_init(unsigned int s)
{
int i;
pccard_io_map io = { 0, 0, 0, 0, 1 };
pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
mem.sys_stop = 0x1000;
tcic_set_socket(s, &dead_socket);
for (i = 0; i < 2; i++) {
io.map = i;
tcic_set_io_map(s, &io);
}
for (i = 0; i < 5; i++) {
mem.map = i;
tcic_set_mem_map(s, &mem);
}
return 0;
}
static int tcic_suspend(unsigned int sock)
{
return tcic_set_socket(sock, &dead_socket);
}
static struct pccard_operations tcic_operations = {
tcic_init,
tcic_suspend,
tcic_register_callback,
tcic_inquire_socket,
tcic_get_status,
......
......@@ -79,13 +79,24 @@ static int yenta_Vpp_power(u32 control)
static int yenta_get_socket(pci_socket_t *socket, socket_state_t *state)
{
u32 control = cb_readl(socket, CB_SOCKET_CONTROL);
u8 reg;
u32 status, control;
status = cb_readb(socket, CB_SOCKET_STATE);
control = cb_readl(socket, CB_SOCKET_CONTROL);
state->Vcc = yenta_Vcc_power(control);
state->Vpp = yenta_Vpp_power(control);
state->io_irq = socket->io_irq;
if (status & CB_CBCARD) {
u16 bridge = cb_readw(socket, CB_BRIDGE_CONTROL);
if (bridge & CB_BRIDGE_CRST)
state->flags |= SS_RESET;
return 0;
}
/* 16-bit card state.. */
reg = exca_readb(socket, I365_POWER);
state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0;
state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0;
......@@ -104,8 +115,6 @@ static int yenta_get_socket(pci_socket_t *socket, socket_state_t *state)
state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0;
}
printk("yenta_get_socket(%p) = %d, %d\n", socket, state->Vcc, state->Vpp);
return 0;
}
......@@ -439,11 +448,25 @@ static unsigned int yenta_probe_irq(pci_socket_t *socket)
{
int i;
unsigned long val;
u16 bridge_ctrl;
/* Are we set up to route the IO irq to the PCI irq? */
bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
if (!(bridge_ctrl & CB_BRIDGE_INTR)) {
socket->io_irq = socket->cb_irq;
if (socket->cb_irq && socket->cb_irq < 16)
return 1 << socket->cb_irq;
printk("CardBus: Hmm.. Routing interrupts to bad PCI irq %d\n", socket->cb_irq);
return 0;
}
cb_writel(socket, CB_SOCKET_EVENT, -1);
cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
val = probe_irq_on();
for (i = 1; i < 16; i++) {
if (!((val >> i) & 1))
continue;
exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4));
cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS);
udelay(100);
......@@ -460,11 +483,9 @@ static void yenta_get_socket_capabilities(pci_socket_t *socket)
config_writeb(socket, PCI_SEC_LATENCY_TIMER, 176);
socket->cap.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
socket->cap.irq_mask = yenta_probe_irq(socket);
if (socket->cb_irq && socket->cb_irq < 16)
socket->cap.irq_mask |= 1 << socket->cb_irq;
socket->cap.map_size = 0x1000;
socket->cap.pci_irq = socket->cb_irq;
socket->cap.irq_mask = yenta_probe_irq(socket);
socket->cap.cardbus = config_readb(socket, PCI_CB_CARD_BUS);
socket->cap.cb_bus = socket->dev->subordinate;
socket->cap.bus = NULL;
......@@ -472,6 +493,35 @@ static void yenta_get_socket_capabilities(pci_socket_t *socket)
printk("Yenta IRQ list %04x\n", socket->cap.irq_mask);
}
/* Called at resume and initialization events */
static int yenta_init(pci_socket_t *socket)
{
int i;
pccard_io_map io = { 0, 0, 0, 0, 1 };
pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
pci_set_power_state(socket->dev, 0);
mem.sys_stop = 0x1000;
yenta_set_socket(socket, &dead_socket);
for (i = 0; i < 2; i++) {
io.map = i;
yenta_set_io_map(socket, &io);
}
for (i = 0; i < 5; i++) {
mem.map = i;
yenta_set_mem_map(socket, &mem);
}
return 0;
}
static int yenta_suspend(pci_socket_t *socket)
{
yenta_set_socket(socket, &dead_socket);
pci_set_power_state(socket->dev, 3);
return 0;
}
/*
* Initialize a cardbus controller. Make sure we have a usable
* interrupt, and that we can map the cardbus area. Fill in the
......@@ -528,6 +578,8 @@ static void yenta_close(pci_socket_t *sock)
struct pci_socket_ops yenta_operations = {
yenta_open,
yenta_close,
yenta_init,
yenta_suspend,
yenta_inquire,
yenta_get_status,
yenta_get_socket,
......
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. NET is implemented using the BSD Socket
* interface as the means of communication with the user level.
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. NET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* Definitions for the ARCnet handlers.
* Definitions used by the ARCnet driver.
*
* Version: $Id: arcdevice.h,v 1.3 1997/11/09 11:05:05 mj Exp $
* Authors: Avery Pennarun and David Woodhouse
*
* Authors: Avery Pennarun <apenwarr@bond.net>
* David Woodhouse <dwmw2@cam.ac.uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#ifndef _LINUX_ARCDEVICE_H
#define _LINUX_ARCDEVICE_H
#include <linux/config.h>
#include <asm/timex.h>
#include <linux/if_arcnet.h>
#ifdef __KERNEL__
#define ARC_20020 1
#define ARC_RIM_I 2
#define ARC_90xx 3
#define ARC_90xx_IO 4
#define MAX_ARCNET_DEVS 8
/* The card sends the reconfiguration signal when it loses the connection to
* the rest of its network. It is a 'Hello, is anybody there?' cry. This
* usually happens when a new computer on the network is powered on or when
* the cable is broken.
*
* Define DETECT_RECONFIGS if you want to detect network reconfigurations.
* Recons may be a real nuisance on a larger ARCnet network; if you are a
* network administrator you probably would like to count them.
* Reconfigurations will be recorded in stats.tx_carrier_errors (the last
* field of the /proc/net/dev file).
*
* Define SHOW_RECONFIGS if you really want to see a log message whenever
* a RECON occurs.
*/
#define DETECT_RECONFIGS
#undef SHOW_RECONFIGS
#ifndef bool
# define bool int
#endif
/* RECON_THRESHOLD is the maximum number of RECON messages to receive within
* one minute before printing a "cabling problem" warning. You must have
* DETECT_RECONFIGS enabled if you want to use this. The default value
* should be fine.
/*
* RECON_THRESHOLD is the maximum number of RECON messages to receive
* within one minute before printing a "cabling problem" warning. The
* default value should be fine.
*
* After that, a "cabling restored" message will be printed on the next IRQ
* if no RECON messages have been received for 10 seconds.
......@@ -63,47 +39,43 @@
#define RECON_THRESHOLD 30
/* Define this to the minimum "timeout" value. If a transmit takes longer
/*
* Define this to the minimum "timeout" value. If a transmit takes longer
* than TX_TIMEOUT jiffies, Linux will abort the TX and retry. On a large
* network, or one with heavy network traffic, this timeout may need to be
* increased. The larger it is, though, the longer it will be between
* necessary transmits - don't set this too large.
* necessary transmits - don't set this too high.
*/
#define TX_TIMEOUT (20*HZ/100)
#define TX_TIMEOUT (HZ * 200 / 1000)
/* Display warnings about the driver being an ALPHA version.
*/
/* Display warnings about the driver being an ALPHA version. */
#undef ALPHA_WARNING
/* New debugging bitflags: each option can be enabled individually.
*
* These can be set while the driver is running by typing:
* ifconfig arc0 down metric 1xxx HOSTNAME
* where 1xxx is 1000 + the debug level you want
* and HOSTNAME is your hostname/ip address
* and then resetting your routes.
*
* An ioctl() should be used for this instead, someday.
*
/*
* Debugging bitflags: each option can be enabled individually.
*
* Note: only debug flags included in the ARCNET_DEBUG_MAX define will
* actually be available. GCC will (at least, GCC 2.7.0 will) notice
* lines using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize
* them out.
*/
#define D_NORMAL 1 /* important operational info */
#define D_EXTRA 2 /* useful, but non-vital information */
#define D_INIT 4 /* show init/probe messages */
#define D_INIT_REASONS 8 /* show reasons for discarding probes */
#define D_NORMAL 1 /* important operational info */
#define D_EXTRA 2 /* useful, but non-vital information */
#define D_INIT 4 /* show init/probe messages */
#define D_INIT_REASONS 8 /* show reasons for discarding probes */
#define D_RECON 32 /* print a message whenever token is lost */
#define D_PROTO 64 /* debug auto-protocol support */
/* debug levels below give LOTS of output during normal operation! */
#define D_DURING 16 /* trace operations (including irq's) */
#define D_TX 32 /* show tx packets */
#define D_RX 64 /* show rx packets */
#define D_SKB 128 /* show skb's */
#define D_DURING 128 /* trace operations (including irq's) */
#define D_TX 256 /* show tx packets */
#define D_RX 512 /* show rx packets */
#define D_SKB 1024 /* show skb's */
#define D_TIMING 2048 /* show time needed to copy buffers to card */
#ifndef ARCNET_DEBUG_MAX
#define ARCNET_DEBUG_MAX (~0) /* enable ALL debug messages */
#define ARCNET_DEBUG_MAX (~0) /* enable ALL debug messages */
#endif
#ifndef ARCNET_DEBUG
......@@ -115,240 +87,253 @@ extern int arcnet_debug;
#define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
#define BUGMSG2(x,msg,args...) do { BUGLVL(x) printk(msg, ## args); } while (0)
#define BUGMSG(x,msg,args...) \
BUGMSG2(x,"%s%6s: " msg, \
x==D_NORMAL ? KERN_WARNING : \
x<=D_INIT_REASONS ? KERN_INFO : KERN_DEBUG , \
dev->name , ## args)
#define SETMASK AINTMASK(lp->intmask)
/* Time needed to resetthe card - in jiffies. This works on my SMC
* PC100. I can't find a reference that tells me just how long I
* should wait.
*/
#define RESETtime (HZ * 3 / 10) /* reset */
/* these are the max/min lengths of packet data. (including
* ClientData header)
* note: packet sizes 250, 251, 252 are impossible (God knows why)
* so exception packets become necessary.
*
* These numbers are compared with the length of the full packet,
* including ClientData header.
*/
#define MTU 253 /* normal packet max size */
#define MinTU 257 /* extended packet min size */
#define XMTU 508 /* extended packet max size */
/* status/interrupt mask bit fields */
#define TXFREEflag 0x01 /* transmitter available */
#define TXACKflag 0x02 /* transmitted msg. ackd */
#define RECONflag 0x04 /* system reconfigured */
#define TESTflag 0x08 /* test flag */
#define RESETflag 0x10 /* power-on-reset */
#define RES1flag 0x20 /* reserved - usually set by jumper */
#define RES2flag 0x40 /* reserved - usually set by jumper */
#define NORXflag 0x80 /* receiver inhibited */
/* Flags used for IO-mapped memory operations */
#define AUTOINCflag 0x40 /* Increase location with each access */
#define IOMAPflag 0x02 /* (for 90xx) Use IO mapped memory, not mmap */
#define ENABLE16flag 0x80 /* (for 90xx) Enable 16-bit mode */
/* in the command register, the following bits have these meanings:
* 0-2 command
* 3-4 page number (for enable rcv/xmt command)
* 7 receive broadcasts
*/
#define NOTXcmd 0x01 /* disable transmitter */
#define NORXcmd 0x02 /* disable receiver */
#define TXcmd 0x03 /* enable transmitter */
#define RXcmd 0x04 /* enable receiver */
#define CONFIGcmd 0x05 /* define configuration */
#define CFLAGScmd 0x06 /* clear flags */
#define TESTcmd 0x07 /* load test flags */
/* flags for "clear flags" command */
#define RESETclear 0x08 /* power-on-reset */
#define CONFIGclear 0x10 /* system reconfigured */
/* flags for "load test flags" command */
#define TESTload 0x08 /* test flag (diagnostic) */
/* byte deposited into first address of buffers on reset */
#define TESTvalue 0321 /* that's octal for 0xD1 :) */
/* for "enable receiver" command */
#define RXbcasts 0x80 /* receive broadcasts */
/* flags for "define configuration" command */
#define NORMALconf 0x00 /* 1-249 byte packets */
#define EXTconf 0x08 /* 250-504 byte packets */
/* Starts receiving packets into recbuf.
*/
#define EnableReceiver() ACOMMAND(RXcmd|(recbuf<<3)|RXbcasts)
#define JIFFER(time) for (delayval=jiffies+time; time_before(jiffies,delayval);) ;
/* a complete ARCnet packet */
union ArcPacket
{
struct archdr hardheader; /* the hardware header */
u_char raw[512]; /* raw packet info, incl ClientData */
};
BUGMSG2(x, "%s%6s: " msg, \
x==D_NORMAL ? KERN_WARNING \
: x < D_DURING ? KERN_INFO : KERN_DEBUG, \
dev->name , ## args)
/* see how long a function call takes to run, expressed in CPU cycles */
#define TIME(name, bytes, call) BUGLVL(D_TIMING) { \
cycles_t _x, _y; \
_x = get_cycles(); \
call; \
_y = get_cycles(); \
BUGMSG(D_TIMING, \
"%s: %d bytes in %lu cycles == " \
"%lu Kbytes/100Mcycle\n",\
name, bytes, _y - _x, \
100000000 / 1024 * bytes / (_y - _x + 1));\
} \
else { \
call;\
}
/* the "client data" header - RFC1201 information
* notice that this screws up if it's not an even number of bytes
* <sigh>
*/
struct ClientData
{
/* data that's NOT part of real packet - we MUST get rid of it before
* actually sending!!
*/
u_char saddr, /* Source address - needed for IPX */
daddr; /* Destination address */
/* data that IS part of real packet */
u_char protocol_id, /* ARC_P_IP, ARC_P_ARP, etc */
split_flag; /* for use with split packets */
u_short sequence; /* sequence number */
};
#define EXTRA_CLIENTDATA (sizeof(struct ClientData)-4)
/*
* Time needed to reset the card - in ms (milliseconds). This works on my
* SMC PC100. I can't find a reference that tells me just how long I
* should wait.
*/
#define RESETtime (300)
/*
* These are the max/min lengths of packet payload, not including the
* arc_hardware header, but definitely including the soft header.
*
* Note: packet sizes 254, 255, 256 are impossible because of the way
* ARCnet registers work That's why RFC1201 defines "exception" packets.
* In non-RFC1201 protocols, we have to just tack some extra bytes on the
* end.
*/
#define MTU 253 /* normal packet max size */
#define MinTU 257 /* extended packet min size */
#define XMTU 508 /* extended packet max size */
/* status/interrupt mask bit fields */
#define TXFREEflag 0x01 /* transmitter available */
#define TXACKflag 0x02 /* transmitted msg. ackd */
#define RECONflag 0x04 /* network reconfigured */
#define TESTflag 0x08 /* test flag */
#define RESETflag 0x10 /* power-on-reset */
#define RES1flag 0x20 /* reserved - usually set by jumper */
#define RES2flag 0x40 /* reserved - usually set by jumper */
#define NORXflag 0x80 /* receiver inhibited */
/* Flags used for IO-mapped memory operations */
#define AUTOINCflag 0x40 /* Increase location with each access */
#define IOMAPflag 0x02 /* (for 90xx) Use IO mapped memory, not mmap */
#define ENABLE16flag 0x80 /* (for 90xx) Enable 16-bit mode */
/* in the command register, the following bits have these meanings:
* 0-2 command
* 3-4 page number (for enable rcv/xmt command)
* 7 receive broadcasts
*/
#define NOTXcmd 0x01 /* disable transmitter */
#define NORXcmd 0x02 /* disable receiver */
#define TXcmd 0x03 /* enable transmitter */
#define RXcmd 0x04 /* enable receiver */
#define CONFIGcmd 0x05 /* define configuration */
#define CFLAGScmd 0x06 /* clear flags */
#define TESTcmd 0x07 /* load test flags */
/* flags for "clear flags" command */
#define RESETclear 0x08 /* power-on-reset */
#define CONFIGclear 0x10 /* system reconfigured */
/* flags for "load test flags" command */
#define TESTload 0x08 /* test flag (diagnostic) */
/* byte deposited into first address of buffers on reset */
#define TESTvalue 0321 /* that's octal for 0xD1 :) */
/* for "enable receiver" command */
#define RXbcasts 0x80 /* receive broadcasts */
/* the "client data" header - RFC1051 information
* this also screws up if it's not an even number of bytes
* <sigh again>
*/
struct S_ClientData
/* flags for "define configuration" command */
#define NORMALconf 0x00 /* 1-249 byte packets */
#define EXTconf 0x08 /* 250-504 byte packets */
/* information needed to define an encapsulation driver */
struct ArcProto
{
/* data that's NOT part of real packet - we MUST get rid of it before
* actually sending!!
*/
u_char saddr, /* Source address - needed for IPX */
daddr, /* Destination address */
junk; /* padding to make an even length */
/* data that IS part of real packet */
u_char protocol_id; /* ARC_P_IP, ARC_P_ARP, etc */
char suffix; /* a for RFC1201, e for ether-encap, etc. */
int mtu; /* largest possible packet */
void (*rx)(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length);
int (*build_header)(struct sk_buff *skb, unsigned short ethproto,
uint8_t daddr);
/* these functions return '1' if the skb can now be freed */
int (*prepare_tx)(struct net_device *dev, struct archdr *pkt, int length,
int bufnum);
int (*continue_tx)(struct net_device *dev, int bufnum);
};
#define S_EXTRA_CLIENTDATA (sizeof(struct S_ClientData)-1)
extern struct ArcProto *arc_proto_map[256],
*arc_proto_default, *arc_bcast_proto;
extern struct ArcProto arc_proto_null;
/* "Incoming" is information needed for each address that could be sending
/*
* "Incoming" is information needed for each address that could be sending
* to us. Mostly for partially-received split packets.
*/
struct Incoming
{
struct sk_buff *skb; /* packet data buffer */
unsigned char lastpacket, /* number of last packet (from 1) */
numpackets; /* number of packets in split */
u_short sequence; /* sequence number of assembly */
struct sk_buff *skb; /* packet data buffer */
uint16_t sequence; /* sequence number of assembly */
uint8_t lastpacket, /* number of last packet (from 1) */
numpackets; /* number of packets in split */
};
/* only needed for RFC1201 */
struct Outgoing
{
struct sk_buff *skb; /* buffer from upper levels */
struct ClientData *hdr; /* clientdata of last packet */
u_char *data; /* pointer to data in packet */
short length, /* bytes total */
dataleft, /* bytes left */
segnum, /* segment being sent */
numsegs, /* number of segments */
seglen; /* length of segment */
struct ArcProto *proto; /* protocol driver that owns this:
* if NULL, no packet is pending.
*/
struct sk_buff *skb; /* buffer from upper levels */
struct archdr *pkt; /* a pointer into the skb */
uint16_t length, /* bytes total */
dataleft, /* bytes left */
segnum, /* segment being sent */
numsegs; /* number of segments */
};
struct arcnet_local {
struct net_device_stats stats;
u_short sequence; /* sequence number (incs with each packet) */
u_short aborted_seq;
u_char stationid, /* our 8-bit station address */
recbuf, /* receive buffer # (0 or 1) */
txbuf, /* transmit buffer # (2 or 3) */
txready, /* buffer where a packet is ready to send */
config, /* current value of CONFIG register */
timeout, /* Extended timeout for COM20020 */
backplane, /* Backplane flag for COM20020 */
setup, /* Contents of setup register */
intmask; /* current value of INTMASK register */
short intx, /* in TX routine? */
in_txhandler, /* in TX_IRQ handler? */
sending, /* transmit in progress? */
lastload_dest, /* can last loaded packet be acked? */
lasttrans_dest; /* can last TX'd packet be acked? */
#if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD)
time_t first_recon, /* time of "first" RECON message to count */
last_recon; /* time of most recent RECON */
int num_recons, /* number of RECONs between first and last. */
network_down; /* do we think the network is down? */
#endif
struct timer_list timer; /* the timer interrupt struct */
struct Incoming incoming[256]; /* one from each address */
struct Outgoing outgoing; /* packet currently being sent */
int card_type;
char *card_type_str;
void (*inthandler) (struct net_device *dev);
int (*arcnet_reset) (struct net_device *dev, int reset_delay);
void (*asetmask) (struct net_device *dev, u_char mask);
void (*acommand) (struct net_device *dev, u_char command);
u_char (*astatus) (struct net_device *dev);
void (*en_dis_able_TX) (struct net_device *dev, int enable);
void (*prepare_tx)(struct net_device *dev,u_char *hdr,int hdrlen,
char *data,int length,int daddr,int exceptA, int offset);
void (*openclose_device)(int open);
struct net_device *adev; /* RFC1201 protocol device */
/* These are last to ensure that the chipset drivers don't depend on the
* CONFIG_ARCNET_ETH and CONFIG_ARCNET_1051 options.
*/
#ifdef CONFIG_ARCNET_ETH
struct net_device *edev; /* Ethernet-Encap device */
#endif
#ifdef CONFIG_ARCNET_1051
struct net_device *sdev; /* RFC1051 protocol device */
#endif
struct arcnet_local
{
struct net_device_stats stats;
uint8_t config, /* current value of CONFIG register */
timeout, /* Extended timeout for COM20020 */
backplane, /* Backplane flag for COM20020 */
clock, /* COM20020 clock speed flag */
setup, /* Contents of setup register */
intmask; /* current value of INTMASK register */
uint8_t default_proto[256]; /* default encap to use for each host */
int cur_tx, /* buffer used by current transmit, or -1 */
next_tx, /* buffer where a packet is ready to send */
cur_rx; /* current receive buffer */
int lastload_dest, /* can last loaded packet be acked? */
lasttrans_dest; /* can last TX'd packet be acked? */
int basename_len; /* name length without suffix ('arc0e' -> 4) */
/*
* Buffer management: an ARCnet card has 4 x 512-byte buffers, each of
* which can be used for either sending or receiving. The new dynamic
* buffer management routines use a simple circular queue of available
* buffers, and take them as they're needed. This way, we simplify
* situations in which we (for example) want to pre-load a transmit
* buffer, or start receiving while we copy a received packet to
* memory.
*
* The rules: only the interrupt handler is allowed to _add_ buffers to
* the queue; thus, this doesn't require a lock. Both the interrupt
* handler and the transmit function will want to _remove_ buffers, so
* we need to handle the situation where they try to do it at the same
* time.
*
* If next_buf == first_free_buf, the queue is empty. Since there are
* only four possible buffers, the queue should never be full.
*/
atomic_t buf_lock;
int buf_queue[5];
int next_buf, first_free_buf;
/* network "reconfiguration" handling */
time_t first_recon, /* time of "first" RECON message to count */
last_recon; /* time of most recent RECON */
int num_recons; /* number of RECONs between first and last. */
bool network_down; /* do we think the network is down? */
struct {
uint16_t sequence; /* sequence number (incs with each packet) */
uint16_t aborted_seq;
struct Incoming incoming[256]; /* one from each address */
} rfc1201;
/* really only used by rfc1201, but we'll pretend it's not */
struct Outgoing outgoing; /* packet currently being sent */
/* hardware-specific functions */
struct {
void (*command) (struct net_device *dev, int cmd);
int (*status) (struct net_device *dev);
void (*intmask) (struct net_device *dev, int mask);
bool (*reset) (struct net_device *dev, bool really_reset);
void (*open_close)(struct net_device *dev, bool open);
void (*open_close_ll)(struct net_device *dev, bool open);
void (*copy_to_card)(struct net_device *dev, int bufnum, int offset,
void *buf, int count);
void (*copy_from_card)(struct net_device *dev, int bufnum, int offset,
void *buf, int count);
} hw;
void *mem_start; /* pointer to ioremap'ed MMIO */
};
/* Functions exported by arcnet.c
*/
#define ARCRESET(x) (lp->hw.reset(dev, (x)))
#define ACOMMAND(x) (lp->hw.command(dev, (x)))
#define ASTATUS() (lp->hw.status(dev))
#define AINTMASK(x) (lp->hw.intmask(dev, (x)))
#define ARCOPEN(x) (lp->hw.open_close(dev, (x)))
#if ARCNET_DEBUG_MAX & D_SKB
extern void arcnet_dump_skb(struct net_device *dev,struct sk_buff *skb,
char *desc);
void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc);
#else
#define arcnet_dump_skb(dev,skb,desc) ;
# define arcnet_dump_skb(dev,skb,desc) ;
#endif
#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
extern void arcnet_dump_packet(struct net_device *dev,u_char *buffer,int ext,
char *desc);
void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc);
#else
#define arcnet_dump_packet(dev,buffer,ext,desc) ;
# define arcnet_dump_packet(dev, bufnum, desc) ;
#endif
extern void arcnet_tx_done(struct net_device *dev, struct arcnet_local *lp);
extern void arcnet_makename(char *device);
extern void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs);
extern void arcnet_setup(struct net_device *dev);
extern int arcnet_go_tx(struct net_device *dev,int enable_irq);
extern void arcnetA_continue_tx(struct net_device *dev);
extern void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr);
extern void arcnet_use_count(int open);
void arcnet_unregister_proto(struct ArcProto *proto);
void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
void arcdev_setup(struct net_device *dev);
void arcnet_rx(struct net_device *dev, int bufnum);
void arcnet_init(void);
void arcnet_rfc1201_init(void);
void arcnet_rfc1051_init(void);
void arcnet_raw_init(void);
int com90xx_probe(struct net_device *dev);
void com20020pci_probe_all(void);
#endif /* __KERNEL__ */
#endif /* __KERNEL__ */
#endif /* _LINUX_ARCDEVICE_H */
#endif /* _LINUX_ARCDEVICE_H */
/*
* Linux ARCnet driver - COM20020 chipset support - function declarations
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
* for sponsoring the further development of this driver.
*
* **********************
*
* The original copyright of skeleton.c was as follows:
*
* skeleton.c Written 1993 by Donald Becker.
* Copyright 1993 United States Government as represented by the
* Director, National Security Agency. This software may only be used
* and distributed according to the terms of the GNU Public License as
* modified by SRC, incorporated herein by reference.
*
* **********************
*
* For more details, see drivers/net/arcnet.c
*
* **********************
*/
#ifndef __COM20020_H
#define __COM20020_H
int com20020_check(struct net_device *dev);
int com20020_found(struct net_device *dev, int shared);
/* The number of low I/O ports used by the card. */
#define ARCNET_TOTAL_SIZE 9
/* various register addresses */
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* standard arcnet commands */
#define _DIAGSTAT (ioaddr+1) /* diagnostic status register */
#define _ADDR_HI (ioaddr+2) /* control registers for IO-mapped memory */
#define _ADDR_LO (ioaddr+3)
#define _MEMDATA (ioaddr+4) /* data port for IO-mapped memory */
#define _CONFIG (ioaddr+6) /* configuration register */
#define _SETUP (ioaddr+7) /* setup register */
/* in the ADDR_HI register */
#define RDDATAflag 0x80 /* next access is a read (not a write) */
/* in the DIAGSTAT register */
#define NEWNXTIDflag 0x02 /* ID to which token is passed has changed */
/* in the CONFIG register */
#define RESETcfg 0x80 /* put card in reset state */
#define TXENcfg 0x20 /* enable TX */
/* in SETUP register */
#define PROMISCset 0x10 /* enable RCV_ALL */
#define REGTENTID (lp->config &= ~3);
#define REGNID (lp->config = (lp->config&~2)|1);
#define REGSETUP (lp->config = (lp->config&~1)|2);
#define REGNXTID (lp->config |= 3);
#undef ARCRESET
#undef ASTATUS
#undef ACOMMAND
#undef AINTMASK
#define ARCRESET { outb(lp->config | 0x80, _CONFIG); \
udelay(5); \
outb(lp->config , _CONFIG); \
}
#define ARCRESET0 { outb(0x18 | 0x80, _CONFIG); \
udelay(5); \
outb(0x18 , _CONFIG); \
}
#define ASTATUS() inb(_STATUS)
#define ACOMMAND(cmd) outb((cmd),_COMMAND)
#define AINTMASK(msk) outb((msk),_INTMASK)
#define SETCONF(cfg) outb(cfg, _CONFIG)
#endif /* __COM20020_H */
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* Global definitions for the ARCnet interface.
* Global definitions for the ARCnet interface.
*
* Version: $Id: if_arcnet.h,v 1.2 1997/09/05 08:57:54 mj Exp $
* Authors: David Woodhouse and Avery Pennarun
*
* Author: David Woodhouse <dwmw2@cam.ac.uk>
* Avery Pennarun <apenwarr@bond.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef _LINUX_IF_ARCNET_H
#define _LINUX_IF_ARCNET_H
#include <linux/if_ether.h>
/*
* These are the defined ARCnet Protocol ID's.
* These are the defined ARCnet Protocol ID's.
*/
/* RFC1201 Protocol ID's */
#define ARC_P_IP 212 /* 0xD4 */
#define ARC_P_ARP 213 /* 0xD5 */
#define ARC_P_RARP 214 /* 0xD6 */
#define ARC_P_IPX 250 /* 0xFA */
#define ARC_P_NOVELL_EC 236 /* 0xEC */
/* RFC1201 Protocol ID's */
#define ARC_P_IP 212 /* 0xD4 */
#define ARC_P_ARP 213 /* 0xD5 */
#define ARC_P_RARP 214 /* 0xD6 */
#define ARC_P_IPX 250 /* 0xFA */
#define ARC_P_NOVELL_EC 236 /* 0xEC */
/* Old RFC1051 Protocol ID's */
#define ARC_P_IP_RFC1051 240 /* 0xF0 */
#define ARC_P_ARP_RFC1051 241 /* 0xF1 */
/* Old RFC1051 Protocol ID's */
#define ARC_P_IP_RFC1051 240 /* 0xF0 */
#define ARC_P_ARP_RFC1051 241 /* 0xF1 */
/* MS LanMan/WfWg protocol */
#define ARC_P_ETHER 0xE8
/* MS LanMan/WfWg "NDIS" encapsulation */
#define ARC_P_ETHER 232 /* 0xE8 */
/* Unsupported/indirectly supported protocols */
/* Unsupported/indirectly supported protocols */
#define ARC_P_DATAPOINT_BOOT 0 /* very old Datapoint equipment */
#define ARC_P_DATAPOINT_MOUNT 1
#define ARC_P_POWERLAN_BEACON 8 /* Probably ATA-Netbios related */
#define ARC_P_POWERLAN_BEACON2 243
#define ARC_P_LANSOFT 251 /* 0xFB - what is this? */
#define ARC_P_ATALK 0xDD
#define ARC_P_POWERLAN_BEACON2 243 /* 0xF3 */
#define ARC_P_LANSOFT 251 /* 0xFB - what is this? */
#define ARC_P_ATALK 0xDD
/*
* The RFC1201-specific components of an arcnet packet header.
*/
struct arc_rfc1201
{
uint8_t proto; /* protocol ID field - varies */
uint8_t split_flag; /* for use with split packets */
uint16_t sequence; /* sequence number */
uint8_t payload[0]; /* space remaining in packet (504 bytes)*/
};
#define RFC1201_HDR_SIZE 4
/*
* The RFC1051-specific components.
*/
struct arc_rfc1051
{
uint8_t proto; /* ARC_P_RFC1051_ARP/RFC1051_IP */
uint8_t payload[0]; /* 507 bytes */
};
#define RFC1051_HDR_SIZE 1
/*
* This is an ARCnet frame header.
* The ethernet-encap-specific components. We have a real ethernet header
* and some data.
*/
struct arc_eth_encap
{
uint8_t proto; /* Always ARC_P_ETHER */
struct ethhdr eth; /* standard ethernet header (yuck!) */
uint8_t payload[0]; /* 493 bytes */
};
#define ETH_ENCAP_HDR_SIZE 14
struct archdr /* was struct HardHeader */
/*
* The data needed by the actual arcnet hardware.
*
* Now, in the real arcnet hardware, the third and fourth bytes are the
* 'offset' specification instead of the length, and the soft data is at
* the _end_ of the 512-byte buffer. We hide this complexity inside the
* driver.
*/
struct arc_hardware
{
u_char source, /* source ARCnet - filled in automagically */
destination, /* destination ARCnet - 0 for broadcast */
offset1, /* offset of ClientData (256-byte packets) */
offset2; /* offset of ClientData (512-byte packets) */
uint8_t source, /* source ARCnet - filled in automagically */
dest, /* destination ARCnet - 0 for broadcast */
offset[2]; /* offset bytes (some weird semantics) */
};
#define ARC_HDR_SIZE 4
/*
* This is an ARCnet frame header, as seen by the kernel (and userspace,
* when you do a raw packet capture).
*/
struct archdr
{
/* hardware requirements */
struct arc_hardware hard;
/* arcnet encapsulation-specific bits */
union {
struct arc_rfc1201 rfc1201;
struct arc_rfc1051 rfc1051;
struct arc_eth_encap eth_encap;
uint8_t raw[0]; /* 508 bytes */
} soft;
};
#endif /* _LINUX_IF_ARCNET_H */
#endif /* _LINUX_IF_ARCNET_H */
......@@ -94,8 +94,8 @@ extern struct kernel_param __setup_start, __setup_end;
#define __FINIT
#define __INITDATA
/* Not sure what version aliases were introduced in, but certainly in 2.95. */
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
/* Not sure what version aliases were introduced in, but certainly in 2.91.66. */
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91)
#define module_init(x) int init_module(void) __attribute__((alias(#x)));
#define module_exit(x) void cleanup_module(void) __attribute__((alias(#x)));
#else
......
......@@ -72,6 +72,8 @@ typedef struct socket_state_t {
u_char io_irq;
} socket_state_t;
extern socket_state_t dead_socket;
/* Socket configuration flags */
#define SS_PWR_AUTO 0x0010
#define SS_IOCARD 0x0020
......@@ -118,6 +120,8 @@ typedef struct cb_bridge_map {
* Socket operations.
*/
struct pccard_operations {
int (*init)(unsigned int sock);
int (*suspend)(unsigned int sock);
int (*register_callback)(unsigned int sock, void (*handler)(void *, unsigned int), void * info);
int (*inquire_socket)(unsigned int sock, socket_cap_t *cap);
int (*get_status)(unsigned int sock, u_int *value);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment