patch-1.3.10 linux/drivers/net/arcnet.c
Next file: linux/drivers/net/eql.c
Previous file: linux/drivers/net/README.arcnet-jumpers
Back to the patch index
Back to the overall index
- Lines: 2618
- Date:
Wed Jul 12 07:59:38 1995
- Orig file:
v1.3.9/linux/drivers/net/arcnet.c
- Orig date:
Fri Jul 7 08:54:46 1995
diff -u --recursive --new-file v1.3.9/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
@@ -6,6 +6,8 @@
RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
**********************
+
+ The original copyright was as follows:
skeleton.c Written 1993 by Donald Becker.
Copyright 1993 United States Government as represented by the
@@ -14,102 +16,144 @@
modified by SRC, incorporated herein by reference.
**********************
-
- 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)
- - Updated my email address. Please use apenwarr@foxnet.net
- from now on.
+
+ v1.92 ALPHA (95/07/11)
+ - Fixes to make things work with kernel 1.3.x. Completely broke
+ 1.2.x support. Oops? 1.2.x users keep using 1.91 ALPHA until I
+ get out a version that supports both.
+
+ v1.91 ALPHA (95/07/02)
+ - Oops. Exception packets hit us again! I remembered to test
+ them in Windows-protocol mode, but due to the many various
+ changes they broke in RFC1201 instead. All fixed.
+ - A long-standing bug with "exception" packets not setting
+ protocol_id properly has been corrected. This would have caused
+ random problems talking to non-Linux servers. I've also sent in
+ a patch to fix this in the latest stable ARCnet (now 1.02).
+ - ARC_P_IPX is an RFC1201 protocol too. Thanks, Tomasz.
+ - We're now "properly" (I think) handling the multiple 'tbusy' and
+ 'start' flags (one for each protocol device) better.
+ - The driver should now start without a NULL-pointer dereference
+ if you aren't connected to the network.
+
+ v1.90 ALPHA (95/06/18)
+ - Removal of some outdated and messy config options (no one has
+ ever complained about the defaults since they were introduced):
+ DANGER_PROBE, EXTRA_DELAYS, IRQ_XMIT, CAREFUL_XMIT,
+ STRICT_MEM_DETECT, LIMIT_MTU, USE_TIMER_HANDLER. Also took out
+ a few "#if 0" sections which are no longer useful.
+ - Cleaned up debug levels - now instead of levels, there are
+ individual flags. Watch out when changing with ifconfig.
+ - More cleanups and beautification. Removed more dead code and
+ made sure every function was commented.
+ - Fixed the DETECT_RECONFIGS option so that it actually _won't_
+ detect reconfigs. Previously, the RECON irq would be disabled
+ but the recon messages would still be logged on the next normal
+ IRQ.
+ - Initial support for "multiprotocol" ARCnet (this involved a LOT
+ of reorganizing!). Added an arc0w device, which allows us to
+ talk to "Windows" ARCnet TCP/IP protocol. To use it, ifconfig
+ arc0 and arc0w (in that order). For now, Windows-protocol
+ hosts should have routes through arc0w - eventually I hope to
+ make things more automatic.
+ v1.11 ALPHA (95/06/07)
+ - Tomasz saves the day again with patches to fix operation if the
+ new VERIFY_ACK option is disabled.
+ - LOTS of little code cleanups/improvements by Tomasz.
+ - Changed autoprobe, since the "never-changing command port"
+ probe was causing problems for some people. I also reset the
+ card fewer times during the probe if DANGER_PROBE is defined,
+ since DANGER_PROBE seems to be a more reliable method anyway.
+ - It looks like the null-pointer problem was finally REALLY fixed
+ by some change from Linux 1.2.8 to 1.2.9. How handy!
+ v1.10 ALPHA (95/04/15)
+ - Fixed (?) some null-pointer dereference bugs
+ - Added better network error detection (from Tomasz) - in
+ particular, we now notice when our network isn't connected,
+ also known as a "network reconfiguration."
+ - We now increment lp->stats.tx_dropped in several more places,
+ on a suggestion from Tomasz.
+ - Minor cleanups/spelling fixes.
+ - We now monitor the TXACK bit in the status register: we don't do
+ anything with it yet, just notice when a transmitted packet isn't
+ acknowledged.
+ - Minor fix with sequence numbers (sometimes they were being sent in
+ the wrong order due to Linux's packet queuing).
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.0 (95/02/15)
+ v1.00 (95/02/15)
- Initial non-alpha release.
TO DO:
- Test in systems with NON-ARCnet network cards, just to see if
- autoprobe kills anything. With any luck, it won't. (It's pretty
- careful.)
- - Except some unfriendly NE2000's die. (as of 0.40-ALPHA)
- - cards with shared memory that can be "turned off?"
+ autoprobe kills anything. Currently, we do cause some NE2000's to
+ die.
+ - What about cards with shared memory that can be "turned off?"
- NFS mount freezes after several megabytes to SOSS for DOS.
- unmount/remount works. Is this arcnet-specific? I don't know.
- - Add support for the various stupid bugs ("I didn't read the RFC"
- syndrome) in Windows for Workgroups and LanMan.
- */
-
-/**************************************************************************/
-
-/* define this if you want to use the new but possibly dangerous ioprobe
- * If you get lockups right after status5, you probably need
- * to undefine this. It should make more cards probe correctly,
- * I hope.
- */
-#define DANGER_PROBE
-
-/* define this if you want to use the "extra delays" which were removed
- * in 0.41 since they seemed needless.
- */
-#undef EXTRA_DELAYS
+ unmount/remount fixes it. Is this arcnet-specific? I don't know.
+ - Add support for "old" (RFC1051) protocol arcnet, such as AmiTCP
+ and NetBSD. Work in Tomasz' initial support for this.
+ - How about TCP/IP over netbios?
+ - Some newer ARCnets support promiscuous mode, supposedly.
+ If someone sends me information, I'll try to implement it.
+ - Remove excess lock variables that are probably not necessary
+ anymore due to the changes in Linux 1.2.9.
+
+
+ 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)
+ - The official ARCnet data sheets (!) thanks to Ken Cornetet
+ <kcornete@nyx10.cs.du.edu>
+ - RFC's 1201 and 1051 (mostly 1201) - re: ARCnet IP packets
+ - 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>
+*/
-/* undefine this if you want to use the non-IRQ-driven transmitter. (possibly
- * safer, although it takes more CPU time and IRQ_XMIT seems fine right now)
- */
-#define IRQ_XMIT
+static char *version =
+ "arcnet.c:v1.92 ALPHA 95/07/11 Avery Pennarun <apenwarr@foxnet.net>\n";
-/* define this for "careful" transmitting. Try with and without if you have
- * problems. If you use IRQ_XMIT, do NOT define this.
- */
-#undef CAREFUL_XMIT
+/**************************************************************************/
-/* define this for an extra-careful memory detect. This should work all
- * the time now, but you never know.
+/* Define this if you want to detect network reconfigurations.
+ * They may be a real nuisance on a larger ARCnet network: but 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).
+ *
+ * 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 STRICT_MEM_DETECT
+#define DETECT_RECONFIGS
-/* define this to use the "old-style" limited MTU by default. It basically
- * disables packet splitting. ifconfig can still be used to reset the MTU.
+/* Define this if you want to make sure transmitted packets are "acknowledged"
+ * by the destination host, as long as they're not to the broadcast address.
*
- * leave this disabled if possible, so it will use ethernet defaults,
- * which is our goal.
+ * That way, if one segment of a split packet doesn't get through, it can
+ * be resent immediately rather than confusing the other end.
+ *
+ * Disable this to return to 1.01-style behaviour, if you have problems.
*/
-#undef LIMIT_MTU
+#define VERIFY_ACK
-/* define this if you have a problem with the card getting "stuck" now and
- * then, which can only be fixed by a reboot or resetting the card manually
- * via ifconfig up/down. ARCnet will set a timer function which is called
- * 8 times every second.
- *
- * This should no longer be necessary. if you experience "stuck" ARCnet
- * drivers, please email apenwarr@foxnet.net or I will remove
- * this feature in a future release.
+/* Define this if you want to make it easier to use the "call trace" when
+ * a kernel NULL pointer assignment occurs.
*/
-#undef USE_TIMER_HANDLER
+#undef static
/**************************************************************************/
-static char *version =
- "arcnet.c:v1.02 95/06/21 Avery Pennarun <apenwarr@foxnet.net>\n";
-
-/*
- 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)
- ...I sure wish I had the ARCnet data sheets right about now!
- RFC's 1201 and 1051 (mostly 1201) - re: ARCnet IP packets
- 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>
-*/
#include <linux/config.h>
#ifdef MODULE
@@ -139,31 +183,31 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+
#include <net/arp.h>
-/* debug levels:
- * D_OFF production
- * D_NORMAL verification
- * D_INIT show init/detect messages
- * D_DURING show messages during normal use (ie interrupts)
- * D_DATA show packets data from skb's, not on Arcnet card
- * D_TX show tx packets
- * D_RX show tx+rx packets
- */
-#define D_OFF 0
-#define D_NORMAL 1
-#define D_INIT 2
-#define D_EXTRA 3
-#define D_DURING 4
-#define D_DATA 6
-#define D_TX 8
-#define D_RX 9
+/* 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 1xx is 1000 + the debug level you want
+ * and HOSTNAME is your hostname/ip address
+ * and then resetting your routes.
+ */
+#define D_NORMAL 1 /* D_NORMAL startup announcement */
+#define D_INIT 2 /* D_INIT show init/probe messages */
+#define D_EXTRA 4 /* D_EXTRA extra information */
+/* debug levels past this point give LOTS of output! */
+#define D_DURING 8 /* D_DURING during normal use (irq's) */
+#define D_TX 16 /* D_TX show tx packets */
+#define D_RX 32 /* D_RX show rx packets */
+#define D_SKB 64 /* D_SKB dump skb's */
#ifndef NET_DEBUG
-#define NET_DEBUG D_INIT
+#define NET_DEBUG D_NORMAL|D_INIT|D_EXTRA
#endif
-static unsigned int net_debug = NET_DEBUG;
+int arcnet_debug = NET_DEBUG;
#ifndef HAVE_AUTOIRQ
/* From auto_irq.c, in ioport.h for later versions. */
@@ -180,10 +224,20 @@
#endif
/* macro to simplify debug checking */
-#define BUGLVL(x) if (net_debug>=x)
+#define BUGLVL(x) if (arcnet_debug&(x))
+
+
+/* Some useful multiprotocol macros */
+#define TBUSY lp->adev->tbusy \
+ =lp->wdev->tbusy
+#define IF_TBUSY (lp->adev->tbusy \
+ || lp->wdev->tbusy)
+#define START lp->adev->start \
+ =lp->wdev->start
+
/* The number of low I/O ports used by the ethercard. */
-#define ETHERCARD_TOTAL_SIZE 16
+#define ARCNET_TOTAL_SIZE 16
/* Handy defines for ARCnet specific stuff */
@@ -193,7 +247,8 @@
#define COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define RESET (ioaddr+8) /* software reset writable */
- /* time needed for various things (in clock ticks, 1/100 sec) */
+ /* Time needed for various things (in clock ticks, 1/100 sec) */
+ /* We mostly don't bother with these - watch out. */
#define RESETtime 40 /* reset */
#define XMITtime 10 /* send (?) */
#define ACKtime 10 /* acknowledge (?) */
@@ -206,66 +261,73 @@
* These numbers are compared with the length of the full packet,
* including ClientData header.
*/
-#define MTU (253+EXTRA_CLIENTDATA) /* normal packet max size */
-#define MinTU (257+EXTRA_CLIENTDATA) /* extended packet min size */
-#define XMTU (508+EXTRA_CLIENTDATA) /* extended packet max size */
+#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 0x001 /* transmitter available */
-#define TXACKflag 0x002 /* transmitted msg. ackd */
-#define RECONflag 0x004 /* system reconfigured */
-#define TESTflag 0x008 /* test flag */
-#define RESETflag 0x010 /* power-on-reset */
-#define RES1flag 0x020 /* unused */
-#define RES2flag 0x040 /* unused */
-#define NORXflag 0x080 /* receiver inhibited */
+#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 /* unused */
+#define RES2flag 0x40 /* unused */
+#define NORXflag 0x80 /* receiver inhibited */
+
+#ifdef DETECT_RECONFIGS
+ #define RECON_flag RECONflag
+#else
+ #define RECON_flag 0
+#endif
/* 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 0x001 /* disable transmitter */
-#define NORXcmd 0x002 /* disable receiver */
-#define TXcmd 0x003 /* enable transmitter */
-#define RXcmd 0x004 /* enable receiver */
-#define CONFIGcmd 0x005 /* define configuration */
-#define CFLAGScmd 0x006 /* clear flags */
-#define TESTcmd 0x007 /* load test flags */
+#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 0x008 /* power-on-reset */
-#define CONFIGclear 0x010 /* system reconfigured */
+#define RESETclear 0x08 /* power-on-reset */
+#define CONFIGclear 0x10 /* system reconfigured */
/* flags for "load test flags" command */
-#define TESTload 0x008 /* test flag (diagnostic) */
+#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 0x080 /* receive broadcasts */
+#define RXbcasts 0x80 /* receive broadcasts */
/* flags for "define configuration" command */
-#define NORMALconf 0x000 /* 1-249 byte packets */
-#define EXTconf 0x008 /* 250-504 byte packets */
+#define NORMALconf 0x00 /* 1-249 byte packets */
+#define EXTconf 0x08 /* 250-504 byte packets */
/* buffers (4 total) used for receive and xmit.
*/
#define EnableReceiver() outb(RXcmd|(recbuf<<3)|RXbcasts,COMMAND)
-/*#define TXbuf 2 (Obsoleted by ping-pong xmits) */
- /* 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 */
+
+ /* MS LanMan/WfWg protocol */
+#define ARC_P_MS_TCPIP 0xE8
+
+ /* Unsupported/indirectly supported protocols */
#define ARC_P_LANSOFT 251 /* 0xFB */
#define ARC_P_ATALK 0xDD
- /* Length of time between "stuck" checks */
-#define TIMERval (HZ/8) /* about 1/8 second */
-
/* these structures define the format of an arcnet packet. */
#define NORMAL 0
#define EXTENDED 1
@@ -293,17 +355,16 @@
*/
struct ClientData
{
- /* data that's NOT part of real packet */
- u_char daddr; /* Destination address - stored here,
- * but WE MUST GET RID OF IT BEFORE SENDING A
- * PACKET!!
- */
- u_char saddr; /* Source address - necessary for IPX protocol */
+ /* 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, or ARC_P_RARP */
+ u_char protocol_id, /* ARC_P_IP, ARC_P_ARP, etc */
split_flag; /* for use with split packets */
- u_short sequence; /* sequence number (?) */
+ u_short sequence; /* sequence number */
};
#define EXTRA_CLIENTDATA (sizeof(struct ClientData)-4)
@@ -329,6 +390,11 @@
segnum, /* segment being sent */
numsegs, /* number of segments */
seglen; /* length of segment */
+#ifdef VERIFY_ACK
+ short lastload_dest, /* can last loaded packet be acked? */
+ lasttrans_dest; /* can last TX'd packet be acked? */
+#endif
+
};
@@ -344,9 +410,13 @@
in_txhandler, /* in TX_IRQ handler? */
sending; /* transmit in progress? */
short tx_left; /* segments of split packet left to TX */
+
struct timer_list timer; /* the timer interrupt struct */
struct Incoming incoming[256]; /* one from each address */
struct Outgoing outgoing; /* packet currently being sent */
+
+ struct device *adev; /* RFC1201 protocol device */
+ struct device *wdev; /* Windows protocol device */
};
@@ -356,40 +426,38 @@
static int arcnet_memprobe(struct device *dev,u_char *addr);
static int arcnet_ioprobe(struct device *dev, short ioaddr);
#endif
+static int arcnetW_init(struct device *dev);
static int arcnet_open(struct device *dev);
static int arcnet_close(struct device *dev);
+static int arcnet_reset(struct device *dev);
-static int arcnet_send_packet(struct sk_buff *skb, struct device *dev);
-#ifdef CAREFUL_XMIT
- static void careful_xmit_wait(struct device *dev);
-#else
- #define careful_xmit_wait(dev)
-#endif
-static void arcnet_continue_tx(struct device *dev);
-static void arcnet_prepare_tx(struct device *dev,struct ClientData *hdr,
+static int arcnetA_send_packet(struct sk_buff *skb, struct device *dev);
+static void arcnetA_continue_tx(struct device *dev);
+static void arcnetA_prepare_tx(struct device *dev,struct ClientData *hdr,
short length,char *data);
-static void arcnet_go_tx(struct device *dev);
+static void arcnetA_go_tx(struct device *dev);
+
+static int arcnetW_send_packet(struct sk_buff *skb, struct device *dev);
static void arcnet_interrupt(int irq,struct pt_regs *regs);
static void arcnet_inthandler(struct device *dev);
-static void arcnet_rx(struct device *dev,int recbuf);
-#ifdef USE_TIMER_HANDLER
-static void arcnet_timer(unsigned long arg);
-#endif
+static void arcnet_rx(struct device *dev,int recbuf);
+static void arcnetA_rx(struct device *dev,struct ClientData *arcsoft,
+ int length,u_char saddr, u_char daddr);
+static void arcnetW_rx(struct device *dev,u_char *arcsoft,
+ int length,u_char saddr, u_char daddr);
static struct enet_statistics *arcnet_get_stats(struct device *dev);
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
/* annoying functions for header/arp/etc building */
-int arc_header(struct sk_buff *skb,struct device *dev,unsigned short type,
+int arcnetA_header(struct sk_buff *skb,struct device *dev,unsigned short type,
void *daddr,void *saddr,unsigned len);
-int arc_rebuild_header(void *eth,struct device *dev,unsigned long raddr,
+int arcnetA_rebuild_header(void *eth,struct device *dev,unsigned long raddr,
struct sk_buff *skb);
-unsigned short arc_type_trans(struct sk_buff *skb,struct device *dev);
-
-static int arcnet_reset(struct device *dev);
+unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev);
#ifdef MODULE
int init_module(void);
@@ -398,19 +466,17 @@
#define tx_done(dev) 1
-/*
-#define JIFFER(time) for (delayval=jiffies+(time); delayval>jiffies;);
-*/
#define JIFFER(time) for (delayval=0; delayval<(time*10); delayval++) \
udelay(1000);
+
-#ifdef EXTRA_DELAYS
- #define XJIFFER(time) JIFFER(time)
-#else
- #define XJIFFER(time)
-#endif
+/****************************************************************************
+ * *
+ * Probe and initialization *
+ * *
+ ****************************************************************************/
+
-
/* Check for a network adaptor of this type, and return '0' if one exists.
* If dev->base_addr == 0, probe all likely locations.
* If dev->base_addr == 1, always return failure.
@@ -450,14 +516,14 @@
int delayval;
struct arcnet_local *lp;
- if (net_debug)
+ BUGLVL(D_NORMAL)
{
printk(version);
printk("arcnet: ***\n");
printk("arcnet: * Read linux/drivers/net/README.arcnet for important release notes!\n");
printk("arcnet: *\n");
- printk("arcnet: * This version should be stable, but e-mail me if you have any\n");
- printk("arcnet: * questions, comments, or bug reports!\n");
+ printk("arcnet: * This is an ALPHA version! (Last stable release: v1.02) E-mail me if\n");
+ printk("arcnet: * you have any questions, comments, or bug reports.\n");
printk("arcnet: ***\n");
}
@@ -473,7 +539,7 @@
else for (port = &ports[0]; *port; port++)
{
int ioaddr = *port;
- if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE))
+ if (check_region(ioaddr, ARCNET_TOTAL_SIZE))
{
BUGLVL(D_INIT)
printk("arcnet: Skipping %Xh because of check_region...\n",
@@ -534,7 +600,7 @@
}
/* Grab the region so we can find another board if autoIRQ fails. */
- request_region(dev->base_addr, ETHERCARD_TOTAL_SIZE,"arcnet");
+ request_region(dev->base_addr, ARCNET_TOTAL_SIZE,"arcnet");
printk("%s: ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n",
dev->name, dev->base_addr, dev->irq, dev->mem_start);
@@ -544,27 +610,26 @@
memset(dev->priv, 0, sizeof(struct arcnet_local));
lp=(struct arcnet_local *)(dev->priv);
- dev->open = arcnet_open;
- dev->stop = arcnet_close;
- dev->hard_start_xmit = arcnet_send_packet;
- dev->get_stats = arcnet_get_stats;
+ dev->open=arcnet_open;
+ dev->stop=arcnet_close;
+ dev->hard_start_xmit=arcnetA_send_packet;
+ dev->get_stats=arcnet_get_stats;
#ifdef HAVE_MULTICAST
dev->set_multicast_list = &set_multicast_list;
#endif
- /* Fill in the fields of the device structure with ethernet-generic values. */
+ /* Fill in the fields of the device structure with ethernet-generic
+ * values.
+ */
ether_setup(dev);
-
- /* And now fill particular ones with arcnet values :) */
+ /* And now fill particular fields with arcnet values */
dev->type=ARPHRD_ARCNET;
dev->hard_header_len=sizeof(struct ClientData);
- BUGLVL(D_EXTRA)
+ BUGLVL(D_DURING)
printk("arcnet: ClientData header size is %d.\narcnet: HardHeader size is %d.\n",
sizeof(struct ClientData),sizeof(struct HardHeader));
-#if LIMIT_MTU /* the old way - normally, now use ethernet default */
- dev->mtu=512-sizeof(struct HardHeader)+EXTRA_CLIENTDATA;
-#endif
+
/* since we strip EXTRA_CLIENTDATA bytes off before sending,
* we let Linux add that many bytes to the packet data...
*/
@@ -585,8 +650,8 @@
lp->sequence=1;
lp->recbuf=0;
- dev->hard_header = arc_header;
- dev->rebuild_header = arc_rebuild_header;
+ dev->hard_header=arcnetA_header;
+ dev->rebuild_header=arcnetA_rebuild_header;
return 0;
}
@@ -598,10 +663,10 @@
int delayval,airq;
BUGLVL(D_INIT)
+ {
printk("arcnet: probing address %Xh\n",ioaddr);
-
- BUGLVL(D_INIT)
printk("arcnet: status1=%Xh\n",inb(STATUS));
+ }
/* very simple - all we have to do is reset the card, and if there's
@@ -621,6 +686,7 @@
return ENODEV;
}
+#if 0
/* we'll try to be reasonably sure it's an arcnet by making sure
* the value of the COMMAND port changes automatically once in a
* while. I have no idea what those values ARE, but at least
@@ -641,13 +707,13 @@
return ENODEV;
}
}
+#endif
BUGLVL(D_INIT)
printk("arcnet: status2=%Xh\n",inb(STATUS));
/* now we turn the reset bit off so we can IRQ next reset... */
outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
- XJIFFER(ACKtime);
if (inb(STATUS) & RESETflag) /* reset flag STILL on */
{
BUGLVL(D_INIT)
@@ -659,32 +725,6 @@
/* set up automatic IRQ detection */
autoirq_setup(0);
- /* enable reset IRQ's (shouldn't be necessary, but worth a try) */
- outb(RESETflag,INTMASK);
-
- /* now reset it again to generate an IRQ */
- inb(RESET);
- JIFFER(RESETtime);
-
- BUGLVL(D_INIT)
- printk("arcnet: status3=%Xh\n",inb(STATUS));
-
- /* and turn the reset flag back off */
- outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
- XJIFFER(ACKtime);
-
- BUGLVL(D_INIT)
- printk("arcnet: status4=%Xh\n",inb(STATUS));
-
- /* enable reset IRQ's again */
- outb(RESETflag,INTMASK);
-
- /* now reset it again to generate an IRQ */
- inb(RESET);
- JIFFER(RESETtime);
-
- BUGLVL(D_INIT)
- printk("arcnet: status5=%Xh\n",inb(STATUS));
/* 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
@@ -693,18 +733,15 @@
* However, this could, theoretically, cause a lockup. Maybe I'm just
* not very good at theory! :)
*/
-#ifdef DANGER_PROBE
outb(NORXflag,INTMASK);
JIFFER(RESETtime);
outb(0,INTMASK);
-#endif
/* and turn the reset flag back off */
outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
- XJIFFER(ACKtime);
airq = autoirq_report(0);
- if (net_debug>=D_INIT && airq)
+ BUGLVL(D_INIT) if (airq)
printk("arcnet: autoirq is %d\n", airq);
/* if there was no autoirq AND the user hasn't set any defaults,
@@ -723,7 +760,6 @@
{
/* now we turn the reset bit off */
outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
- XJIFFER(ACKtime);
}
if (inb(STATUS) & RESETflag) /* reset flag STILL on */
@@ -744,7 +780,7 @@
}
else if (dev->irq == 2)
{
- if (net_debug)
+ BUGLVL(D_NORMAL)
printk("arcnet: IRQ2 == IRQ9, don't worry.\n");
dev->irq = 9;
}
@@ -758,7 +794,7 @@
/* A memory probe that is called after the card is reset.
* It checks for the official TESTvalue in byte 0 and makes sure the buffer
- * has certain characteristics of an ARCnet...
+ * has certain characteristics of an ARCnet.
*/
int arcnet_memprobe(struct device *dev,u_char *addr)
{
@@ -767,7 +803,6 @@
dev->mem_start=0;
-#ifdef STRICT_MEM_DETECT /* probably better. */
/* ARCnet memory byte 0 is TESTvalue */
if (addr[0]!=TESTvalue)
{
@@ -786,15 +821,6 @@
(unsigned long)addr,addr[0]);
return ENODEV;
}
-#else
- if (addr[0]!=TESTvalue)
- {
- BUGLVL(D_INIT)
- printk("arcnet: probe failed. addr=%lXh, addr[0]=%Xh (not %Xh)\n",
- (unsigned long)addr,addr[0],TESTvalue);
- return ENODEV;
- }
-#endif
/* got it! fill in dev */
dev->mem_start=(unsigned long)addr;
@@ -807,64 +833,136 @@
#endif /* MODULE */
-
-/* Open/initialize the board. This is called (in the current kernel)
- sometime after booting when the 'ifconfig' program is run.
- This routine should set everything up anew at each open, even
- registers that "should" only need to be set once at boot, so that
- there is non-reboot way to recover if something goes wrong.
- */
+int arcnet_reset(struct device *dev)
+{
+ struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
+ short ioaddr=dev->base_addr;
+ int delayval,recbuf=lp->recbuf;
+ u_char *cardmem;
+
+ outb(0,INTMASK); /* no IRQ's, please! */
+
+ BUGLVL(D_INIT)
+ printk("arcnet: Resetting %s (status=%Xh)\n",
+ dev->name,inb(STATUS));
+
+ inb(RESET); /* Reset by reading this port */
+ JIFFER(RESETtime);
+
+ outb(CFLAGScmd|RESETclear, COMMAND); /* clear flags & end reset */
+ outb(CFLAGScmd|CONFIGclear,COMMAND);
+
+ /* after a reset, the first byte of shared mem is TESTvalue and the
+ * second byte is our 8-bit ARCnet address.
+ */
+ cardmem = (u_char *) dev->mem_start;
+ if (cardmem[0] != TESTvalue)
+ {
+ BUGLVL(D_INIT)
+ printk("arcnet: reset failed: TESTvalue not present.\n");
+ return 1;
+ }
+ lp->arcnum=cardmem[1]; /* save address for later use */
+
+ /* clear out status variables */
+ recbuf=lp->recbuf=0;
+ lp->txbuf=2;
+
+ /* enable extended (512-byte) packets */
+ outb(CONFIGcmd|EXTconf,COMMAND);
+
+ /* clean out all the memory to make debugging make more sense :) */
+ BUGLVL(D_DURING)
+ memset((void *)dev->mem_start,0x42,2048);
+
+ /* and enable receive of our first packet to the first buffer */
+ EnableReceiver();
+
+ /* re-enable interrupts */
+ outb(NORXflag|RECON_flag,INTMASK);
+
+ /* done! return success. */
+ return 0;
+}
+
+static int arcnetW_init(struct device *dev)
+{
+ struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+
+ ether_setup(lp->wdev);
+ dev->dev_addr[0]=0;
+ dev->dev_addr[5]=lp->arcnum;
+ dev->mtu=493; /* MTU is small because of missing packet splitting */
+ lp->wdev->open=NULL;
+ lp->wdev->stop=NULL;
+ lp->wdev->hard_start_xmit=arcnetW_send_packet;
+
+ BUGLVL(D_EXTRA)
+ printk("%s: ARCnet \"Windows\" protocol initialized.\n",
+ lp->wdev->name);
+
+ return 0;
+}
+
+
+/****************************************************************************
+ * *
+ * 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 device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-/* int ioaddr = dev->base_addr;*/
- if (dev->metric>=10)
+ if (dev->metric>=1000)
{
- net_debug=dev->metric-10;
+ arcnet_debug=dev->metric-1000;
+ printk("arcnet: debug level set to %d\n",arcnet_debug);
dev->metric=1;
}
- if (net_debug) printk(version);
-
-#if 0 /* Yup, they're hardwired in arcnets */
- /* This is used if the interrupt line can turned off (shared).
- See 3c503.c for an example of selecting the IRQ at config-time. */
- if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet")) {
- return -EAGAIN;
- }
-#endif
+ BUGLVL(D_NORMAL) printk(version);
irq2dev_map[dev->irq] = dev;
- /* Reset the hardware here. */
BUGLVL(D_EXTRA) printk("arcnet: arcnet_open: resetting card.\n");
/* try to reset - twice if it fails the first time */
if (arcnet_reset(dev) && arcnet_reset(dev))
return -ENODEV;
-/* chipset_init(dev, 1);*/
-/* outb(0x00, ioaddr);*/
-
-/* lp->open_time = jiffies;*/
-
dev->tbusy=0;
dev->interrupt=0;
- dev->start=1;
lp->intx=0;
lp->in_txhandler=0;
+
+ /* The RFC1201 driver is the default - just store */
+ lp->adev=dev;
+ BUGLVL(D_EXTRA)
+ printk("%s: ARCnet RFC1201 protocol initialized.\n",
+ lp->adev->name);
+
+ /* Initialize the Windows protocol driver */
+ lp->wdev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
+ memcpy(lp->wdev,dev,sizeof(struct device));
+ lp->wdev->name=(char *)kmalloc(10,GFP_KERNEL);
+ sprintf(lp->wdev->name,"%sw",dev->name);
+ lp->wdev->init=arcnetW_init;
+ register_netdev(lp->wdev);
-#ifdef USE_TIMER_HANDLER
- /* grab a timer handler to recover from any missed IRQ's */
- init_timer(&lp->timer);
- lp->timer.expires = TIMERval; /* length of time */
- lp->timer.data = (unsigned long)dev; /* pointer to "dev" structure */
- lp->timer.function = &arcnet_timer; /* timer handler */
- add_timer(&lp->timer);
-#endif
+ /* we're started */
+ START=1;
#ifdef MODULE
MOD_INC_USE_COUNT;
@@ -874,32 +972,33 @@
}
-/* The inverse routine to arcnet_open(). */
+/* The inverse routine to arcnet_open - shuts down the card.
+ */
static int
arcnet_close(struct device *dev)
{
- struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr = dev->base_addr;
-#ifdef EXTRA_DELAYS
- int delayval;
-#endif
-
-/* lp->open_time = 0;*/
+ struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
- dev->tbusy = 1;
- dev->start = 0;
+ TBUSY=1;
+ START=0;
- /* release the timer */
- del_timer(&lp->timer);
-
/* Flush the Tx and disable Rx here. */
- /* resetting the card should do the job. */
- /*inb(RESET);*/
outb(0,INTMASK); /* no IRQ's */
outb(NOTXcmd,COMMAND); /* disable transmit */
- XJIFFER(ACKtime);
outb(NORXcmd,COMMAND); /* disable receive */
+
+ /* do NOT free lp->adev!! It's static! */
+ lp->adev=NULL;
+
+ /* free the Windows protocol device */
+ lp->wdev->start=0;
+ lp->wdev->priv=NULL;
+ unregister_netdev(lp->wdev);
+ kfree(lp->wdev->name);
+ kfree(lp->wdev);
+ lp->wdev=NULL;
/* Update the statistics here. */
@@ -911,20 +1010,36 @@
}
+
+/****************************************************************************
+ * *
+ * Transmitter routines *
+ * *
+ ****************************************************************************/
+
+
+/* Called by the kernel in order to transmit a packet.
+ */
static int
-arcnet_send_packet(struct sk_buff *skb, struct device *dev)
+arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr;
-/* short daddr;*/
lp->intx++;
-
+
BUGLVL(D_DURING)
printk("arcnet: transmit requested (status=%Xh, inTX=%d)\n",
inb(STATUS),lp->intx);
+
+ if (lp->in_txhandler)
+ {
+ printk("arcnet: send_packet called while in txhandler!\n");
+ lp->intx--;
+ return 1;
+ }
- if (dev->tbusy || lp->in_txhandler)
+ if (IF_TBUSY)
{
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
@@ -932,18 +1047,6 @@
int recbuf=lp->recbuf;
int status=inb(STATUS);
- /* resume any stopped tx's */
-#if 0
- if (lp->txready && (inb(STATUS)&TXFREEflag))
- {
- printk("arcnet: kickme: starting a TX (status=%Xh)\n",
- inb(STATUS));
- arcnet_go_tx(dev);
- lp->intx--;
- return 1;
- }
-#endif
-
if (tickssofar < 5)
{
BUGLVL(D_DURING)
@@ -955,27 +1058,36 @@
return 1;
}
- BUGLVL(D_INIT)
- printk("arcnet: transmit timed out (status=%Xh, inTX=%d, tickssofar=%d)\n",
- status,lp->intx,tickssofar);
+ BUGLVL(D_EXTRA)
+ printk("arcnet: transmit timed out (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
+ status,lp->intx,lp->in_txhandler,tickssofar);
+
+ lp->stats.tx_errors++;
/* Try to restart the adaptor. */
/*arcnet_reset(dev);*/
+ outb(0,INTMASK);
if (status&NORXflag) EnableReceiver();
if (!(status&TXFREEflag)) outb(NOTXcmd,COMMAND);
dev->trans_start = jiffies;
if (lp->outgoing.skb)
+ {
dev_kfree_skb(lp->outgoing.skb,FREE_WRITE);
+ lp->stats.tx_dropped++;
+ }
lp->outgoing.skb=NULL;
- dev->tbusy=0;
- mark_bh(NET_BH);
- lp->intx=0;
- lp->in_txhandler=0;
+ TBUSY=0;
+ lp->intx--;
+ /*lp->intx=0;*/
+ /*lp->in_txhandler=0;*/
lp->txready=0;
lp->sending=0;
+ mark_bh(NET_BH);
+
+ outb(NORXflag|RECON_flag,INTMASK);
return 1;
}
@@ -984,7 +1096,7 @@
we are passed NULL. Caution: dev_tint() handles the cli()/sti()
itself. */
if (skb == NULL) {
- BUGLVL(D_INIT)
+ BUGLVL(D_NORMAL)
printk("arcnet: tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
inb(STATUS),lp->intx,jiffies-dev->trans_start);
dev_tint(dev);
@@ -994,9 +1106,16 @@
if (lp->txready) /* transmit already in progress! */
{
- printk("arcnet: trying to start new packet while busy!\n");
- printk("arcnet: marking as not ready.\n");
- lp->txready=0;
+ printk("arcnet: trying to start new packet while busy! (status=%Xh)\n",
+ inb(STATUS));
+ /*printk("arcnet: marking as not ready.\n");*/
+ outb(0,INTMASK);
+ outb(NOTXcmd,COMMAND); /* abort current send */
+ arcnet_inthandler(dev); /* fake an interrupt */
+ lp->stats.tx_errors++;
+ lp->intx--;
+ lp->txready=0; /* we definitely need this line! */
+
return 1;
}
@@ -1011,10 +1130,15 @@
}
else {
struct Outgoing *out=&(lp->outgoing);
- out->length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+
+ TBUSY=1;
+
+ out->length = 1 < skb->len ? skb->len : 1;
out->hdr=(struct ClientData*)skb->data;
out->skb=skb;
- BUGLVL( D_DATA ) {
+
+ BUGLVL(D_SKB)
+ {
short i;
for( i=0; i< skb->len; i++)
{
@@ -1024,25 +1148,25 @@
printk("\n");
}
-#ifdef IRQ_XMIT
- if (lp->txready && inb(STATUS)&TXFREEflag)
- arcnet_go_tx(dev);
-#endif
+ out->hdr->sequence=(lp->sequence++);
+ if (lp->txready && inb(STATUS)&TXFREEflag)
+ arcnetA_go_tx(dev);
- if (out->length<=XMTU) /* fits in one packet? */
+ /* fits in one packet? */
+ if (out->length-EXTRA_CLIENTDATA<=XMTU)
{
- BUGLVL(D_TX) printk("arcnet: not splitting %d-byte packet. (split_flag=%d)\n",
+ BUGLVL(D_DURING)
+ printk("arcnet: not splitting %d-byte packet. (split_flag=%d)\n",
out->length,out->hdr->split_flag);
- BUGLVL(D_INIT) if (out->hdr->split_flag)
+ BUGLVL(D_EXTRA) if (out->hdr->split_flag)
printk("arcnet: short packet has split_flag set?! (split_flag=%d)\n",
out->hdr->split_flag);
out->numsegs=1;
out->segnum=1;
- arcnet_prepare_tx(dev,out->hdr,
+ arcnetA_prepare_tx(dev,out->hdr,
out->length-sizeof(struct ClientData),
((char *)skb->data)+sizeof(struct ClientData));
- careful_xmit_wait(dev);
/* done right away */
dev_kfree_skb(out->skb,FREE_WRITE);
@@ -1050,16 +1174,16 @@
if (!lp->sending)
{
- arcnet_go_tx(dev);
+ arcnetA_go_tx(dev);
/* inform upper layers */
- dev->tbusy=0;
+ TBUSY=0;
mark_bh(NET_BH);
}
}
else /* too big for one - split it */
{
- int maxsegsize=XMTU-sizeof(struct ClientData);
+ int maxsegsize=XMTU-4;
out->data=(u_char *)skb->data
+ sizeof(struct ClientData);
@@ -1071,23 +1195,22 @@
BUGLVL(D_TX) printk("arcnet: packet (%d bytes) split into %d fragments:\n",
out->length,out->numsegs);
-#ifdef IRQ_XMIT
/* if a packet waiting, launch it */
if (lp->txready && inb(STATUS)&TXFREEflag)
- arcnet_go_tx(dev);
+ arcnetA_go_tx(dev);
if (!lp->txready)
{
/* prepare a packet, launch it and prepare
* another.
*/
- arcnet_continue_tx(dev);
+ arcnetA_continue_tx(dev);
if (!lp->sending)
{
- arcnet_go_tx(dev);
- arcnet_continue_tx(dev);
+ arcnetA_go_tx(dev);
+ arcnetA_continue_tx(dev);
if (!lp->sending)
- arcnet_go_tx(dev);
+ arcnetA_go_tx(dev);
}
}
@@ -1101,29 +1224,7 @@
if (out->skb)
dev_kfree_skb(out->skb,FREE_WRITE);
out->skb=NULL;
-#if 0
- /* inform upper layers */
- dev->tbusy=0;
- mark_bh(NET_BH);
-#endif
- }
-
-#else /* non-irq xmit */
- while (out->segnum<out->numsegs)
- {
- arcnet_continue_tx(dev);
- careful_xmit_wait(dev);
- arcnet_go_tx(dev);
- dev->trans_start=jiffies;
}
-
- dev_kfree_skb(out->skb,FREE_WRITE);
- out->skb=NULL;
-
- /* inform upper layers */
- dev->tbusy = 0;
- mark_bh(NET_BH);
-#endif
}
}
@@ -1133,10 +1234,15 @@
return 0;
}
-static void arcnet_continue_tx(struct device *dev)
+/* After an RFC1201 split packet has been set up, this function calls
+ * arcnetA_prepare_tx to load the next segment into the card. This function
+ * does NOT automatically call arcnetA_go_tx to allow for easier double-
+ * buffering.
+ */
+static void arcnetA_continue_tx(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
- int maxsegsize=XMTU-sizeof(struct ClientData);
+ int maxsegsize=XMTU-4;
struct Outgoing *out=&(lp->outgoing);
if (lp->txready)
@@ -1163,43 +1269,21 @@
out->segnum+1,out->seglen,out->numsegs,
out->length,out->hdr->split_flag);
- arcnet_prepare_tx(dev,out->hdr,out->seglen,out->data);
+ arcnetA_prepare_tx(dev,out->hdr,out->seglen,out->data);
out->dataleft-=out->seglen;
out->data+=out->seglen;
out->segnum++;
}
-#ifdef CAREFUL_XMIT
-static void careful_xmit_wait(struct device *dev)
-{
- int ioaddr=dev->base_addr;
- struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
- /* wait patiently for tx to become available again */
- while ( !(inb(STATUS)&TXFREEflag) )
- {
- if (jiffies-dev->trans_start > 20 || !dev->tbusy)
- {
- BUGLVL(D_INIT)
- printk("arcnet: CAREFUL_XMIT timeout. (busy=%d, status=%Xh)\n",
- dev->tbusy,inb(STATUS));
- lp->stats.tx_errors++;
-
- outb(NOTXcmd,COMMAND);
- return;
- }
- }
- BUGLVL(D_TX) printk("arcnet: transmit completed successfully. (status=%Xh)\n",
- inb(STATUS));
-}
-#endif
+/* Given an skb, copy a packet into the ARCnet buffers for later transmission
+ * by arcnetA_go_tx.
+ */
static void
-arcnet_prepare_tx(struct device *dev,struct ClientData *hdr,short length,
+arcnetA_prepare_tx(struct device *dev,struct ClientData *hdr,short length,
char *data)
{
-/* int ioaddr = dev->base_addr;*/
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct ClientData *arcsoft;
union ArcPacket *arcpacket =
@@ -1210,10 +1294,10 @@
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
- length+=sizeof(struct ClientData);
+ length+=4;
BUGLVL(D_TX)
- printk("arcnet: arcnet_prep_tx: hdr:%ph, length:%d, data:%ph\n",
+ printk("arcnet: arcnetA_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr,length,data);
/* clean out the page to make debugging make more sense :) */
@@ -1227,8 +1311,7 @@
{
pkttype=NORMAL;
- arcpacket->hardheader.offset1=offset=256-length
- + EXTRA_CLIENTDATA;
+ arcpacket->hardheader.offset1=offset=256-length;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset-EXTRA_CLIENTDATA]);
}
@@ -1237,8 +1320,7 @@
pkttype=EXTENDED;
arcpacket->hardheader.offset1=0;
- arcpacket->hardheader.offset2=offset=512-length
- + EXTRA_CLIENTDATA;
+ arcpacket->hardheader.offset2=offset=512-length;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset-EXTRA_CLIENTDATA]);
}
@@ -1247,8 +1329,7 @@
pkttype=EXCEPTION;
arcpacket->hardheader.offset1=0;
- arcpacket->hardheader.offset2=offset=512-length-4
- + EXTRA_CLIENTDATA;
+ arcpacket->hardheader.offset2=offset=512-length-4;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset+4-EXTRA_CLIENTDATA]);
@@ -1267,11 +1348,9 @@
* - the first bytes of ClientData header are skipped
*/
memcpy((u_char*)arcsoft+EXTRA_CLIENTDATA,
- (u_char*)hdr+EXTRA_CLIENTDATA,
- sizeof(struct ClientData)-EXTRA_CLIENTDATA);
+ (u_char*)hdr+EXTRA_CLIENTDATA,4);
memcpy((u_char*)arcsoft+sizeof(struct ClientData),
- data,
- length-sizeof(struct ClientData));
+ data,length-4);
BUGLVL(D_DURING) printk("arcnet: transmitting packet to station %02Xh (%d bytes, type=%d)\n",
daddr,length,pkttype);
@@ -1292,35 +1371,18 @@
printk("\n");
}
-#ifdef CAREFUL_XMIT
- #if 0
- careful_xmit_wait(dev);
-
- /* if we're not broadcasting, make sure the xmit was ack'd.
- * if it wasn't, there is probably no card with that
- * address... or else it missed our tx somehow.
- */
- if (daddr && !(inb(STATUS)&TXACKflag))
- {
- BUGLVL(D_INIT)
- printk("arcnet: transmit not acknowledged. (status=%Xh, daddr=%02Xh)\n",
- inb(STATUS),daddr);
- lp->stats.tx_errors++;
- return -ENONET; /* "machine is not on the network" */
- }
- #endif
-#endif
- lp->txready=lp->txbuf; /* packet is ready for sending */
-#if 0
-#ifdef IRQ_XMIT
- if (inb(STATUS)&TXFREEflag) arcnet_go_tx(dev);
-#endif
+#ifdef VERIFY_ACK
+ lp->outgoing.lastload_dest=hdr->daddr;
#endif
+ lp->txready=lp->txbuf; /* packet is ready for sending */
}
+/* Actually start transmitting a packet that was placed in the card's
+ * buffer by arcnetA_prepare_tx.
+ */
static void
-arcnet_go_tx(struct device *dev)
+arcnetA_go_tx(struct device *dev)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr;
@@ -1334,47 +1396,203 @@
/* start sending */
outb(TXcmd|(lp->txready<<3),COMMAND);
-#ifdef IRQ_XMIT
- outb(TXFREEflag|NORXflag,INTMASK);
-#endif
+ outb(TXFREEflag|NORXflag|RECON_flag,INTMASK);
dev->trans_start = jiffies;
lp->txready=0;
lp->sending++;
+#ifdef VERIFY_ACK
+ lp->outgoing.lasttrans_dest=lp->outgoing.lastload_dest;
+ lp->outgoing.lastload_dest=0;
+#endif
}
-
-/* The typical workload of the driver:
- Handle the network interface interrupts. */
+
+/* Called by the kernel in order to transmit a "Windows" packet.
+ */
+static int
+arcnetW_send_packet(struct sk_buff *skb, struct device *dev)
+{
+ struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+
+ BUGLVL(D_DURING)
+ printk("%s: in arcnetW_send_packet (skb=%p)\n",dev->name,skb);
+
+ if (IF_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;
+ if (tickssofar < 10)
+ return 1;
+ printk("%s: transmit timed out\n",dev->name);
+
+ /* Try to restart the adaptor. */
+ TBUSY=0;
+ dev->trans_start = jiffies;
+ return 0;
+ }
+
+ /* If some higher layer thinks we've missed an tx-done interrupt
+ we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+ itself. */
+ if (skb == NULL)
+ {
+ dev_tint(dev);
+ return 0;
+ }
+
+ /* 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 (set_bit(0, (void*)&dev->tbusy) != 0)
+ printk("%s: Transmitter access conflict.\n", dev->name);
+ else
+ {
+ union ArcPacket *arcpacket =
+ (union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
+ u_char *arcsoft,daddr;
+ short offset,length=skb->len+1;
+
+ TBUSY=1;
+
+ if (length>XMTU)
+ {
+ printk("arcnet: MTU for %s and %s must be <= 493 for Windows protocol.\n",
+ lp->adev->name,lp->wdev->name);
+ printk("arcnet: transmit aborted.\n");
+
+ dev_kfree_skb(skb,FREE_WRITE);
+ return 0;
+ }
+
+ BUGLVL(D_DURING)
+ printk("arcnet: starting tx sequence...\n");
+
+ lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate btw 2 & 3 */
+
+ /* clean out the page to make debugging make more sense :) */
+ BUGLVL(D_DURING)
+ memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
+
+ /* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
+ if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
+ daddr=arcpacket->hardheader.destination=0;
+ else
+ daddr=arcpacket->hardheader.destination=
+ ((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;
+ arcpacket->hardheader.offset1=0;
+ arcpacket->hardheader.offset2=offset;
+ }
+ else /* short packet */
+ {
+ arcpacket->hardheader.offset1=(offset-=256);
+ }
+
+ BUGLVL(D_DURING)
+ printk("arcnet: length=%Xh, offset=%Xh, offset1=%Xh, offset2=%Xh\n",
+ length,offset,arcpacket->hardheader.offset1,
+ arcpacket->hardheader.offset2);
+
+ arcsoft=&arcpacket->raw[offset];
+ arcsoft[0]=ARC_P_MS_TCPIP;
+ arcsoft++;
+
+ /* copy the packet into ARCnet shmem
+ * - the first bytes of ClientData header are skipped
+ */
+ BUGLVL(D_DURING) printk("arcnet: ready to memcpy\n");
+
+ memcpy(arcsoft,skb->data,skb->len);
+
+ BUGLVL(D_DURING)
+ printk("arcnet: transmitting packet to station %02Xh (%d bytes)\n",
+ daddr,length);
+
+ BUGLVL(D_TX)
+ {
+ int countx,county;
+
+ printk("arcnet: packet dump [tx] follows:");
+
+ for (county=0; county<16+(length>=240)*16; county++)
+ {
+ printk("\n[%04X] ",county*16);
+ for (countx=0; countx<16; countx++)
+ printk("%02X ",
+ arcpacket->raw[county*16+countx]);
+ }
+
+ printk("\n");
+ }
+
+ #ifdef VERIFY_ACK
+ lp->outgoing.lastload_dest=daddr;
+ #endif
+ lp->txready=lp->txbuf; /* packet is ready for sending */
+
+ arcnetA_go_tx(dev);
+ dev->trans_start = jiffies;
+ }
+
+ dev_kfree_skb(skb,FREE_WRITE);
+
+ return 0;
+}
+
+
+/****************************************************************************
+ * *
+ * Interrupt handler *
+ * *
+ ****************************************************************************/
+
+
+/* The typical workload of the driver: Handle the network interface
+ * interrupts. This doesn't do much right now except call arcnet_inthandler,
+ * which takes different parameters but is sometimes called from other places
+ * as well.
+ */
static void
arcnet_interrupt(int irq,struct pt_regs *regs)
{
struct device *dev = (struct device *)(irq2dev_map[irq]);
- if (dev == NULL) {
- if (net_debug >= D_DURING)
+ if (dev==NULL || !dev->start)
+ {
+ BUGLVL(D_EXTRA)
printk("arcnet: irq %d for unknown device.\n", irq);
return;
}
-
+
arcnet_inthandler(dev);
}
+
+/* The actual interrupt handler routine - handle various IRQ's generated
+ * by the card.
+ */
static void
arcnet_inthandler(struct device *dev)
{
struct arcnet_local *lp;
int ioaddr, status, boguscount = 3, didsomething;
+ if (dev->interrupt)
+ printk("arcnet: DRIVER PROBLEM! Nested arcnet interrupts!\n");
+
dev->interrupt = 1;
- sti();
ioaddr = dev->base_addr;
lp = (struct arcnet_local *)dev->priv;
-#ifdef IRQ_XMIT
outb(0,INTMASK);
-#endif
+ sti();
BUGLVL(D_DURING)
printk("arcnet: in net_interrupt (status=%Xh)\n",inb(STATUS));
@@ -1386,13 +1604,12 @@
if (!dev->start)
{
- BUGLVL(D_EXTRA)
+ BUGLVL(D_DURING)
printk("arcnet: ARCnet not yet initialized. irq ignored. (status=%Xh)\n",
status);
-#ifdef IRQ_XMIT
if (!(status&NORXflag))
- outb(NORXflag,INTMASK);
-#endif
+ outb(NORXflag|RECON_flag,INTMASK);
+
dev->interrupt=0;
return;
}
@@ -1402,14 +1619,22 @@
*/
if (status & RESETflag)
{
+ outb(CFLAGScmd|RESETclear,COMMAND);
BUGLVL(D_INIT)
printk("arcnet: reset irq (status=%Xh)\n",
status);
- dev->interrupt=0;
- return;
}
+#ifdef DETECT_RECONFIGS
+ if (status & RECONflag)
+ {
+ outb(CFLAGScmd|CONFIGclear,COMMAND);
+ BUGLVL(D_EXTRA)
+ printk("arcnet: Network reconfiguration detected (status=%Xh)\n",
+ status);
+ lp->stats.tx_carrier_errors++;
+ }
+#endif
-#if 1 /* yes, it's silly to disable this part but it makes good testing */
/* RX is inhibited - we must have received something. */
if (status & NORXflag)
{
@@ -1427,8 +1652,7 @@
didsomething++;
}
-#endif
-#ifdef IRQ_XMIT
+
/* it can only be an xmit-done irq if we're xmitting :) */
if (status&TXFREEflag && !lp->in_txhandler && lp->sending)
{
@@ -1441,10 +1665,31 @@
printk("arcnet: TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
status,out->numsegs,out->segnum,out->skb);
+#ifdef VERIFY_ACK
+ if (!(status&TXACKflag))
+ {
+ if (lp->outgoing.lasttrans_dest != 0)
+ {
+ BUGLVL(D_NORMAL)
+ printk("arcnet: transmit was not acknowledged! (status=%Xh, dest=%d)\n",
+ status,
+ lp->outgoing.lasttrans_dest);
+ lp->stats.tx_errors++;
+ }
+ else
+ {
+ BUGLVL(D_DURING)
+ printk("arcnet: broadcast was not acknowledged; that's normal (status=%Xh, dest=%d)\n",
+ status,
+ lp->outgoing.lasttrans_dest);
+ }
+ }
+#endif
+
/* send packet if there is one */
if (lp->txready)
{
- arcnet_go_tx(dev);
+ arcnetA_go_tx(dev);
didsomething++;
}
@@ -1460,9 +1705,9 @@
printk("arcnet: TX IRQ done: no split to continue.\n");
/* inform upper layers */
- if (!lp->txready && dev->tbusy)
+ if (!lp->txready && IF_TBUSY)
{
- dev->tbusy=0;
+ TBUSY=0;
mark_bh(NET_BH);
}
@@ -1476,9 +1721,9 @@
* are done, then continue xmit.
*/
if (out->segnum<out->numsegs)
- arcnet_continue_tx(dev);
+ arcnetA_continue_tx(dev);
if (lp->txready && !lp->sending)
- arcnet_go_tx(dev);
+ arcnetA_go_tx(dev);
/* if segnum==numsegs, the transmission is finished;
* free the skb.
@@ -1492,9 +1737,9 @@
out->skb=NULL;
/* inform upper layers */
- if (!lp->txready && dev->tbusy)
+ if (!lp->txready && IF_TBUSY)
{
- dev->tbusy=0;
+ TBUSY=0;
mark_bh(NET_BH);
}
}
@@ -1502,49 +1747,52 @@
lp->in_txhandler--;
}
-#endif /* IRQ_XMIT */
+
} while (--boguscount && didsomething);
BUGLVL(D_DURING)
- printk("arcnet: net_interrupt complete (status=%Xh)\n",
+ printk("arcnet: net_interrupt complete (status=%Xh)\n\n",
inb(STATUS));
-#ifdef IRQ_XMIT
if (dev->start && lp->sending )
- outb(NORXflag|TXFREEflag,INTMASK);
+ outb(NORXflag|TXFREEflag|RECON_flag,INTMASK);
else
- outb(NORXflag,INTMASK);
-#endif
+ outb(NORXflag|RECON_flag,INTMASK);
dev->interrupt=0;
}
+
+/****************************************************************************
+ * *
+ * Receiver routines *
+ * *
+ ****************************************************************************/
+
+
/* A packet has arrived; grab it from the buffers and possibly unsplit it.
+ * This is a generic packet receiver that calls arcnet??_rx depending on the
+ * protocol ID found.
*/
static void
arcnet_rx(struct device *dev,int recbuf)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr = dev->base_addr;
-/* int status = inb(STATUS);*/
-
- struct sk_buff *skb;
-
union ArcPacket *arcpacket=
(union ArcPacket *)(dev->mem_start+recbuf*512);
- struct ClientData *soft,*arcsoft;
+ u_char *arcsoft;
short length,offset;
- u_char pkttype,daddr,saddr;
+ u_char daddr,saddr;
- daddr=arcpacket->hardheader.destination;
saddr=arcpacket->hardheader.source;
+ daddr=arcpacket->hardheader.destination;
- /* if source is 0, it's not a "used" packet! */
+ /* if source is 0, it's a "used" packet! */
if (saddr==0)
{
- /*BUGLVL(D_DURING)*/
- printk("arcnet: discarding old packet. (status=%Xh)\n",
- inb(STATUS));
+ printk("arcnet: discarding old packet. (status=%Xh)\n",
+ inb(STATUS));
lp->stats.rx_errors++;
return;
}
@@ -1553,30 +1801,91 @@
if (arcpacket->hardheader.offset1) /* Normal Packet */
{
offset=arcpacket->hardheader.offset1;
- arcsoft=(struct ClientData *)
- (&arcpacket->raw[offset-EXTRA_CLIENTDATA]);
- length=256-offset+EXTRA_CLIENTDATA;
- pkttype=NORMAL;
+ arcsoft=&arcpacket->raw[offset];
+ length=256-offset;
}
else /* ExtendedPacket or ExceptionPacket */
{
offset=arcpacket->hardheader.offset2;
- arcsoft=(struct ClientData *)
- (&arcpacket->raw[offset-EXTRA_CLIENTDATA]);
+ arcsoft=&arcpacket->raw[offset];
- if (arcsoft->split_flag!=0xFF) /* Extended Packet */
- {
- length=512-offset+EXTRA_CLIENTDATA;
- pkttype=EXTENDED;
- }
- else /* Exception Packet */
- {
- /* skip over 4-byte junkola */
- arcsoft=(struct ClientData *)
- ((u_char *)arcsoft + 4);
- length=512-offset+EXTRA_CLIENTDATA-4;
- pkttype=EXCEPTION;
- }
+ length=512-offset;
+ }
+
+ BUGLVL(D_DURING)
+ printk("arcnet: 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:
+ arcnetA_rx(dev,(struct ClientData*)arcsoft,
+ length,saddr,daddr);
+ break;
+ case ARC_P_MS_TCPIP:
+ arcnetW_rx(dev,arcsoft,length,saddr,daddr);
+ break;
+ default:
+ printk("arcnet: received unknown protocol %d (%Xh)\n",
+ arcsoft[0],arcsoft[0]);
+ break;
+ }
+
+ BUGLVL(D_RX)
+ {
+ int countx,county;
+
+ printk("arcnet: rx packet dump follows:");
+
+ for (county=0; county<16+(length>240)*16; county++)
+ {
+ printk("\n[%04X] ",county*16);
+ for (countx=0; countx<16; countx++)
+ printk("%02X ",
+ arcpacket->raw[county*16+countx]);
+ }
+
+ printk("\n");
+ }
+
+
+ /* 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 device *dev,struct ClientData *arcsoft,
+ int length,u_char saddr, u_char daddr)
+{
+ struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+ struct sk_buff *skb;
+ struct ClientData *soft;
+
+ BUGLVL(D_DURING)
+ printk("arcnet: it's an RFC1201 packet (length=%d)\n",
+ length);
+
+ arcsoft=(struct ClientData *)((u_char *)arcsoft-EXTRA_CLIENTDATA);
+ length+=EXTRA_CLIENTDATA;
+
+ if (arcsoft->split_flag==0xFF) /* Exception Packet */
+ {
+ BUGLVL(D_DURING)
+ printk("arcnet: 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 */
@@ -1586,26 +1895,28 @@
BUGLVL(D_RX) printk("arcnet: incoming is not split (splitflag=%d)\n",
arcsoft->split_flag);
- if (in->skb) /* already assembling one! */
+ if (in->skb) /* already assembling one! */
{
- BUGLVL(D_INIT) printk("arcnet: aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
+ BUGLVL(D_EXTRA) printk("arcnet: aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag,
arcsoft->sequence);
kfree_skb(in->skb,FREE_WRITE);
+ lp->stats.tx_dropped++;
+ lp->stats.rx_errors++;
in->skb=NULL;
}
in->sequence=arcsoft->sequence;
- skb = dev_alloc_skb(length);
+ skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) {
- printk("%s: Memory squeeze, dropping packet.\n",
- dev->name);
+ printk("arcnet: Memory squeeze, dropping packet.\n");
lp->stats.rx_dropped++;
return;
}
- soft=(struct ClientData *)skb_put(skb,length);
+ soft=(struct ClientData *)skb->data;
+ skb->len = length;
skb->dev = dev;
memcpy((u_char *)soft+EXTRA_CLIENTDATA,
@@ -1614,30 +1925,10 @@
soft->daddr=daddr;
soft->saddr=saddr;
- BUGLVL(D_DURING)
- printk("arcnet: received packet from %02Xh to %02Xh (%d bytes, type=%d)\n",
- saddr,daddr,length,pkttype);
- BUGLVL(D_RX)
- {
- int countx,county;
-
- printk("arcnet: packet dump [rx-unsplit] follows:");
-
- for (county=0; county<16+(pkttype!=NORMAL)*16; county++)
- {
- printk("\n[%04X] ",county*16);
- for (countx=0; countx<16; countx++)
- printk("%02X ",
- arcpacket->raw[county*16+countx]);
- }
-
- printk("\n");
- }
-
/* ARP packets have problems when sent from DOS.
- * source address is always 0! So we take the hardware
- * source addr (which is impossible to fumble) and insert
- * it ourselves.
+ * 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)
{
@@ -1651,7 +1942,7 @@
if (!*cptr) /* is saddr = 00? */
{
- BUGLVL(D_DURING)
+ BUGLVL(D_EXTRA)
printk("arcnet: ARP source address was 00h, set to %02Xh.\n",
saddr);
*cptr=saddr;
@@ -1666,9 +1957,23 @@
{
printk("arcnet: funny-shaped ARP packet. (%Xh, %Xh)\n",
arp->ar_hln,arp->ar_pln);
+ lp->stats.rx_frame_errors++;
}
}
- skb->protocol=arc_type_trans(skb,dev);
+
+ BUGLVL(D_SKB)
+ {
+ short i;
+ for( i=0; i< skb->len; i++)
+ {
+ if( i%16 == 0 ) printk("\n[%04hX] ",i);
+ printk("%02hX ",((unsigned char*)skb->data)[i]);
+ }
+ printk("\n");
+ }
+
+ skb->protocol=arcnetA_type_trans(skb,dev);
+
netif_rx(skb);
lp->stats.rx_packets++;
}
@@ -1698,11 +2003,13 @@
if (in->skb && in->sequence!=arcsoft->sequence)
{
- BUGLVL(D_INIT) printk("arcnet: wrong seq number, aborting assembly (expected=%d, seq=%d, splitflag=%d)\n",
+ BUGLVL(D_EXTRA) printk("arcnet: wrong seq number, aborting assembly (expected=%d, seq=%d, splitflag=%d)\n",
in->sequence,arcsoft->sequence,
arcsoft->split_flag);
kfree_skb(in->skb,FREE_WRITE);
in->skb=NULL;
+ lp->stats.tx_dropped++;
+ lp->stats.rx_fifo_errors++;
in->lastpacket=in->numpackets=0;
}
@@ -1712,9 +2019,11 @@
arcsoft->split_flag);
if (in->skb) /* already assembling one! */
{
- BUGLVL(D_INIT) printk("arcnet: aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
+ BUGLVL(D_EXTRA) printk("arcnet: aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag,
arcsoft->sequence);
+ lp->stats.tx_dropped++;
+ lp->stats.rx_over_errors++;
kfree_skb(in->skb,FREE_WRITE);
}
@@ -1724,14 +2033,15 @@
if (in->numpackets>16)
{
- printk("arcnet: incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
+ BUGLVL(D_EXTRA) printk("arcnet: incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
arcsoft->split_flag);
lp->stats.rx_dropped++;
return;
}
- in->skb=skb=dev_alloc_skb(508*in->numpackets
- + sizeof(struct ClientData));
+ in->skb=skb=alloc_skb(508*in->numpackets
+ + sizeof(struct ClientData),
+ GFP_ATOMIC);
if (skb == NULL) {
printk("%s: (split) memory squeeze, dropping packet.\n",
dev->name);
@@ -1744,8 +2054,9 @@
*/
skb->free=1;
- soft=(struct ClientData *)skb_put(skb,sizeof(struct ClientData));
+ soft=(struct ClientData *)skb->data;
+ skb->len=sizeof(struct ClientData);
skb->dev=dev;
memcpy((u_char *)soft+EXTRA_CLIENTDATA,
@@ -1762,8 +2073,9 @@
*/
if (!in->skb)
{
- BUGLVL(D_INIT) printk("arcnet: can't continue split without starting first! (splitflag=%d, seq=%d)\n",
+ BUGLVL(D_EXTRA) printk("arcnet: can't continue split without starting first! (splitflag=%d, seq=%d)\n",
arcsoft->split_flag,arcsoft->sequence);
+ lp->stats.rx_errors++;
return;
}
@@ -1773,53 +2085,37 @@
/* harmless duplicate? ignore. */
if (packetnum<=in->lastpacket-1)
{
- BUGLVL(D_INIT) printk("arcnet: duplicate splitpacket ignored! (splitflag=%d)\n",
+ BUGLVL(D_EXTRA) printk("arcnet: duplicate splitpacket ignored! (splitflag=%d)\n",
arcsoft->split_flag);
return;
}
/* "bad" duplicate, kill reassembly */
- BUGLVL(D_INIT) printk("arcnet: out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
+ BUGLVL(D_EXTRA) printk("arcnet: out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag,
arcsoft->sequence);
kfree_skb(in->skb,FREE_WRITE);
in->skb=NULL;
+ lp->stats.tx_dropped++;
+ lp->stats.rx_fifo_errors++;
in->lastpacket=in->numpackets=0;
return;
}
- soft=(struct ClientData *)skb->data;
+ soft=(struct ClientData *)in->skb->data;
}
skb=in->skb;
- memcpy(skb_put(skb,length-sizeof(struct ClientData)),
+ memcpy(skb->data+skb->len,
(u_char *)arcsoft+sizeof(struct ClientData),
length-sizeof(struct ClientData));
+ skb->len+=length-sizeof(struct ClientData);
+
soft->daddr=daddr;
soft->saddr=saddr;
- BUGLVL(D_DURING)
- printk("arcnet: received packet from %02Xh to %02Xh (%d bytes, type=%d)\n",
- saddr,daddr,length,pkttype);
- BUGLVL(D_RX)
- {
- int countx,county;
-
- printk("arcnet: packet dump [rx-split] follows:");
-
- for (county=0; county<16+(pkttype!=NORMAL)*16; county++)
- {
- printk("\n[%04X] ",county*16);
- for (countx=0; countx<16; countx++)
- printk("%02X ",
- arcpacket->raw[county*16+countx]);
- }
-
- printk("\n");
- }
-
/* are we done? */
if (in->lastpacket == in->numpackets)
{
@@ -1828,75 +2124,102 @@
skb,in->skb);
in->skb=NULL;
in->lastpacket=in->numpackets=0;
- skb->protocol=arc_type_trans(skb,dev);
+
+ BUGLVL(D_SKB)
+ {
+ short i;
+ for( i=0; i< skb->len; i++)
+ {
+ if( i%16 == 0 ) printk("\n[%04hX] ",i);
+ printk("%02hX ",((unsigned char*)skb->data)[i]);
+ }
+ printk("\n");
+ }
+
+ skb->protocol=arcnetA_type_trans(skb,dev);
+
netif_rx(skb);
lp->stats.rx_packets++;
}
}
-
- /* If any worth-while packets have been received, netif_rx()
- has done a mark_bh(NET_BH) for us and will work on them
- when we get to the bottom-half routine. */
}
-#ifdef USE_TIMER_HANDLER
-/* this function is called every once in a while to make sure the ARCnet
- * isn't stuck.
- *
- * If we miss a receive IRQ, the receiver (and IRQ) is permanently disabled
- * and we might never receive a packet again! This will check if this
- * is the case, and if so, re-enable the receiver.
+/* Packet receiver for non-standard Windows-style packets
*/
static void
-arcnet_timer(unsigned long arg)
+arcnetW_rx(struct device *dev,u_char *arcsoft,
+ int length,u_char saddr, u_char daddr)
{
- struct device *dev=(struct device *)arg;
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
- short ioaddr=dev->base_addr;
- int status=inb(STATUS);
+ struct sk_buff *skb;
+
+ BUGLVL(D_DURING)
+ printk("arcnet: it's a Windows packet (length=%d)\n",
+ length);
- /* if we didn't interrupt the IRQ handler, and RX's are still
- * disabled, and we're not resetting the card... then we're stuck!
- */
- if (!dev->interrupt && dev->start
- && status&NORXflag && !status&RESETflag)
- {
- BUGLVL(D_INIT)
- printk("arcnet: timer: ARCnet was stuck! (status=%Xh)\n",
- status);
-
- arcnet_inthandler(dev);
- }
+ skb = alloc_skb(length, GFP_ATOMIC);
+ if (skb == NULL) {
+ printk("arcnet: Memory squeeze, dropping packet.\n");
+ lp->stats.rx_dropped++;
+ return;
+ }
+
+ skb->len = length;
+ skb->dev = lp->wdev;
+
+ memcpy(skb->data,(u_char *)arcsoft+1,length-1);
- /* requeue ourselves */
- init_timer(&lp->timer);
- lp->timer.expires=TIMERval;
- add_timer(&lp->timer);
+ BUGLVL(D_SKB)
+ {
+ short i;
+ printk("arcnet: rx skb dump follows:\n");
+ for(i=0; i<skb->len; i++)
+ {
+ if (i%16==0)
+ printk("\n[%04hX] ",i);
+ else
+ printk("%02hX ",((u_char *)skb->data)[i]);
+ }
+ printk("\n");
+ }
+
+ skb->protocol=eth_type_trans(skb,dev);
+
+ netif_rx(skb);
+ lp->stats.rx_packets++;
}
-#endif
+
+
+/****************************************************************************
+ * *
+ * Miscellaneous routines *
+ * *
+ ****************************************************************************/
+
/* Get the current statistics. This may be called with the card open or
- closed. */
+ * closed.
+ */
+
static struct enet_statistics *
arcnet_get_stats(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-/* short ioaddr = dev->base_addr;*/
return &lp->stats;
}
/* 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.
+ * 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.
*/
static void
set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
-#if 0 /* no promiscuous mode at all */
+#if 0 /* no promiscuous mode at all on most ARCnet models */
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
short ioaddr = dev->base_addr;
@@ -1907,74 +2230,17 @@
#endif
}
-int arcnet_reset(struct device *dev)
-{
- struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
- short ioaddr=dev->base_addr;
- int delayval,recbuf=lp->recbuf;
-
- outb(0,INTMASK); /* no IRQ's, please! */
-
- BUGLVL(D_INIT)
- printk("arcnet: Resetting %s (status=%Xh)\n",
- dev->name,inb(STATUS));
-
- inb(RESET); /* Reset by reading this port */
- JIFFER(RESETtime);
-
- outb(CFLAGScmd|RESETclear, COMMAND); /* clear flags & end reset */
- outb(CFLAGScmd|CONFIGclear,COMMAND);
-
- /* after a reset, the first byte of shared mem is TESTvalue and the
- * second byte is our 8-bit ARCnet address
- */
- {
- u_char *cardmem = (u_char *) dev->mem_start;
- if (cardmem[0] != TESTvalue)
- {
- BUGLVL(D_INIT)
- printk("arcnet: reset failed: TESTvalue not present.\n");
- return 1;
- }
- lp->arcnum=cardmem[1]; /* save address for later use */
- }
-
- /* clear out status variables */
- recbuf=lp->recbuf=0;
- lp->txbuf=2;
- /*dev->tbusy=0;*/
-
- /* enable extended (512-byte) packets */
- outb(CONFIGcmd|EXTconf,COMMAND);
- XJIFFER(ACKtime);
-
- /* clean out all the memory to make debugging make more sense :) */
- BUGLVL(D_DURING)
- memset((void *)dev->mem_start,0x42,2048);
-
- /* and enable receive of our first packet to the first buffer */
- EnableReceiver();
-
- /* re-enable interrupts */
- outb(NORXflag,INTMASK);
-
- /* done! return success. */
- return 0;
-}
-
-
-/*
- * Create the ARCnet ClientData header for an arbitrary protocol layer
+/* 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)
+ * saddr=NULL means use device source address (always will anyway)
+ * daddr=NULL means leave destination address (eg unresolved arp)
*/
-int arc_header(struct sk_buff *skb,struct device *dev,unsigned short type,
+int arcnetA_header(struct sk_buff *skb,struct 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);
+/* struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);*/
/* set the protocol ID according to RFC-1201 */
switch(type)
@@ -2000,18 +2266,18 @@
return 0;
}
-#if 1
/*
- * Set the source hardware address.
- * AVE: we can't do this, so we don't. Code below is directly
- * stolen from eth.c driver and won't work.
- ** TM: but for debugging I would like to have saddr in the header
+ * 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];
-#endif
#if 0
/*
@@ -2028,7 +2294,7 @@
#endif
head->split_flag=0; /* split packets are done elsewhere */
- head->sequence=(lp->sequence++);
+ head->sequence=0; /* so are sequence numbers */
/* supposedly if daddr is NULL, we should ignore it... */
if(daddr)
@@ -2043,18 +2309,17 @@
}
-/*
- * 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.
+/* 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.
*/
-int arc_rebuild_header(void *buff,struct device *dev,unsigned long dst,
+int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst,
struct sk_buff *skb)
{
struct ClientData *head = (struct ClientData *)buff;
/*
- * Only ARP/IP is currently supported
+ * Only ARP and IP are currently supported
*/
if(head->protocol_id != ARC_P_IP)
@@ -2067,7 +2332,7 @@
}
/*
- * Try and get ARP to resolve the header.
+ * Try and get ARP to resolve the header.
*/
#ifdef CONFIG_INET
return arp_find(&(head->daddr), dst, dev, dev->pa_addr, skb)? 1 : 0;
@@ -2076,25 +2341,22 @@
#endif
}
-/*
- * Determine the packet's protocol ID.
+/* Determine a packet's protocol ID.
*
- * With ARCnet we have to convert everything to Ethernet-style stuff.
+ * With ARCnet we have to convert everything to Ethernet-style stuff.
*/
-unsigned short arc_type_trans(struct sk_buff *skb,struct device *dev)
+unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev)
{
struct ClientData *head = (struct ClientData *) skb->data;
+ struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
- /*
- * Pull off the arcnet header.
- */
-
+ /* Pull off the arcnet header. */
skb->mac.raw=skb->data;
skb_pull(skb,dev->hard_header_len);
if (head->daddr==0)
skb->pkt_type=PACKET_BROADCAST;
- else if(dev->flags&IFF_PROMISC)
+ else if (dev->flags&IFF_PROMISC)
{
/* if we're not sending to ourselves :) */
if (head->daddr != dev->dev_addr[0])
@@ -2108,50 +2370,61 @@
case ARC_P_ARP: return htons(ETH_P_ARP);
case ARC_P_RARP: return htons(ETH_P_RARP);
case ARC_P_IPX: return htons(ETH_P_IPX);
- case ARC_P_ATALK: return htons(ETH_P_ATALK); /* Doesn't work yet */
+ case ARC_P_ATALK: return htons(ETH_P_ATALK); /* untested appletalk */
case ARC_P_LANSOFT: /* don't understand. fall through. */
default:
- BUGLVL(D_DURING)
+ BUGLVL(D_EXTRA)
printk("arcnet: received packet of unknown protocol id %d (%Xh)\n",
head->protocol_id,head->protocol_id);
+ lp->stats.rx_frame_errors++;
return 0;
}
+
return htons(ETH_P_IP);
}
+
+
+/****************************************************************************
+ * *
+ * Kernel Loadable Module Support *
+ * *
+ ****************************************************************************/
+
+
#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
-static struct device thisARCnet = {
- " ",/* if blank, device name inserted by /linux/drivers/net/net_init.c */
+static struct device thiscard = {
+ " ",/* if blank, device name inserted by /linux/drivers/net/net_init.c */
0, 0, 0, 0,
0, 0, /* I/O address, IRQ */
0, 0, 0, NULL, arcnet_probe };
int io=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
-int irqnum=0; /* or use the insmod io= irq= shmem= options */
+int irqnum=0; /* or use the insmod io= irqnum= shmem= options */
int shmem=0;
-int num=0; /* number of device (ie for arc0, arc1, arc2...) */
+int num=0; /* number of device (ie for 0 for arc0, 1 for arc1...) */
int
init_module(void)
{
- sprintf(thisARCnet.name,"arc%d",num);
+ sprintf(thiscard.name,"arc%d",num);
- thisARCnet.base_addr=io;
+ thiscard.base_addr=io;
- thisARCnet.irq=irqnum;
- if (thisARCnet.irq==2) thisARCnet.irq=9;
+ thiscard.irq=irqnum;
+ if (thiscard.irq==2) thiscard.irq=9;
if (shmem)
{
- thisARCnet.mem_start=shmem;
- thisARCnet.mem_end=thisARCnet.mem_start+512*4-1;
- thisARCnet.rmem_start=thisARCnet.mem_start+512*0;
- thisARCnet.rmem_end=thisARCnet.mem_start+512*2-1;
+ thiscard.mem_start=shmem;
+ thiscard.mem_end=thiscard.mem_start+512*4-1;
+ thiscard.rmem_start=thiscard.mem_start+512*0;
+ thiscard.rmem_end=thiscard.mem_start+512*2-1;
}
- if (register_netdev(&thisARCnet) != 0)
+ if (register_netdev(&thiscard) != 0)
return -EIO;
return 0;
}
@@ -2159,15 +2432,18 @@
void
cleanup_module(void)
{
- if (MOD_IN_USE) {
- printk("%s: device busy, remove delayed\n",thisARCnet.name);
- } else {
- if (thisARCnet.start) arcnet_close(&thisARCnet);
- if (thisARCnet.irq) free_irq(thisARCnet.irq);
- if (thisARCnet.base_addr) release_region(thisARCnet.base_addr,
- ETHERCARD_TOTAL_SIZE);
- unregister_netdev(&thisARCnet);
- }
+ if (MOD_IN_USE)
+ {
+ printk("%s: device busy, remove delayed\n",thiscard.name);
+ }
+ else
+ {
+ if (thiscard.start) arcnet_close(&thiscard);
+ if (thiscard.irq) free_irq(thiscard.irq);
+ if (thiscard.base_addr) release_region(thiscard.base_addr,
+ ARCNET_TOTAL_SIZE);
+ unregister_netdev(&thiscard);
+ }
}
#endif /* MODULE */
@@ -2176,10 +2452,10 @@
/*
* Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c arcnet.c"
* version-control: t
* kept-new-versions: 5
- * tab-width: 4
+ * tab-width: 8
* End:
*/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this