diff -u --recursive --new-file v2.1.24/linux/CREDITS linux/CREDITS
--- v2.1.24/linux/CREDITS	Tue Jan 28 18:49:43 1997
+++ linux/CREDITS	Sun Feb  2 15:18:29 1997
@@ -757,6 +757,16 @@
 S: 1098 VA Amsterdam 
 S: The Netherlands
 
+N: Gene Kozin
+E: 74604.152@compuserve.com
+W: http://www.sangoma.com
+D: WAN Router & Sangoma WAN drivers
+S: Sangoma Technologies Inc.
+S: 7170 Warden Avenue, Unit 2
+S: Markham, Ontario
+S: L3R 8B2
+S: Canada
+
 N: Gero Kuhlmann
 E: gero@gkminix.han.de
 D: mounting root via NFS
diff -u --recursive --new-file v2.1.24/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.24/linux/Documentation/Configure.help	Tue Jan 28 18:49:45 1997
+++ linux/Documentation/Configure.help	Sun Feb  2 15:18:29 1997
@@ -841,41 +841,6 @@
   on sunsite.unc.edu:/pub/Linux/docs/HOWTO).  Short answer:
   say Y.
 
-IP: forwarding/gatewaying
-CONFIG_IP_FORWARD
-  People who want to use their Linux box as the router for a local
-  network (i.e. the computer responsible for distributing Internet
-  traffic to and from the machines in the local network and the
-  subnetworks) should say Y here (thereby enlarging their kernel by
-  about 5 kB). Note that in this case, you possibly have two ethernet
-  devices in your computer: one for the "outside world" and one for
-  your local net. The kernel is not able to recognize both at boot
-  time without help; for details read the
-  Multiple-Ethernet-mini-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.  If your box is
-  connected to two networks, it may still make sense to say N here,
-  namely if you want to turn your box into a firewall protecting a
-  local network from the internet. The Firewall-HOWTO tells you how to
-  do this. If your setup is more complex, say you are connected to
-  three networks and you want to act as a firewall between two of them
-  and route traffic for the others, you need to say Y here and Y to 
-  "IP firewalling" below. If you intend to use IP masquerading (i.e. IP
-  traffic from one of the local computers and destined for an outside
-  host is changed by your box so that it appears to come from you),
-  you'll have to say Y here and also to IP firewalling and IP
-  masquerading below. You should also say Y here if you want to
-  configure your box as a SLIP (the protocol for sending internet
-  traffic over telephone lines) or PPP (a better SLIP) server for
-  other people to dial into and your box is connected to a local
-  network at the same time. You would then most likely use proxy-ARP
-  (Address Resolution Protocol), explained in the Proxy-Arp mini howto
-  on sunsite in /pub/Linux/docs/HOWTO/mini. You also need to say Y
-  here if you want to run mrouted in order to do multicast routing as
-  used on the MBONE (a high bandwidth network on top of the internet
-  which carries audio and video broadcasts) for example. In this case,
-  say Y to "IP: multicasting" and "IP: multicast routing" as well. If
-  unsure, say N.
-
 IP: multicasting
 CONFIG_IP_MULTICAST
   This is code for addressing several networked computers at once,
@@ -1249,6 +1214,23 @@
   all you will need to do is download and install the localtalk
   driver.
 
+IP-over-DDP support
+CONFIG_IPDDP
+  This allows IP networking for users who only have Appletalk
+  networking available.  It doesn't work yet in 2.1.xx, so you
+  should say N.
+
+LocalTalk PC card support
+CONFIG_LTPC
+  This allows you to use the AppleTalk PC card to connect to LocalTalk
+  networks.  The card is also known as the Farallon PhoneNet PC card.
+  If you are in doubt, this card is the one with the 65C02 chip on it.
+  You also need version 1.3.3 or later of the netatalk package.
+  This driver is experimental, which means that it may not work.
+  In particular the module support is not yet working for the 2.1.xx
+  kernels, so choose Y or N, but not M for now.
+  See README.ltpc in the drivers/net directory.
+
 Amateur Radio AX.25 Level 2
 CONFIG_AX25
   This is the protocol used for computer communication over amateur
@@ -2156,14 +2138,6 @@
   the running kernel whenever you want), say M here and read
   Documentation/modules.txt. The module will be called strip.o.
 
-WIC (Radio IP bridge)
-CONFIG_WIC
-  Support for the WIC parallel port radio bridge. You'll probably want
-  to say N.  If you want to compile this driver as a module though ( =
-  code which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read Documentation/modules.txt.
-  The module will be called wic.o.
-  
 CONFIG_LAPBETHER
 LAPB over Ethernet driver
   This is a driver for a pseudo device (usually called /dev/lapb0)
@@ -2383,6 +2357,75 @@
   sdla.o. If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
+WAN Router
+CONFIG_WAN_ROUTER
+      Wide Area Networks (WANs), such as X.25, frame relay and leased
+  lines, are used to interconnect Local Area Networks (LANs) over vast
+  distances with data transfer rates significantly higher than those
+  achievable with commonly used asynchronous modem connections.
+  Usually, a quite expensive external device called `WAN router' is
+  needed to connect to WAN.
+      As an alternative, WAN router can be build into Linux kernel.
+  With relatively inexpensive WAN interface cards available on the
+  market, a perfectly usable router can be built for less than half a
+  price of an external router.  If you have one of those cards (with
+  appropriate WAN Link Driver) and wish to use your Linux box as a WAN
+  router, you may say 'Y' to this option.  You will also need a
+  wan-tools package available via FTP (user: anonymous) from
+  ftp.sangoma.com.  Read Documentation/networking/wan-router.txt for
+  more information.
+      WAN router is always built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  For general information about modules read Documentation/modules.txt.
+
+WAN Drivers
+CONFIG_WAN_DRIVERS
+      Say 'Y' to this option if you are planning to use your Linux box
+  as a WAN router ( = device used to interconnect local area networks
+  over wide area communication links, such as leased lines and public
+  data networks, e.g. X.25 and frame relay) and you will be offered a
+  list of WAN drivers currently available.  For more information, read
+  Documentation/networking/wan-router.txt.
+
+Sangoma WANPIPE(tm) multiprotocol cards
+CONFIG_VENDOR_SANGOMA
+      WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com)
+  is a family of intelligent multiprotocol WAN adapter with data
+  transfer rates up to T1 (1.544 Mbps).  They are also known as
+  Synchronous Data Link Adapters (SDLA) and designated S502E(A), S503
+  or S508.  If you have one of these cards, say 'Y' to this option.
+      WANPIPE driver is always built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  For general information about modules read Documentation/modules.txt.
+
+Maximum number of cards
+CONFIG_WANPIPE_CARDS
+      Enter number of WANPIPE adapters installed in your machine.  The
+  driver can support up to 8 cards.  You may enter more that you
+  actually have if you plan to add more cards in the future without
+  re-compiling the driver, but remember that in this case you'll waste
+  some kernel memory (about 1K per card).
+
+WANPIPE X.25 support
+CONFIG_WANPIPE_X25
+      Say 'Y' to this option, if you are planning to connect WANPIPE
+  card to an X.25 network.  If you say 'N', the X.25 support will not
+  be included in the driver (saves about 16K of kernel memory).
+
+WANPIPE Frame Relay support
+CONFIG_WANPIPE_FR
+      Say 'Y' to this option, if you are planning to connect WANPIPE
+  card to a frame relay network.  If you say 'N', the frame relay
+  support will not be included in the driver (saves about 16K of
+  kernel memory).
+
+WANPIPE PPP support
+CONFIG_WANPIPE_PPP
+      Say 'Y' to this option, if you are planning to connect WANPIPE
+  card to a leased line using Point-to-Point protocol (PPP).  If you
+  say 'N', the PPP support will not be included in the driver (saves
+  about 16K of kernel memory).
+
 Sun LANCE Ethernet support
 CONFIG_SUN_LANCE
   This is support for lance ethernet cards on Sun workstations such as
@@ -2656,6 +2699,20 @@
   Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt. If you plan to use more
   than one network card under linux, read the
+  Multiple-Ethernet-mini-HOWTO, available from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+
+CS89x0 support
+CONFIG_CS89x0
+  Support for CS89x0 chipset based ethernet cards. 
+  If you have a network (ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO as well as
+  drivers/net/depca.c.  If you want to compile this as a module ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want), say M here and read Documentation/modules.txt as
+  well as Documentation/networking/net-modules.txt. If you plan to use
+  more than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
diff -u --recursive --new-file v2.1.24/linux/Documentation/filesystems/vfs.txt linux/Documentation/filesystems/vfs.txt
--- v2.1.24/linux/Documentation/filesystems/vfs.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/filesystems/vfs.txt	Sun Feb  2 15:18:29 1997
@@ -0,0 +1,173 @@
+A Brief Overview of the Virtual File System
+===========================================
+	by Benjamin LaHaise (blah@dot.superaje.com)
+
+Noone else seems to be writing this, so here's a quick description of what
+I've learned while writing lofs...
+
+The VFS relatively simple, but it is nice not to have to browse through
+pages of code to determine what is expected when writing a filesystem.
+Hopefully this helps anyone attempting such a feat, as well as clearing up
+a few important points/dependancies.
+
+
+register_filesystem (struct file_system_type *fstype)
+=====================================================
+
+All filesystems are created equal... or at least they start out that way.
+A filesystem, be it in module form, or linked into the kernel, needs to add
+itself to the table of filesystems by calling register_filesystem with an
+initialized file_system_type structure.  Any further functions of the
+filesystem are accessed through the following function tables...
+
+
+struct file_system_type
+=======================
+
+	struct super_block *(*read_super) (struct super_block *sb, void *options, int silent);
+
+		This is the entry point of all filesystems.  If the filesystem succeeds
+		in mounting itself, sb should be returned, otherwise NULL.  options is
+		a pointer to a maximum of PAGE_SIZE-1 bytes of options, typically a zero
+		terminated string passed from mount.  This page is freed after read_super
+		returns, so do not use any pointers into it.
+
+		This routine _must_ set the s_op member of sb to point to a valid
+		super_operations structure.
+
+	const char *name;
+
+		Name points to a string that the system will know the filesystem by.
+
+	int requires_dev;
+
+		Set this flag to 1 if the filesystem requires a block device to be mounted
+		on.
+
+	struct file_system_type * next;
+
+		This field points to the next file_system_type that is present in the system,
+		and should be initialized to NULL.
+
+struct super_operations
+=======================
+
+The super_operations structure is found through the s_op member of the
+super_block structure.
+
+	void (*read_inode) (struct inode *inode);
+	[optional - doesn't quite make sense]
+		read_inode is called by the VFS when iget is called requesting an inode
+		not already present in the inode table.  i_ino is set to the number of the
+		inode requested.
+
+		The i_op member of inode should be set to a valid inode_operations
+		structure.  Typically filesystems have separate inode_operations for
+		directories, files and symlinks.  i_op can be NULL.
+
+	int (*notify_change) (struct inode *, struct iattr *);
+	[optional]
+	void (*write_inode) (struct inode *);
+	[optional]
+
+	int (*put_inode) (struct inode *inode);
+	[optional]
+		put_inode is called by the VFS when the last instance of inode is released
+		with a call to iput.  The only special consideration that should be made
+		is that iget may reuse inode without calling read_inode unless clear_inode
+		is called.  put_inode MUST return 1 if it called clear_inode on the inode,
+		otherwise zero.
+
+	void (*put_super) (struct super_block *);
+	[optional]
+	void (*write_super) (struct super_block *);
+	[optional]
+	void (*statfs) (struct super_block *, struct statfs *, int);
+	[optional]
+	int (*remount_fs) (struct super_block *, int *, char *);
+	[optional]
+
+
+struct inode_operations
+=======================
+
+	struct file_operations * default_file_ops;
+	[mandatory]
+		All inode_operations structures must have default_file_ops pointing to
+		a valid file_operations structure.
+
+	int (*create) (struct inode *,const char *,int,int,struct inode **);
+	[optional]
+
+	int (*lookup) (struct inode *dir, const char *name, int len, struct inode **result);
+	[optional]
+		lookup is called when the VFS wishes to have the filesystem resolve a name
+		into an inode.  Dir is a directory on the filesystem that [hopefully] contains
+		the zero terminated string name (length len).  A return value of zero indicates
+		that there is a valid inode stored in *result.
+
+***		Note: lofs assumes that any filesystem returns an inode within the filesystem
+		for all directory inodes.  Therefore, __iget(sb,ino,0) should be used to fetch
+		the inode in a filesystem's lookup routine.
+
+	int (*link) (struct inode *,struct inode *,const char *,int);
+	[optional]
+	int (*unlink) (struct inode *,const char *,int);
+	[optional]
+	int (*symlink) (struct inode *,const char *,int,const char *);
+	[optional]
+	int (*mkdir) (struct inode *,const char *,int,int);
+	[optional]
+	int (*rmdir) (struct inode *,const char *,int);
+	[optional]
+	int (*mknod) (struct inode *,const char *,int,int,int);
+	[optional]
+	int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int, int);
+	[optional]
+
+	int (*readlink) (struct inode *inode, char *buf, int len);
+	[optional]
+		readlink is called by the VFS to read the contents of a symbolic link.
+		inode is an inode that meets the S_ISLNK test, and buf points to a buffer
+		of len bytes.
+
+	int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **);
+	[optional]
+		The follow_link function is only nescessary if a filesystem uses a really
+		twisted form of symbolic links - namely if the symbolic link comes from a
+		foriegn filesystem that makes no sense....
+		I threw this one out - too much redundant code!
+
+	int (*readpage) (struct inode *, struct page *);	[optional]
+	int (*writepage) (struct inode *, struct page *);	[mandatory with readpage]
+
+		In order for files to be mmap'd, readpage and writepage are required.
+		A filesystem can use generic_readpage/writepage if it supports the bmap
+		function.  Otherwise, a custom version must be written. 
+
+	int (*bmap) (struct inode *,int);
+	[optional]
+	void (*truncate) (struct inode *);
+	[optional]
+	int (*permission) (struct inode *, int);
+	[optional]
+	int (*smap) (struct inode *,int);
+	[optional]
+
+struct file_operations
+======================
+
+	int (*lseek) (struct inode *, struct file *, off_t, int);
+	int (*read) (struct inode *, struct file *, char *, int);
+	int (*write) (struct inode *, struct file *, const char *, int);
+	int (*readdir) (struct inode *, struct file *, void *, filldir_t);
+	unsigned int (*poll) (struct file *, poll_table *);
+	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
+	int (*mmap) (struct inode *, struct file *, struct vm_area_struct *);
+	int (*open) (struct inode *, struct file *);
+	void (*release) (struct inode *, struct file *);
+	int (*fsync) (struct inode *, struct file *);
+	int (*fasync) (struct inode *, struct file *, int);
+	int (*check_media_change) (kdev_t dev);
+	int (*revalidate) (kdev_t dev);
+
diff -u --recursive --new-file v2.1.24/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.1.24/linux/Documentation/ioctl-number.txt	Wed Dec 18 15:58:34 1996
+++ linux/Documentation/ioctl-number.txt	Sun Feb  2 15:18:29 1997
@@ -81,6 +81,7 @@
 'T'	all	linux/soundcard.h	conflict!
 'T'	all	asm-i386/ioctls.h	conflict!
 'V'	all	linux/vt.h
+'W'	00-1F	linux/router.h		conflict [Please reallocate]
 'W'	00-1F	linux/watchdog.h
 'W'	20-27	linux/octal-relay.h	in development
 'W'	28-2F	linux/iso16-relay.h	in development
diff -u --recursive --new-file v2.1.24/linux/Documentation/magic-number.txt linux/Documentation/magic-number.txt
--- v2.1.24/linux/Documentation/magic-number.txt	Thu May 16 16:35:39 1996
+++ linux/Documentation/magic-number.txt	Sun Feb  2 15:18:29 1997
@@ -54,6 +54,7 @@
 ISDN_ASYNC_MAGIC    0x49344C01  modem_info           include/linux/isdn.h
 ISDN_NET_MAGIC      0x49344C02  isdn_net_ndev        include/linux/isdn.h
 STLI_BOARDMAGIC     0x4bc6c825  stlibrd_t            include/linux/istallion.h
+ROUTER_MAGIC        0x524d4157  wanlink_t            include/linux/router.h
 STLI_PORTMAGIC      0xe671c7a1  stliport_t           include/linux/istallion.h
 STL_PANELMAGIC      0x7ef621a1  stlpanel_t           include/linux/stallion.h
 STL_BOARDMAGIC      0xa2267f52  stlbrd_t             include/linux/stallion.h
diff -u --recursive --new-file v2.1.24/linux/Documentation/networking/00-INDEX linux/Documentation/networking/00-INDEX
--- v2.1.24/linux/Documentation/networking/00-INDEX	Thu Jan  2 15:55:13 1997
+++ linux/Documentation/networking/00-INDEX	Sun Feb  2 15:18:29 1997
@@ -30,6 +30,8 @@
 	- info on using DEC 21040/21041/21140 based PCI ethernet cards.
 vortex.txt
 	- info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) e'net cards.
+wan-router.txt
+	- Wan router documentation
 x25.txt
 	- general info on X.25 development.
 x25-iface.txt
diff -u --recursive --new-file v2.1.24/linux/Documentation/networking/ax25.txt linux/Documentation/networking/ax25.txt
--- v2.1.24/linux/Documentation/networking/ax25.txt	Thu Dec 12 17:02:39 1996
+++ linux/Documentation/networking/ax25.txt	Sun Feb  2 15:18:29 1997
@@ -12,7 +12,7 @@
 1	IP Default Mode		0=DG 1=VC			0
 2	AX.25 Default Mode	0=Normal 1=Extended		0
 3	Allow Vanilla Connects	0=No 1=Yes			1
-4	Backoff			0=Linear 1=Exponential		1
+4	Backoff			0=None 1=Linear 2=Exponential	1
 5	Connected Mode		0=No 1=Yes			1
 6	Standard Window		1  <= N <= 7			2
 7	Extended Window		1  <= N <= 63			32
diff -u --recursive --new-file v2.1.24/linux/Documentation/networking/cs89x0.txt linux/Documentation/networking/cs89x0.txt
--- v2.1.24/linux/Documentation/networking/cs89x0.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/networking/cs89x0.txt	Sun Feb  2 15:18:29 1997
@@ -0,0 +1,651 @@
+CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS
+Linux Network Interface Driver ver. 1.02
+===============================================================================
+ 
+
+TABLE OF CONTENTS
+
+1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS
+    1.1 Product Overview 
+    1.2 Driver Description
+	1.2.1 Driver Name
+	1.2.2 File in the Driver Package
+    1.3 System Requirements
+    1.4 Licensing Information
+
+2.0 ADAPTER INSTALLATION and CONFIGURATION
+    2.1 CS8900-based Adapter Configuration
+    2.2 CS8920-based Adapter Configuration 
+
+3.0 LOADING THE DRIVER AS A MODULE
+
+4.0 COMPILING THE DRIVER
+    4.1 Compiling the Driver As a Loadable Module
+    4.2 Compiling the Driver Into the Kernel
+    4.3 Compiling the Driver for a Linux v1.2.13 Kernel
+
+5.0 TESTING AND TROUBLESHOOTING
+    5.1 Known Defects and Limitations
+    5.2 Testing the Adapter
+        5.2.1 Diagnostic Self-Test
+        5.2.2 Diagnostic Network Test
+    5.3 Using the Adapter's LEDs
+    5.4 Resolving I/O Conflicts
+
+6.0 TECHNICAL SUPPORT
+    6.1 Contacting Crystal's Technical Support
+    6.2 Information Required Before Contacting Technical Support
+    6.3 Obtaining the Latest Driver Version
+        6.3.1 Crystal's Web Site
+        6.3.2 Crystal's Bulletin Board Service
+
+
+8.3 OBTAINING THE LATEST DRIVER VERSION
+
+You can obtain the latest CS89XX drivers and support software from Crystal's 
+BBS or Web site.
+
+
+8.3.1 CRYSTAL'S WEB SITE
+
+Crystal Semiconductor maintains a web page at http://www.crystal.com with the
+the latest drivers and technical publications.
+
+
+8.3.2 CRYSTAL'S BULLETIN BOARD SERVICE
+
+
+
+
+1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS
+===============================================================================
+
+
+1.1 PRODUCT OVERVIEW
+
+The CS8900-based ISA Ethernet Adapters from Crystal Semiconductor follow 
+IEEE 802.3 standards and support half or full-duplex operation in ISA bus 
+computers on 10 Mbps Ethernet networks.  The adapters are designed for 
+operation in 16-bit ISA or EISA bus expansion slots and are available in 
+10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5
+or fiber networks).  
+
+CS8920-based adapters are similar to the CS8900-based adapter with additional 
+features for Plug and Play (PnP) support and Wakeup Frame recognition.  As 
+such, the configuration procedures differ somewhat between the two types of 
+adapters.  Refer to the "Adapter Configuration" section for details on 
+configuring both types of adapters.
+
+
+1.2 DRIVER DESCRIPTION
+
+The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux v1.2.13 
+and v2.0 (or greater) kernels.  It can be compiled directly into the kernel or 
+loaded at run-time as a device driver module.
+
+1.2.1 Driver Name: cs89x0
+
+1.2.2 Files in the Driver Archive:
+
+  readme.txt  - this file
+  release.txt - known defects and modifcation log
+  cs89x0.c    - driver C code
+  cs89x0.h    - driver header file
+  cs89x0.o    - pre-compiled module (for v2.0 kernel)
+
+
+
+1.3 SYSTEM REQUIREMENTS
+
+The following hardware is required:
+
+   * Crystal LAN (CS8900/20-based) Ethernet ISA Adapter   
+
+   * IBM or IBM-compatible PC with:
+     * An 80386 or higher processor
+     * 16 bytes of contiguous IO space available between 210h - 370h
+     * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920).
+
+   * Appropriate cable (and connector for AUI, 10BASE-2) for your network
+     topology.
+
+The following software is required:
+
+   * LINUX kernel version 1.2.13 or 2.X
+
+   * CS8900/20 Setup Utility (DOS-based)
+
+   * LINUX kernel sources for your kernel (if compiling into kernel)
+
+   * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel 
+     or a module)   
+
+
+
+1.4 LICENSING INFORMATION
+
+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, version 1.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+more details.
+
+For a full copy of the GNU General Public License, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+
+2.0 ADAPTER INSTALLATION and CONFIGURATION
+===============================================================================
+
+Both the CS8900 and CS8920-based adapters can be configured using parameters 
+stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup 
+Utility if you want to change the adapter's configuration in EEPROM.  
+
+When loading the driver as a module, you can specify many of the adapter's 
+configuration parameters on the command-line to override the EEPROM's settings 
+or for interface configuration when an EEPROM is not used. (CS8920-based 
+adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE.
+
+Since the CS8900/20 Setup Utility is a DOS-based application, you must install 
+and configure the adapter in a DOS-based system using the CS8900/20 Setup 
+Utility before installation in the target LINUX system.  (Not required if 
+installing a CS8900-based adapter and the default configuration is acceptable.)
+     
+
+2.1 CS8900-BASED ADAPTER CONFIGURATION
+
+CS8900-based adapters shipped from Crystal Semiconductor have been configured 
+with the following "default" settings:
+
+  Operation Mode:      Memory Mode
+  IRQ:                 10
+  Base I/O Address:    300
+  Memory Base Address: D0000
+  Optimization:	       DOS Client
+  Transmission Mode:   Half-duplex
+  BootProm:            None
+  Media Type:	       Autodetect (3-media cards) or 
+                       10BASE-T (10BASE-T only adapter)
+
+You should only change the default configuration settings if conflicts with 
+another adapter exists. To change the adapter's configuration, run the 
+CS8900/20 Setup Utility. 
+
+
+2.2 CS8920-BASED ADAPTER CONFIGURATION
+
+CS8920-based adapters are shipped from Crystal Semiconductor configured as Plug
+and Play (PnP) enabled.  However, since Linux is not currently a PnP compatible 
+operating system, you must install the CS8920 adapter in a DOS-based PC and 
+run the CS8900/20 Setup Utility to disable PnP and configure the adapter before
+installation in the target Linux system.  Failure to do this will leave the 
+adapter inactive and the driver will be unable to communicate with the
+adapter.
+
+
+        **************************************************************** 
+        *                    CS8920-BASED ADAPTERS:                    *
+        *                                                              * 
+        * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT.  * 
+        * SCO UNIX IS NOT A PnP OPERATING SYSTEM. THEREFORE, YOU MUST  *
+        * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND   *
+        * TO ACTIVATE THE ADAPTER.                                     *
+        ****************************************************************
+
+
+
+
+3.0 LOADING THE DRIVER AS A MODULE
+===============================================================================
+
+If the driver is compiled as a loadable module, you can load the driver module
+with the 'insmod' command.  Many of the adapter's configuration parameters can 
+be specified as command-line arguments to the load command.  This facility 
+provides a means to override the EEPROM's settings or for interface 
+configuration when an EEPROM is not used.
+
+Example:
+
+    insmod cs89x0.o io=0x200 irq=0xA media=aui
+
+This exmaple loads the module and configures the adapter to use an IO port base
+address of 200h, interrupt 10, and use the AUI media connection.  The following
+configuration options are available on the command line:
+
+* io=###              - specify IO address (200h-360h)
+* irq=##              - specify interrupt level
+* mmode=#####         - specify memory base address
+* dma=#               - specify dma channel
+* media=rj45          - specify media type
+   or media=2
+   or media=aui
+   or medai=auto
+* duplex=f            - specify forced half/full/autonegotiate duplex
+   or duplex=h
+   or duplex=auto
+* debug=#             - debug level
+
+NOTES:
+* If an EEPROM is present, any specified command-line parameter will override
+the corresponding configuration value stored in EEPROM.
+
+* If no "io" or "mmode" parameter is specified on the command-line, the driver
+will scan for the adapter.  When scanning, the driver only reads I/O ports.  
+This sometimes is not sufficient, (e.g. after a warm boot).  If you wish to 
+allow the driver to perform a more aggressive scan (one write to the IO base 
+addresses to reset the data port pointer) you can specify an I/O address with 
+an address value one greater than the configured address.  Example, to scan for
+an adapter located at IO base 0x300, specify an IO address of 0x301.  Only 
+ports between 200h and 360h at 20h intervals are scanned.  
+
+* The "duplex=auto" parameter is only supported for the CS8920.
+
+* The minimum command-line configuration required if an EEPROM is not present
+is:
+
+  * io or mmode base address
+  * irq 
+  * media type (no autodetect)
+
+The following addtional parameters are CS89XX defaults (values used with no 
+EEPROM or command-line argument).
+
+  * DMA Burst = enabled
+  * IOCHRDY Enabled = enabled
+  * UseSA = enabled
+  * CS8900 defaults to half-duplex if not specified on command-line
+  * CS8920 defaults to autoneg if not specified on command-line
+  * Use reset defaults for other config parameters
+
+* You can use ifconfig to set the adapter's Ethernet address.
+
+
+
+
+4.0 COMPILING THE DRIVER
+===============================================================================
+
+The cs89x0 driver can be compiled directly into the kernel or compiled into
+a loadable device driver module.
+
+NOTE: This part of the description relates to adding the driver to a kernel
+not containing the cs89x0 driver. This kernel already contains it.
+
+4.1 COMPILING THE DRIVER AS A LOADABLE MODULE
+
+To compile the driver into a loadable module, use the following command 
+(single command line, without quotes):
+
+"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall 
+-Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS 
+-c cs89x0.c"
+
+
+4.2 COMPILING THE DRIVER INTO THE KERNEL
+
+To compile the driver directly into the kernel requires editing four 
+configuration files, copying the source file to the /linux/drivers/net
+directory and then running the make utility to rebuild the kernel.
+
+1. Edit the following configuration files by adding the statements as
+indicated.  (When possible, try to locate the added text to the section of the
+file containing similar statements).
+
+a.) In /usr/src/linux/drivers/net/CONFIG, add
+
+CS89x0_OPTS   =
+
+Example:
+
+ WD_OPTS	= #-DWD_SHMEM=0xDD000
+ EL2_OPTS	= #-DEL2_AUI
+ CS89x0_OPTS	=                
+ NE_OPTS	=
+ HP_OPTS	=
+ PLIP_OPTS	=
+
+
+b.) In /usr/src/linux/drivers/net/Config.in, add:
+
+tristate 'CS89x0 support' CONFIG_CS89x0
+
+Example:
+
+     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+       tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
+     fi
+
+     tristate 'CS89x0 support' CONFIG_CS89x0
+
+     tristate 'NE2000/NE1000 support' CONFIG_NE2000
+     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+       tristate 'NI5210 support' CONFIG_NI52
+
+
+c.) In /usr/src/linux/drivers/net/Makefile, add the following lines: 
+
+ifeq ($(CONFIG_CS89x0),y)
+L_OBJS += cs89x0.o
+else
+  ifeq ($(CONFIG_CS89x0),m)
+  M_OBJS += cs89x0.o
+  endif
+endif
+
+
+d.) In /linux/drivers/net/Space.c file, add the line:
+
+extern int cs89x0_probe(struct device *dev);
+
+
+Example:
+
+ extern int ultra_probe(struct device *dev);
+ extern int wd_probe(struct device *dev);
+ extern int el2_probe(struct device *dev);
+
+ extern int cs89x0_probe(struct device *dev);
+
+ extern int ne_probe(struct device *dev);
+ extern int hp_probe(struct device *dev);
+ extern int hp_plus_probe(struct device *dev);
+
+
+Also add:
+
+ #ifdef CONFIG_CS89x0
+ 	&& cs89x0_probe(dev)
+ #endif
+
+
+2.) Copy the driver source files (cs89x0.c and cs89x0.h) and this README file 
+into the /usr/src/linux/drivers/net directory.
+
+
+3.) Run 'make config' followed by 'make dep' and finally 'make' to rebuild 
+the kernel. 
+
+
+4.3 COMPILING THE DRIVER FOR A LINUX v1.2.13 KERNEL
+
+To compile the driver for Linux v1.2.13 (into the kernel or as a module), 
+change the "SUPPORTS" define at the beginning of the cs89x0.c file.  
+Example:
+
+#define SUPPORTS_1_2_13 1   /* supports Linux kernel v1.2.13 */
+   or
+#define SUPPORTS_1_2_13 0   /* supports Linux kernel v2.0 (default) */
+
+
+
+5.0 TESTING AND TROUBLESHOOTING
+===============================================================================
+
+5.1 KNOWN DEFECTS and LIMITATIONS
+
+Refer to the RELEASE.TXT file distributed as part of this archive for a list of 
+know defects, driver limitations, and work arounds.
+
+
+5.2 TESTING THE ADAPTER
+
+Once the adapter has been installed and configured, the diagnostic option of 
+the CS8900/20 Setup Utility can be used to test the functionality of the 
+adapter and its network connection.  Use the diagnostics 'Self Test' option to
+test the functionality of the adapter with the hardware configuration you have
+assigned. You can use the diagnostics 'Network Test' to test the ability of the
+adapter to communicate across the Ethernet with another PC equipped with a 
+CS8900/20-based adapter card (it must also be running the CS8900/20 Setup 
+Utility).
+
+         NOTE: The Setup Utility's diagnostics are designed to run in a
+         DOS-only operating system environment.  DO NOT run the diagnostics 
+         from a DOS or command prompt session under Windows 95, Windows NT, 
+         OS/2, or other operating system.
+
+	[AC - Question : Do they work in DOSEMU ?]
+
+To run the diagnostics tests on the CS8900/20 adapter:
+
+   1.) Boot DOS on the PC and start the CS8900/20 Setup Utility.
+
+   2.) The adapter's current configuration is displayed.  Hit the ENTER key to
+       get to the main menu.
+
+   4.) Select 'Diagnostics' (ALT-G) from the main menu.  
+       * Select 'Self-Test' to test the adapter's basic functionality.
+       * Select 'Network Test' to test the network connection and cabling.
+
+
+5.2.1 DIAGNOSTIC SELF-TEST
+
+The diagnostic self-test checks the adapter's basic functionality as well as 
+its ability to communicate across the ISA bus based on the system resources 
+assigned during hardware configuration.  The following tests are performed:
+
+   * IO Register Read/Write Test
+     The IO Register Read/Write test insures that the CS8900/20 can be 
+     accessed in IO mode, and that the IO base address is correct.
+
+   * Shared Memory Test
+     The Shared Memory test insures the CS8900/20 can be accessed in memory 
+     mode and that the range of memory addresses assigned does not conflict 
+     with other devices in the system.
+
+   * Interrupt Test
+     The Interrupt test insures there are no conflicts with the assigned IRQ
+     signal.
+
+   * EEPROM Test
+     The EEPROM test insures the EEPROM can be read.
+
+   * Chip RAM Test
+     The Chip RAM test insures the 4K of memory internal to the CS8900/20 is
+     working properly.
+
+   * Internal Loop-back Test
+     The Internal Loop Back test insures the adapter's transmitter and 
+     receiver are operating properly.  If this test fails, make sure the 
+     adapter's cable is connected to the network (check for LED activity for 
+     example).
+
+   * Boot PROM Test
+     The Boot PROM  test insures the Boot PROM is present, and can be read.
+     Failure indicates the Boot PROM  was not successfully read due to a
+     hardware problem or due to a conflicts on the Boot PROM address
+     assignment. (Test only applies if the adapter is configured to use the
+     Boot PROM option.)
+
+Failure of a test item indicates a possible system resource conflict with 
+another device on the ISA bus.  In this case, you should use the Manual Setup 
+option to reconfigure the adapter by selecting a different value for the system
+resource that failed.
+
+
+5.2.2 DIAGNOSTIC NETWORK TEST
+
+The Diagnostic Network Test verifies a working network connection by 
+transferring data between two CS8900/20 adapters installed in different PCs 
+on the same network. (Note: the diagnostic network test should not be run 
+between two nodes across a router.) 
+
+This test requires that each of the two PCs have a CS8900/20-based adapter
+installed and have the CS8900/20 Setup Utility running.  The first PC is 
+configured as a Responder and the other PC is configured as an Initiator.  
+Once the Initiator is started, it sends data frames to the Responder which 
+returns the frames to the Initiator.
+
+The total number of frames received and transmitted are displayed on the 
+Initiator's display, along with a count of the number of frames received and 
+transmitted OK or in error.  The test can be terminated anytime by the user at 
+either PC.
+
+To setup the Diagnostic Network Test:
+
+    1.) Select a PC with a CS8900/20-based adapter and a known working network
+        connection to act as the Responder.  Run the CS8900/20 Setup Utility 
+        and select 'Diagnostics -> Network Test -> Responder' from the main 
+        menu.  Hit ENTER to start the Responder.
+
+    2.) Return to the PC with the CS8900/20-based adapter you want to test and
+        start the CS8900/20 Setup Utility. 
+
+    3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'.
+        Hit ENTER to start the test.
+ 
+You may stop the test on the Initiator at any time while allowing the Responder
+to continue running.  In this manner, you can move to additional PCs and test 
+them by starting the Initiator on another PC without having to stop/start the 
+Responder.
+ 
+
+
+5.3 USING THE ADAPTER'S LEDs
+
+The 2 and 3-media adapters have two LEDs visible on the back end of the board 
+located near the 10Base-T connector.  
+
+Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T 
+connection.  (Only applies to 10Base-T.  The green LED has no significance for
+a 10Base-2 or AUI connection.)
+
+TX/RX LED: The yellow LED lights briefly each time the adapter transmits or 
+receives data. (The yellow LED will appear to "flicker" on a typical network.)
+
+
+5.4 RESOLVING I/O CONFLICTS
+
+An IO conflict occurs when two or more adapter use the same ISA resource (IO 
+address, memory address or IRQ).  You can usually detect an IO conflict in one 
+of four ways after installing and or configuring the CS8900/20-based adapter:
+
+    1.) The system does not boot properly (or at all).
+
+    2.) The driver can not communicate with the adapter, reporting an "Adapter
+        not found" error message.
+
+    3.) You cannot connect to the network or the driver will not load.
+
+    4.) If you have configured the adapter to run in memory mode but the driver
+        reports it is using IO mode when loading, this is an indication of a
+        memory address conflict.
+
+If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a 
+diagnostic self-test.  Normally, the ISA resource in conflict will fail the 
+self-test.  If so, reconfigure the adapter selecting another choice for the 
+resource in conflict.  Run the diagnostics again to check for further IO 
+conflicts.
+
+In some cases, such as when the PC will not boot, it may be necessary to remove
+the adapter and reconfigure it by installing it in another PC to run the 
+CS8900/20 Setup Utility.  Once reinstalled in the target system, run the 
+diagnostics self-test to ensure the new configuration is free of conflicts 
+before loading the driver again.
+
+When manually configuring the adapter, keep in mind the typical ISA system 
+resource usage as indicated in the tables below.
+
+I/O Address    	Device                        IRQ      Device
+-----------    	--------                      ---      --------
+ 200-20F       	Game I/O adapter               3       COM2, Bus Mouse
+ 230-23F       	Bus Mouse                      4       COM1
+ 270-27F       	LPT3: third parallel port      5       LPT2
+ 2F0-2FF       	COM2: second serial port       6       Floppy Disk controller
+ 320-32F       	Fixed disk controller          7       LPT1
+                                      	       8       Real-time Clock
+                                               9       EGA/VGA display adapter    
+                                              12       Mouse (PS/2)                              
+Memory Address  Device                        13       Math Coprocessor
+--------------  ---------------------         14       Hard Disk controller
+A000-BFFF	EGA Graphics Adpater
+A000-C7FF	VGA Graphics Adpater
+B000-BFFF	Mono Graphics Adapter
+B800-BFFF	Color Graphics Adapter
+E000-FFFF	AT BIOS
+
+
+
+
+6.0 TECHNICAL SUPPORT
+===============================================================================
+
+6.1 CONTACTING CRYSTAL'S TECHNICAL SUPPORT
+
+Crystal's CS89XX Technical Application Support can be reached at:
+
+Telephone  :(800) 888-5016 (from inside U.S. and Canada)
+           :(512) 442-7555 (from outside the U.S. and Canada)
+Fax	   :(512) 912-3871
+Email	   :ethernet@crystal.cirrus.com
+WWW        :http://www.crystal.com
+
+
+6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT
+
+Before contacting Crystal for technical support, be prepared to provide as much
+of the following information as possible. 
+
+1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.)
+
+2.) Adapter configuration
+
+    * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel
+    * Plug and Play enabled/disabled (CS8920-based adapters only)
+    * Configured for media auto-detect or specific media type (which type).    
+
+3.) PC System's Configuration
+
+    * Plug and Play system (yes/no)
+    * BIOS (make and version)
+    * System make and model
+    * CPU (type and speed)
+    * System RAM
+    * SCSI Adapter
+
+4.) Software
+
+    * CS89XX driver and version
+    * Your network operating system and version
+    * Your system's OS version 
+    * Version of all protocol support files
+
+5.) Any Error Message displayed.
+
+
+
+6.3 OBTAINING THE LATEST DRIVER VERSION
+
+You can obtain the latest CS89XX drivers and support software from Crystal's 
+BBS or Web site.  You can also contact Crystal's Technical Support (email:
+ethernet@crystal.cirrus.com) and request that you be registered for automatic 
+software-update notification.
+
+
+6.3.1 CRYSTAL'S WEB SITE
+
+Crystal Semiconductor maintains a web page at http://www.crystal.com with the
+the latest drivers and technical publications.
+
+
+6.3.2 CRYSTAL'S BULLETIN BOARD SERVICE
+
+Access to the BBS is available 24 hours a day, seven days a week. Baud 
+rates from 300K to 14.4K are supported as well as most common file transfer 
+protocols.  
+
+To access the BBS, set your terminal software to use 8 data bits, 1 stop bit, 
+and no parity.  Dial (512) 441-3265 and press <ENTER> after connection is made.
+Login using your account name and password.  (If you do not have an account, 
+you may login as "GUEST".  No password is required for the Guest account.)
+
+From the main system menu, select the "Enter Public File Area" menu option.  
+From the Public File Area menu, select the "LAN (Local Area Network)" file
+area.  A list of the latest drivers and support utilities available for the
+CS89XX ISA Ethernet adapter will be presented along with the option to download
+the file(s) of your choice.
+
+
diff -u --recursive --new-file v2.1.24/linux/Documentation/networking/wan-router.txt linux/Documentation/networking/wan-router.txt
--- v2.1.24/linux/Documentation/networking/wan-router.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/networking/wan-router.txt	Sun Feb  2 15:18:29 1997
@@ -0,0 +1,130 @@
+------------------------------------------------------------------------------
+WAN Router for Linux Operating System
+------------------------------------------------------------------------------
+Version 1.0.0
+December 31, 1996
+Author: Gene Kozin <genek@compuserve.com>
+Copyright (c) 1995-1996 Sangoma Technologies Inc.
+------------------------------------------------------------------------------
+
+INTRODUCTION
+
+Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs)
+and/or stand-alone hosts over vast distances with data transfer rates
+significantly higher than those achievable with commonly used dial-up
+connections.
+
+Usually an external device called `WAN router' sitting on your local network
+or connected to your machine's serial port provides physical connection to
+WAN.  Although router's job may be as simple as taking your local network
+traffic, converting it to WAN format and piping it through the WAN link, these
+devices are notoriously expensive, with prices as much as 2 - 5 times higher
+then the price of a typical PC box.
+
+Alternatively, considering robustness and multitasking capabilities of Linux,
+an internal router can be build (most routers use some sort of stripped down
+Unix-like operating system anyway).  With number of relatively inexpensive WAN
+interface cards available on the market, a perfectly usable router can be
+built for less than half a price of an external router.  Yet a Linux box
+acting as a router can still be used for other purposes, such as firewalling,
+running FTP, WWW or DNS server, etc.
+
+This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux
+operating system and provides generic hardware-independent services for such
+drivers.  Why existing Linux network device interface can not be used for
+this purpose?  Well, it can.  However, there are few key differences between
+typical network interface (i.e. ethernet) and WAN link.
+
+Many WAN protocols, such as X.25 and frame relay, allow for multiple logical
+connections (known as `virtual circuits' in X.25 terminology) over a single
+physical link.  Each such virtual circuit may (and almost always does) lead
+to diffrent geographical location and, therefore, different network.  As a
+result, it is the virtual circuit, not the physical link, that represents a
+route and, therefore, a network interface in Linux terms.
+
+To further complicate things, virtual cuircits are usually volatile in nature
+(excluding so called `permanent' virtual circuits or PVCs).  With almost no
+time required to set up and tear down virtual circuit, it is highly desirable
+to implement on-demand connections in order to minimize network charges.  So
+unlike typical network driver, the WAN driver must be able to handle multiple
+network interfaces and cope with multiple virtual circuits come into existance
+and go away dynamically.
+ 
+Last, but not least, WAN configuration is much more complex than that of say
+ethernet and may well amount to several dozens of parameters.  Some of them
+are "link-wide"  while others are virtual circuit-specific.  The same holds
+true for WAN statistics which is by far more extensive and extremely useful
+when troubleshooting WAN connections.  Extending ifconfig utility to suite
+these needs may be possible, but does not seem quite reasonable.  Therefore, a
+WAN configuration utility and corresponding application programmer's interface
+is needed for this purpose.
+
+Most of these problems are taken care of by this module.  It's goal is to
+provide user with more-or-less standard look and feel for all WAN devices and
+assist WAN device driver writer by providing common services, such as:
+
+ o User-level interface via /proc filesystem
+ o Centralized configuration
+ o Device managenent (setup, shutdown, etc.)
+ o Network interface management (dynamic creation/destruction)
+ o Protocol encapsulation/decapsulation
+
+To ba able to use Linux WAN Router you will also need a WAN Tools package
+available from
+
+	ftp.sangoma.com/pub/linux/wantools-X.Y.Z.tgz
+
+For technical questions and/or comments regarding this product please e-mail
+to genek@compuserve.com or dm@sangoma.com.
+
+
+
+COPYRIGHT AND LICENSING INFORMATION
+
+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, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+
+
+
+KNOWN BUGS AND LIMITATIONS
+
+/proc user interface is not complete yet.
+
+
+
+ACKNOLEGEMENTS
+
+This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed
+by Sangoma Technologies Inc. for Linux 1.2.x.  Release of Linux 2.0 in summer
+1996 commanded adequate changes to the WANPIPE code to take full advantage of
+new Linux features.  Instead of continuing developing proprietory interface
+specific to Sangoma WAN cards, we decided to put all hardware-independent code
+into a separate module and define two levels of interfaces - one for user-
+level applications and another for kernel-level WAN drivers.
+
+Many usefull ideas concerning hardware-independent interface implementation
+were given by Mike McLagan <mike.mclagan@linux.org> and his implementation
+of the Frame Relay router and drivers for Sangoma cards (dlci/sdla).
+
+Special thanks to all the WANPIPE users who performed field-testing, reported
+bugs and made valuable comments and suggestions that help us to improve this
+product.
+
+
+
+REVISION HISTORY
+
+1.0.0	 December 31, 1996
+--------------------------
+ o Initial version.
+
+>>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
diff -u --recursive --new-file v2.1.24/linux/Documentation/serial-console.txt linux/Documentation/serial-console.txt
--- v2.1.24/linux/Documentation/serial-console.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/serial-console.txt	Sun Feb  2 15:18:29 1997
@@ -0,0 +1,78 @@
+                       Linux Serial Console
+
+These examples are valid if you want to use /dev/ttyS1 (COM2)
+as the serial console. Replace as needed.
+
+1. Tell LILO to use the serial port.
+   In lilo.conf (global section): 
+
+   serial  = 1,9600n8 (ttyS1, 9600 bd, no parity, 8 bits)
+
+2. Adjust to kernel flags for the new kernel,
+   again in lilo.conf (kernel section)
+
+   append = "console=1,9600,n8" 
+
+   (Note the extra comma needed if you want to supply parity/framing 
+   information.)
+
+3. Link /dev/console to the serial port.
+
+   Your probably want to save your old /dev/console (the "master" virtual
+   console). Check if it is a symbolic link first. If not, `mv' it to
+   `/dev/tty0':
+
+   ls -l /dev/console
+   mv /dev/console /dev/tty0
+
+   Now link the serial port you are going to use as the console to
+   /dev/console, for example ttyS1:
+
+   ln -s /dev/ttyS1 /dev/console
+
+   On some systems you might want to edit your bootup scripts to make sure
+   they don't reset this arrangement on boot. (On Debian, check
+   /etc/rc.boot/console and /etc/default/console). You probably also want
+   to put a getty on either /dev/console or /dev/ttyS1.
+
+4. Init and /dev/console.
+   Sysvinit will open /dev/console on boot. If this does not point
+   to the serial console device, the startup messages will be printed
+   to the wrong device. The kernel also passes the environment variable
+   "CONSOLE" to the init program. sysvinit-2.64 reckognizes this, and
+   opens that device instead. Boot scripts as mentioned in (3) can
+   also check this variable to see what device the system console is.
+   If CONSOLE is not set you can assume the console is /dev/tty0.
+
+   Sysvinit remembers its stty settings in a file in /etc, called
+   `/etc/ioctl.save'. REMOVE THIS FILE before using the serial
+   console for the first time, because otherwise init will probably
+   set the baudrate to 38400 (bausdrate of the virtual console).
+
+5. /dev/console and X
+   Programs that want to do something with the virtual console usually
+   open /dev/console. XF86 does this, and probably SVGALIB as well.
+   IMO this is wrong; they should open /dev/tty0.
+   I have binary patched /usr/bin/X11/XF86_SVGA to use "tty0"
+   instead of "console".
+
+6. Notes.
+
+   If you compile the next little program, you will be able
+   to really "halt" the system. It will enter a little
+   monitor :)
+
+   main() { reboot(0xfee1dead, 672274793, 0xCDEF0123); }
+
+   This is just a call to the new "halt" function that later
+   kernels have. This is included the "halt" command of
+   the recent sysvinit versions.
+
+   The monitor will also be entered at a kernel panic, or
+   when you press "break". That last function does not
+   work at the moment I think, but it would be useful for
+   kernel debugging.  You don't have alt-scrollock on a serial
+   console to find out the current EIP...
+
+Miquel van Smoorenburg <miquels@cistron.nl>, 21-Jun-1996
+Stephen C. Tweedie <sct@dcs.ed.ac.uk>, 23-Dec-1996
diff -u --recursive --new-file v2.1.24/linux/Documentation/smp linux/Documentation/smp
--- v2.1.24/linux/Documentation/smp	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/smp	Sun Feb  2 15:18:29 1997
@@ -0,0 +1,23 @@
+To set up SMP
+
+Edit linux/Makefile and uncomment SMP=1, then compile and install
+as usual.
+
+If you are using LILO, it is handy to have both SMP and non-SMP
+kernel images on hand. Edit /etc/lilo.conf to create an entry
+for another kernel image called "linux-smp" or something.
+
+The next time you compile the kernel, when running a SMP kernel,
+edit linux/Makefile and change "MAKE=make" "MAKE=make -jN"
+(where N = number of CPU + 1, or if you have tons of memory/swap
+ you can just use "-j" without a number). Feel free to experiment
+with this one.
+
+Of course you should time how long each build takes :-)
+Example:
+   make config
+   time -v sh -c 'make dep ; make clean install modules modules_install'
+
+If you are using some Compaq MP compliant machines you will need to set
+the operating system in the BIOS settings to "Unixware" - don't ask me
+why Compaq's dont work otherwise.
diff -u --recursive --new-file v2.1.24/linux/Documentation/watchdog.txt linux/Documentation/watchdog.txt
--- v2.1.24/linux/Documentation/watchdog.txt	Thu Jan 23 21:06:45 1997
+++ linux/Documentation/watchdog.txt	Sun Feb  2 15:18:30 1997
@@ -87,6 +87,8 @@
 9950 Barnes Canyon Road 
 San Diego, CA     
 
+http://www.industry.net/indcompsrc
+
 and please mention Linux when enquiring.
 
 For full information about the PCWD cards see the pcwd-watchdog.txt document.
diff -u --recursive --new-file v2.1.24/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.24/linux/MAINTAINERS	Sun Feb  2 15:46:19 1997
+++ linux/MAINTAINERS	Sun Feb  2 15:18:30 1997
@@ -277,6 +277,13 @@
 W:	http://mosquitonet.Stanford.EDU/strip.html
 S:	Maintained
 
+WAN ROUTER AND SANGOMA WANPIPE DRIVERS (X.25, FRAME RELAY, PPP)
+P:     Gene Kozin
+M:     genek@compuserve.com
+M:     dm@sangoma.com
+W:     http://www.sangoma.com
+S:     Supported
+
 SMB FILESYSTEM:
 P:	Volker Lendecke
 M:	lendecke@namu01.Num.Math.Uni-Goettingen.de
diff -u --recursive --new-file v2.1.24/linux/Makefile linux/Makefile
--- v2.1.24/linux/Makefile	Sun Feb  2 15:46:19 1997
+++ linux/Makefile	Wed Jan 29 13:32:27 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 24
+SUBLEVEL = 25
 
 ARCH = i386
 
diff -u --recursive --new-file v2.1.24/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v2.1.24/linux/arch/alpha/kernel/bios32.c	Tue Jan 28 18:49:45 1997
+++ linux/arch/alpha/kernel/bios32.c	Sun Feb  2 15:00:34 1997
@@ -24,6 +24,7 @@
  * within the United States, $35 abroad.
  */
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 
@@ -50,7 +51,6 @@
 
 #else /* CONFIG_PCI */
 
-#include <linux/kernel.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/malloc.h>
diff -u --recursive --new-file v2.1.24/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.1.24/linux/arch/alpha/kernel/traps.c	Tue Jan 28 18:49:46 1997
+++ linux/arch/alpha/kernel/traps.c	Sun Feb  2 15:00:46 1997
@@ -426,13 +426,13 @@
 	exp = (exp_msb << 10) | exp_low;	/* common case */
 	if (exp_msb) {
 		if (exp_low == 0x7f) {
-			exp = 0x3ff;
+			exp = 0x7ff;
 		}
 	} else {
 		if (exp_low == 0x00) {
 			exp = 0x000;
 		} else {
-			exp |= (0x7 << 8);
+			exp |= (0x7 << 7);
 		}
 	}
 	return (sign << 63) | (exp << 52) | (frac << 29);
diff -u --recursive --new-file v2.1.24/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.1.24/linux/arch/i386/boot/setup.S	Thu Jan 23 21:06:46 1997
+++ linux/arch/i386/boot/setup.S	Sun Feb  2 15:18:30 1997
@@ -240,6 +240,16 @@
 	push	ax
 	push	cx
 	push	dx
+				! which bootloader ?
+	seg cs
+	mov	al,byte ptr type_of_loader
+	and	al,#0xf0
+	cmp	al,#0x10
+	jne	try_xe801	! not Loadlin
+	seg cs
+	cmp	byte ptr type_of_loader,#0x16
+	jbe	oldstylemem	! Loadlin <= 1.6 don't like that
+try_xe801:
 	mov	ax,#0xe801
 	int	0x15
 	jc	oldstylemem
@@ -257,6 +267,9 @@
 oldstylemem:
 	mov	ah,#0x88
 	int	0x15
+	or	ax,ax		! some BIOSes report ZERO for 64meg
+	mov	word ptr [2],#0x400
+	jz	gotmem
 	mov	cx,#64		! got memory size in kbytes, so we need to
 	xor	dx,dx		! adjust to 64k chunks for the system.
 	div	cx
diff -u --recursive --new-file v2.1.24/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.1.24/linux/arch/i386/kernel/setup.c	Thu Jan 23 21:06:46 1997
+++ linux/arch/i386/kernel/setup.c	Sun Feb  2 15:18:30 1997
@@ -235,7 +235,8 @@
 static const char * i586model(unsigned int nr)
 {
 	static const char *model[] = {
-		"0", "Pentium 60/66","Pentium 75+","OverDrive PODP5V83"
+		"0", "Pentium 60/66","Pentium 75+","OverDrive PODP5V83",
+		"Pentium MMX"
 	};
 	if (nr < sizeof(model)/sizeof(char *))
 		return model[nr];
diff -u --recursive --new-file v2.1.24/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.24/linux/arch/i386/kernel/smp.c	Sun Feb  2 15:46:19 1997
+++ linux/arch/i386/kernel/smp.c	Sun Feb  2 15:18:30 1997
@@ -22,6 +22,7 @@
  *	Matthias Sattler	:	Changes for 2.1 kernel map.
  *	Michel Lespinasse	:	Changes for 2.1 kernel map.
  *	Michael Chastain	:	Change trampoline.S to gnu as.
+ *		Alan Cox	:	Dumb bug: 'B' step PPro's are fine
  *
  */
 
@@ -573,8 +574,11 @@
 	c->x86=x86;
 	c->x86_model=x86_model;
 	c->x86_mask=x86_mask;
-	if(x86_mask>=1 && x86_mask<=4)
-		smp_b_stepping=1;		/* Remember we have B step CPUs */
+	/*
+	 *	Mask B, Pentium, but not Pentium MMX
+	 */
+	if(x86_mask>=1 && x86_mask<=4 && x86==5 && (x86_model>=0&&x86_model<=3))
+		smp_b_stepping=1;		/* Remember we have B step Pentia with bugs */
 	c->x86_capability=x86_capability;
 	c->fdiv_bug=fdiv_bug;
 	c->wp_works_ok=wp_works_ok;		/* Always assumed the same currently */
diff -u --recursive --new-file v2.1.24/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v2.1.24/linux/arch/i386/kernel/vm86.c	Tue Jan 28 18:49:47 1997
+++ linux/arch/i386/kernel/vm86.c	Sun Feb  2 15:18:30 1997
@@ -427,34 +427,26 @@
 	return_to_32bit(regs, VM86_INTx + (i << 8));
 }
 
-
-
+/* This must be called with the kernel lock held. */
 int handle_vm86_trap(struct kernel_vm86_regs * regs, long error_code, int trapno)
 {
-	int ret;
-
-	lock_kernel();
 	if (VMPI.is_vm86pus) {
 		if ( (trapno==3) || (trapno==1) )
 			return_to_32bit(regs, VM86_TRAP + (trapno << 8));
 		do_int(regs, trapno, (unsigned char *) (regs->ss << 4), SP(regs));
-		ret = 1;
-		goto out;
+		return  1;
 	}
-	ret = 0;
 	if (trapno !=1)
-		goto out; /* we let this handle by the calling routine */
+		return 0; /* we let this handle by the calling routine */
 	if (current->flags & PF_PTRACED)
 		current->blocked &= ~(1 << (SIGTRAP-1));
 	send_sig(SIGTRAP, current, 1);
 	current->tss.trap_no = trapno;
 	current->tss.error_code = error_code;
-out:
-	unlock_kernel();
-	return ret;
+	return 0;
 }
 
-
+/* This must be called with the kernel lock held. */
 void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code)
 {
 	unsigned char *csp, *ssp;
@@ -466,9 +458,8 @@
 #define VM86_FAULT_RETURN \
 	if (VMPI.force_return_for_pic  && (VEFLAGS & IF_MASK)) \
 		return_to_32bit(regs, VM86_PICRETURN); \
-	goto out;
+	return;
 	                                   
-	lock_kernel();
 	csp = (unsigned char *) (regs->cs << 4);
 	ssp = (unsigned char *) (regs->ss << 4);
 	sp = SP(regs);
@@ -532,7 +523,7 @@
 				return_to_32bit(regs, VM86_INTx + (intno << 8));
 		}
 		do_int(regs, intno, ssp, sp);
-		goto out;
+		return;
 	}
 
 	/* iret */
@@ -565,8 +556,6 @@
 	default:
 		return_to_32bit(regs, VM86_UNKNOWN);
 	}
-out:
-	unlock_kernel();
 }
 
 /* ---------------- vm86 special IRQ passing stuff ----------------- */
diff -u --recursive --new-file v2.1.24/linux/arch/i386/lib/checksum.c linux/arch/i386/lib/checksum.c
--- v2.1.24/linux/arch/i386/lib/checksum.c	Thu Dec 12 19:36:58 1996
+++ linux/arch/i386/lib/checksum.c	Sun Feb  2 15:18:30 1997
@@ -11,6 +11,9 @@
  *		Lots of code moved from tcp.c and ip.c; see those files
  *		for more names.
  *
+ * Changes:     Ingo Molnar, converted csum_partial_copy() to 2.1 exception
+ *			     handling.
+ *
  *		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
@@ -86,7 +89,7 @@
 	    shll $16,%%ecx
 5:	    movb (%%esi),%%cl
 6:	    addl %%ecx,%%eax
-	    adcl $0, %%eax
+	    adcl $0, %%eax 
 7:	    "
 	: "=a"(sum)
 	: "0"(sum), "c"(len), "S"(buff)
@@ -94,96 +97,228 @@
 	return(sum);
 }
 
+/*
+ * Copy from ds while checksumming, otherwise like csum_partial
+ *
+ * The macros SRC and DST specify wether there should be exception handling
+ * for the source and/or the destination addresses.
+ *
+ * FIXME: could someone double check wether i havent mixed up some SRC and
+ *	  DST definitions? It's damn hard to trigger all cases, i hope i got
+ *	  them all but theres no guarantee ...
+ */
 
+#define csum_partial_copy_type(type) \
+unsigned int csum_partial_copy ##type (int * __csum_err, const char *src, char *dst,   \
+				  int len, int sum) {  \
+    __asm__( 									  \
+"		testl $2, %%edi		# Check alignment. 			\n" \
+"		jz 2f			# Jump if alignment is ok. 		\n" \
+"		subl $2, %%ecx		# Alignment uses up two bytes. 		\n" \
+"		jae 1f			# Jump if we had at least two bytes. 	\n" \
+"		addl $2, %%ecx		# ecx was < 2.  Deal with it. 		\n" \
+"		jmp 4f 								\n" \
+"	1000: 									\n" \
+"	 1:	movw (%%esi), %%bx						\n" \
+"		addl $2, %%esi							\n" \
+"	1001:									\n" \
+"		movw %%bx, (%%edi)						\n" \
+"		addl $2, %%edi							\n" \
+"		addw %%bx, %%ax							\n" \
+"		adcl $0, %%eax							\n" \
+"	2:									\n" \
+"		pushl %%ecx							\n" \
+"		shrl $5, %%ecx							\n" \
+"		jz 2f								\n" \
+"		testl %%esi, %%esi						\n" \
+"	1002:									\n" \
+"	1:	movl (%%esi), %%ebx						\n" \
+"	1003:									\n" \
+"		movl 4(%%esi), %%edx						\n" \
+"		adcl %%ebx, %%eax						\n" \
+"	1004:									\n" \
+"		movl %%ebx, (%%edi)						\n" \
+"		adcl %%edx, %%eax						\n" \
+"	1005:									\n" \
+"		movl %%edx, 4(%%edi)						\n" \
+"	 									\n" \
+"	1006:									\n" \
+"		movl 8(%%esi), %%ebx						\n" \
+"	1007:									\n" \
+"		movl 12(%%esi), %%edx						\n" \
+"		adcl %%ebx, %%eax						\n" \
+"	1008:									\n" \
+"		movl %%ebx, 8(%%edi)						\n" \
+"		adcl %%edx, %%eax						\n" \
+"	1009:									\n" \
+"		movl %%edx, 12(%%edi)						\n" \
+"	 									\n" \
+"	1010: 									\n" \
+"		movl 16(%%esi), %%ebx 						\n" \
+"	1011: 									\n" \
+"		movl 20(%%esi), %%edx						\n" \
+"		adcl %%ebx, %%eax						\n" \
+"	1012:									\n" \
+"		movl %%ebx, 16(%%edi)						\n" \
+"		adcl %%edx, %%eax						\n" \
+"	1013:									\n" \
+"		movl %%edx, 20(%%edi)						\n" \
+"										\n" \
+"	1014:									\n" \
+"		movl 24(%%esi), %%ebx						\n" \
+"	1015:									\n" \
+"		movl 28(%%esi), %%edx						\n" \
+"		adcl %%ebx, %%eax						\n" \
+"	1016:									\n" \
+"		movl %%ebx, 24(%%edi)						\n" \
+"		adcl %%edx, %%eax						\n" \
+"	1017:									\n" \
+"		movl %%edx, 28(%%edi)						\n" \
+"	 									\n" \
+"	1018:									\n" \
+"		lea 32(%%esi), %%esi						\n" \
+"	1019:									\n" \
+"		lea 32(%%edi), %%edi						\n" \
+"		dec %%ecx							\n" \
+"		jne 1b								\n" \
+"		adcl $0, %%eax							\n" \
+"	2:	popl %%edx							\n" \
+"		movl %%edx, %%ecx						\n" \
+"		andl $0x1c, %%edx						\n" \
+"		je 4f								\n" \
+"		shrl $2, %%edx		# This clears CF			\n" \
+"	1020:									\n" \
+"	3:	movl (%%esi), %%ebx						\n" \
+"		adcl %%ebx, %%eax						\n" \
+"	1021:									\n" \
+"		movl %%ebx, (%%edi)						\n" \
+"	1022:									\n" \
+"		lea 4(%%esi), %%esi						\n" \
+"	1023:									\n" \
+"		lea 4(%%edi), %%edi						\n" \
+"		dec %%edx							\n" \
+"		jne 3b								\n" \
+"		adcl $0, %%eax							\n" \
+"	4:	andl $3, %%ecx							\n" \
+"		jz 7f								\n" \
+"		cmpl $2, %%ecx							\n" \
+"		jb 5f								\n" \
+"	1024:									\n" \
+"		movw (%%esi), %%cx						\n" \
+"	1025:									\n" \
+"		leal 2(%%esi), %%esi						\n" \
+"	1026:									\n" \
+"		movw %%cx, (%%edi)						\n" \
+"	1027:									\n" \
+"		leal 2(%%edi), %%edi						\n" \
+"		je 6f								\n" \
+"		shll $16,%%ecx							\n" \
+"	1028:									\n" \
+"	5:	movb (%%esi), %%cl						\n" \
+"	1029:									\n" \
+"		movb %%cl, (%%edi)						\n" \
+"	6:	addl %%ecx, %%eax						\n" \
+"		adcl $0, %%eax							\n" \
+"	7:									\n" \
+"	2000:									\n" \
+"     	   .section .fixup,\"ax\"						\n" \
+"	3000:		movl %7,%1						\n" \
+/* FIXME: zero out the rest of the buffer here !!!!!! */			\
+"		jmp 2000b							\n" \
+"		.previous							\n" \
+"		.section __ex_table,\"a\"					\n" \
+"		.align 4                   					\n" \
+"										\n" \
+SRC(  "        .long 1000b,3000b        \n  "    ) \
+DST(  "        .long 1001b,3000b        \n  "    ) \
+SRC(  "        .long 1002b,3000b        \n  "    ) \
+SRC(  "        .long 1003b,3000b        \n  "    ) \
+DST(  "        .long 1004b,3000b        \n  "    ) \
+DST(  "        .long 1005b,3000b        \n  "    ) \
+SRC(  "        .long 1006b,3000b        \n  "    ) \
+SRC(  "        .long 1007b,3000b        \n  "    ) \
+DST(  "        .long 1008b,3000b        \n  "    ) \
+DST(  "        .long 1009b,3000b        \n  "    ) \
+SRC(  "        .long 1010b,3000b        \n  "    ) \
+SRC(  "        .long 1011b,3000b        \n  "    ) \
+DST(  "        .long 1012b,3000b        \n  "    ) \
+DST(  "        .long 1013b,3000b        \n  "    ) \
+SRC(  "        .long 1014b,3000b        \n  "    ) \
+SRC(  "        .long 1015b,3000b        \n  "    ) \
+DST(  "        .long 1016b,3000b        \n  "    ) \
+DST(  "        .long 1017b,3000b        \n  "    ) \
+SRC(  "        .long 1018b,3000b        \n  "    ) \
+DST(  "        .long 1019b,3000b        \n  "    ) \
+SRC(  "        .long 1020b,3000b        \n  "    ) \
+DST(  "        .long 1021b,3000b        \n  "    ) \
+SRC(  "        .long 1022b,3000b        \n  "    ) \
+DST(  "        .long 1023b,3000b        \n  "    ) \
+SRC(  "        .long 1024b,3000b        \n  "    ) \
+SRC(  "        .long 1025b,3000b        \n  "    ) \
+DST(  "        .long 1026b,3000b        \n  "    ) \
+DST(  "        .long 1027b,3000b        \n  "    ) \
+SRC(  "        .long 1028b,3000b        \n  "    ) \
+DST(  "        .long 1029b,3000b        \n  "    ) \
+"        .previous                      \n  " 				\
+	: "=a" (sum), "=r" (*__csum_err)   				\
+	:  "0" (sum), "c" (len), "S" (src), "D" (dst), 			\
+		"1" (*__csum_err), "i" (-EFAULT)   			\
+	: "bx", "cx", "dx", "si", "di" );  				\
+ 									\
+    return(sum);  							\
+}
 
 /*
- * copy from ds while checksumming, otherwise like csum_partial
+ *  Currently we need only 2 out of the 4 possible type combinations:
  */
 
-unsigned int csum_partial_copy(const char *src, char *dst, 
-				  int len, int sum) {
-    __asm__("
-	testl $2, %%edi		# Check alignment.
-	jz 2f			# Jump if alignment is ok.
-	subl $2, %%ecx		# Alignment uses up two bytes.
-	jae 1f			# Jump if we had at least two bytes.
-	addl $2, %%ecx		# ecx was < 2.  Deal with it.
-	jmp 4f
-1:	movw (%%esi), %%bx
-	addl $2, %%esi
-	movw %%bx, (%%edi)
-	addl $2, %%edi
-	addw %%bx, %%ax
-	adcl $0, %%eax
-2:
-	pushl %%ecx
-	shrl $5, %%ecx
-	jz 2f
-	testl %%esi, %%esi
-1:	movl (%%esi), %%ebx
-	movl 4(%%esi), %%edx
-	adcl %%ebx, %%eax
-	movl %%ebx, (%%edi)
-	adcl %%edx, %%eax
-	movl %%edx, 4(%%edi)
-
-	movl 8(%%esi), %%ebx
-	movl 12(%%esi), %%edx
-	adcl %%ebx, %%eax
-	movl %%ebx, 8(%%edi)
-	adcl %%edx, %%eax
-	movl %%edx, 12(%%edi)
-
-	movl 16(%%esi), %%ebx
-	movl 20(%%esi), %%edx
-	adcl %%ebx, %%eax
-	movl %%ebx, 16(%%edi)
-	adcl %%edx, %%eax
-	movl %%edx, 20(%%edi)
-
-	movl 24(%%esi), %%ebx
-	movl 28(%%esi), %%edx
-	adcl %%ebx, %%eax
-	movl %%ebx, 24(%%edi)
-	adcl %%edx, %%eax
-	movl %%edx, 28(%%edi)
-
-	lea 32(%%esi), %%esi
-	lea 32(%%edi), %%edi
-	dec %%ecx
-	jne 1b
-	adcl $0, %%eax
-2:	popl %%edx
-	movl %%edx, %%ecx
-	andl $0x1c, %%edx
-	je 4f
-	shrl $2, %%edx		# This clears CF
-3:	movl (%%esi), %%ebx
-	adcl %%ebx, %%eax
-	movl %%ebx, (%%edi)
-	lea 4(%%esi), %%esi
-	lea 4(%%edi), %%edi
-	dec %%edx
-	jne 3b
-	adcl $0, %%eax
-4:	andl $3, %%ecx
-	jz 7f
-	cmpl $2, %%ecx
-	jb 5f
-	movw (%%esi), %%cx
-	leal 2(%%esi), %%esi
-	movw %%cx, (%%edi)
-	leal 2(%%edi), %%edi
-	je 6f
-	shll $16,%%ecx
-5:	movb (%%esi), %%cl
-	movb %%cl, (%%edi)
-6:	addl %%ecx, %%eax
-	adcl $0, %%eax
-7:
-	"
-	: "=a" (sum)
-	: "0"(sum), "c"(len), "S"(src), "D" (dst)
-	: "bx", "cx", "dx", "si", "di" );
-    return(sum);
+/*
+ * Generate 'csum_partial_copy_from_user()', we need to do exception
+ * handling for source addresses.
+ */
+
+#define SRC(x) x
+#define DST(x)
+csum_partial_copy_type(_from_user)
+#undef SRC
+#undef DST
+
+/*
+ * Generate 'csum_partial_copy_nocheck()', no need to do exception
+ * handling.
+ */
+
+#define SRC(x)
+#define DST(x)
+csum_partial_copy_type(_nocheck_generic)
+#undef SRC
+#undef DST
+
+/*
+ * Generate 'csum_partial_copy_old()', old and slow compability stuff,
+ * full checking.
+ *
+ * tell us if you see something printk-ing on this. This function will be
+ * removed soon.
+ */
+
+#define SRC(x) x
+#define DST(x) x
+csum_partial_copy_type(_old)
+#undef SRC
+#undef DST
+
+unsigned int csum_partial_copy ( const char *src, char *dst, 
+				  int len, int sum)
+{
+	int ret;
+	int error = 0;
+
+	ret = csum_partial_copy_old (&error, src, dst, len, sum);
+
+	if (error)
+		printk("csum_partial_copy_old(): tell mingo to convert me!\n");
+
+	return ret;
 }
+
diff -u --recursive --new-file v2.1.24/linux/drivers/cdrom/isp16.c linux/drivers/cdrom/isp16.c
--- v2.1.24/linux/drivers/cdrom/isp16.c	Mon Dec 30 15:39:05 1996
+++ linux/drivers/cdrom/isp16.c	Sun Feb  2 15:18:30 1997
@@ -62,12 +62,12 @@
 static int isp16_cdrom_irq = ISP16_CDROM_IRQ;
 static int isp16_cdrom_dma = ISP16_CDROM_DMA;
 static char *isp16_cdrom_type = ISP16_CDROM_TYPE;
+
+#ifdef MODULE
 MODULE_PARM(isp16_cdrom_base, "i");
 MODULE_PARM(isp16_cdrom_irq, "i");
 MODULE_PARM(isp16_cdrom_dma, "i");
 MODULE_PARM(isp16_cdrom_type, "s");
-
-#ifdef MODULE
 int init_module(void);
 void cleanup_module(void);
 #endif
diff -u --recursive --new-file v2.1.24/linux/drivers/cdrom/sjcd.c linux/drivers/cdrom/sjcd.c
--- v2.1.24/linux/drivers/cdrom/sjcd.c	Tue Jan 28 18:49:58 1997
+++ linux/drivers/cdrom/sjcd.c	Sun Feb  2 15:18:30 1997
@@ -106,7 +106,10 @@
 static struct sjcd_play_msf sjcd_playing;
 
 static int sjcd_base = SJCD_BASE_ADDR;
+
+#ifdef MODULE
 MODULE_PARM(sjcd_base, "i");
+#endif
 
 static struct wait_queue *sjcd_waitq = NULL;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c
--- v2.1.24/linux/drivers/char/apm_bios.c	Tue Jan 28 18:49:59 1997
+++ linux/drivers/char/apm_bios.c	Wed Jan 29 13:32:58 1997
@@ -59,6 +59,7 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/poll.h>
 
 #include <linux/types.h>
 #include <linux/stddef.h>
diff -u --recursive --new-file v2.1.24/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.1.24/linux/drivers/char/console.c	Tue Jan 28 18:50:01 1997
+++ linux/drivers/char/console.c	Sun Feb  2 15:52:22 1997
@@ -60,6 +60,7 @@
  * User-defined bell sound, new setterm control sequences and printk
  * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
  *
+ * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
  */
 
 #define BLANK 0x0020
@@ -2194,12 +2195,14 @@
 	hide_cursor();
 	console_blanked = fg_console + 1;
 
+	if(!nopowersave)
+	{
 #ifdef CONFIG_APM
-	if (apm_display_blank())
-		return;
+		if (apm_display_blank())
+			return;
 #endif
-	if(!nopowersave)
-	    vesa_blank();
+		vesa_blank();
+	}
 }
 
 void do_unblank_screen(void)
diff -u --recursive --new-file v2.1.24/linux/drivers/char/softdog.c linux/drivers/char/softdog.c
--- v2.1.24/linux/drivers/char/softdog.c	Sun Feb  2 15:46:19 1997
+++ linux/drivers/char/softdog.c	Sun Feb  2 15:18:35 1997
@@ -46,7 +46,6 @@
  
 struct timer_list watchdog_ticktock;
 static int timer_alive = 0;
-static int in_use = 0;
 
 
 /*
@@ -71,9 +70,8 @@
  
 static int softdog_open(struct inode *inode, struct file *file)
 {
-	if(in_use)
+	if(timer_alive)
 		return -EBUSY;
-	in_use = 1;
 	MOD_INC_USE_COUNT;
 	/*
 	 *	Activate timer
@@ -81,7 +79,7 @@
 	del_timer(&watchdog_ticktock);
 	watchdog_ticktock.expires=jiffies + (soft_margin * HZ);
 	add_timer(&watchdog_ticktock);
-	timer_alive++;
+	timer_alive=1;
 	return 0;
 }
 
@@ -94,9 +92,8 @@
 #ifndef CONFIG_WATCHDOG_NOWAYOUT	 
 	del_timer(&watchdog_ticktock);
 	MOD_DEC_USE_COUNT;
-	timer_alive=0;
 #endif	
-	in_use = 0;
+	timer_alive=0;
 }
 
 static void softdog_ping(void)
diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v2.1.24/linux/drivers/net/3c501.c	Tue Dec 31 21:41:01 1996
+++ linux/drivers/net/3c501.c	Sun Feb  2 15:18:35 1997
@@ -123,7 +123,7 @@
 static void el_receive(struct device *dev);
 static void el_reset(struct device *dev);
 static int  el1_close(struct device *dev);
-static struct enet_statistics *el1_get_stats(struct device *dev);
+static struct net_device_stats *el1_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 #define EL1_IO_EXTENT	16
@@ -139,7 +139,7 @@
 
 struct net_local
 {
-    struct enet_statistics stats;
+    struct net_device_stats stats;
     int tx_pkt_start;		/* The length of the current Tx packet. */
     int collisions;		/* Tx collisions this packet */
     int loading;		/* Spot buffer load collisions */
@@ -398,12 +398,6 @@
 		dev->trans_start = jiffies;
 	}
 
-	if (skb == NULL)
-	{
-		dev_tint(dev);
-		return 0;
-	}
-
 	save_flags(flags);
 
 	/*
@@ -432,6 +426,8 @@
 		lp->tx_pkt_start = gp_start;
     		lp->collisions = 0;
 
+    		lp->stats.tx_bytes += skb->len;
+
 		/*
 		 *	Command mode with status cleared should [in theory]
 		 *	mean no more interrupts can be pending on the card.
@@ -769,7 +765,7 @@
 	return 0;
 }
 
-static struct enet_statistics *el1_get_stats(struct device *dev)
+static struct net_device_stats *el1_get_stats(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	return &lp->stats;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.1.24/linux/drivers/net/3c505.c	Tue Dec 31 21:41:01 1996
+++ linux/drivers/net/3c505.c	Sun Feb  2 15:18:35 1997
@@ -1034,6 +1034,9 @@
 	}
 	adapter = dev->priv;
 
+
+	adapter->stats.tx_bytes+=nlen;
+	
 	/*
 	 * send the adapter a transmit packet command. Ignore segment and offset
 	 * and make sure the length is even
@@ -1111,15 +1114,6 @@
 		adapter->stats.tx_dropped++;
 	}
 
-	/* Some upper layer thinks we've missed a tx-done interrupt */
-	if (skb == NULL) {
-		dev_tint(dev);
-		return 0;
-	}
-
-	if (skb->len <= 0)
-		return 0;
-
 	if (elp_debug >= 3)
 		printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
 
@@ -1156,7 +1150,7 @@
  *
  ******************************************************/
 
-static struct enet_statistics *elp_get_stats(struct device *dev)
+static struct net_device_stats *elp_get_stats(struct device *dev)
 {
 	elp_device *adapter = (elp_device *) dev->priv;
 
@@ -1329,7 +1323,7 @@
 	/*
 	 * setup ptr to adapter specific information
 	 */
-	memset(&(adapter->stats), 0, sizeof(struct enet_statistics));
+	memset(&(adapter->stats), 0, sizeof(struct net_device_stats));
 
 	/*
 	 * memory information
diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c505.h linux/drivers/net/3c505.h
--- v2.1.24/linux/drivers/net/3c505.h	Wed Oct 16 10:48:17 1996
+++ linux/drivers/net/3c505.h	Sun Feb  2 15:18:35 1997
@@ -264,7 +264,7 @@
 	pcb_struct rx_pcb;	/* PCB for foreground receiving */
 	pcb_struct itx_pcb;	/* PCB for background sending */
 	pcb_struct irx_pcb;	/* PCB for background receiving */
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 
 	void *dma_buffer;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v2.1.24/linux/drivers/net/3c507.c	Tue Dec 31 21:41:02 1996
+++ linux/drivers/net/3c507.c	Sun Feb  2 15:18:35 1997
@@ -115,7 +115,7 @@
 
 /* Information that need to be kept for each board. */
 struct net_local {
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	int last_restart;
 	ushort rx_head;
 	ushort rx_tail;
@@ -283,7 +283,7 @@
 static void	el16_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void el16_rx(struct device *dev);
 static int	el16_close(struct device *dev);
-static struct enet_statistics *el16_get_stats(struct device *dev);
+static struct net_device_stats *el16_get_stats(struct device *dev);
 
 static void hardware_send_packet(struct device *dev, void *buf, short length);
 void init_82586_mem(struct device *dev);
@@ -300,8 +300,8 @@
 	If dev->base_addr == 2, (detachable devices only) allocate space for the
 	device and return success.
 	*/
-int
-el16_probe(struct device *dev)
+
+int el16_probe(struct device *dev)
 {
 	int base_addr = dev ? dev->base_addr : 0;
 	int i;
@@ -428,10 +428,7 @@
 	return 0;
 }
 
-
-
-static int
-el16_open(struct device *dev)
+static int el16_open(struct device *dev)
 {
 	irq2dev_map[dev->irq] = dev;
 
@@ -447,14 +444,14 @@
 	return 0;
 }
 
-static int
-el16_send_packet(struct sk_buff *skb, struct device *dev)
+static int el16_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int ioaddr = dev->base_addr;
 	short *shmem = (short*)dev->mem_start;
 
-	if (dev->tbusy) {
+	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. */
 		int tickssofar = jiffies - dev->trans_start;
@@ -480,21 +477,15 @@
 		dev->trans_start = jiffies;
 	}
 
-	/* 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. */
 	if (set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
-	else {
+	else
+	{
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		unsigned char *buf = skb->data;
 
+		lp->stats.tx_bytes+=length;
 		/* Disable the 82586's input to the interrupt line. */
 		outb(0x80, ioaddr + MISC_CTRL);
 		hardware_send_packet(dev, buf, length);
@@ -509,11 +500,10 @@
 
 	return 0;
 }
-
+
 /*	The typical workload of the driver:
 	Handle the network interface interrupts. */
-static void
-el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct device *dev = (struct device *)(irq2dev_map[irq]);
 	struct net_local *lp;
@@ -588,8 +578,9 @@
 		ack_cmd |= CUC_RESUME;
 	}
 
-	if ((status & 0x0070) != 0x0040  &&  dev->start) {
-	  static void init_rx_bufs(struct device *);
+	if ((status & 0x0070) != 0x0040  &&  dev->start) 
+	{
+		static void init_rx_bufs(struct device *);
 		/* The Rx unit is not ready, it must be hung.  Restart the receiver by
 		   initializing the rx buffers, and issuing an Rx start command. */
 		if (net_debug)
@@ -612,8 +603,7 @@
 	return;
 }
 
-static int
-el16_close(struct device *dev)
+static int el16_close(struct device *dev)
 {
 	int ioaddr = dev->base_addr;
 	ushort *shmem = (short*)dev->mem_start;
@@ -642,8 +632,7 @@
 
 /* Get the current statistics.	This may be called with the card open or
    closed. */
-static struct enet_statistics *
-el16_get_stats(struct device *dev)
+static struct net_device_stats *el16_get_stats(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 
@@ -653,8 +642,7 @@
 }
 
 /* Initialize the Rx-block list. */
-static void
-init_rx_bufs(struct device *dev)
+static void init_rx_bufs(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned short *write_ptr;
@@ -699,8 +687,7 @@
 
 }
 
-void
-init_82586_mem(struct device *dev)
+void init_82586_mem(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	short ioaddr = dev->base_addr;
@@ -758,8 +745,7 @@
 	return;
 }
 
-static void
-hardware_send_packet(struct device *dev, void *buf, short length)
+static void hardware_send_packet(struct device *dev, void *buf, short length)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	short ioaddr = dev->base_addr;
@@ -804,8 +790,7 @@
 		dev->tbusy = 0;
 }
 
-static void
-el16_rx(struct device *dev)
+static void el16_rx(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	short *shmem = (short*)dev->mem_start;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.1.24/linux/drivers/net/3c509.c	Tue Dec 31 21:41:02 1996
+++ linux/drivers/net/3c509.c	Sun Feb  2 15:18:35 1997
@@ -110,7 +110,7 @@
 #define SKB_QUEUE_SIZE	64
 
 struct el3_private {
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	/* skb send-queue */
 	int head, size;
 	struct sk_buff *queue[SKB_QUEUE_SIZE];
@@ -123,7 +123,7 @@
 static int el3_start_xmit(struct sk_buff *skb, struct device *dev);
 static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void update_stats(int addr, struct device *dev);
-static struct enet_statistics *el3_get_stats(struct device *dev);
+static struct net_device_stats *el3_get_stats(struct device *dev);
 static int el3_rx(struct device *dev);
 static int el3_close(struct device *dev);
 #ifdef HAVE_MULTICAST
@@ -421,8 +421,7 @@
 	return 0;					/* Always succeed */
 }
 
-static int
-el3_start_xmit(struct sk_buff *skb, struct device *dev)
+static int el3_start_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct el3_private *lp = (struct el3_private *)dev->priv;
 	int ioaddr = dev->base_addr;
@@ -444,14 +443,6 @@
 		dev->tbusy = 0;
 	}
 
-	if (skb == NULL) {
-		dev_tint(dev);
-		return 0;
-	}
-
-	if (skb->len <= 0)
-		return 0;
-
 	if (el3_debug > 4) {
 		printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
 			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));
@@ -479,6 +470,7 @@
 	if (set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
+		lp->stats.tx_bytes+=skb->len;
 		/* Put out the doubleword header... */
 		outw(skb->len, ioaddr + TX_FIFO);
 		outw(0x00, ioaddr + TX_FIFO);
@@ -589,8 +581,7 @@
 }
 
 
-static struct enet_statistics *
-el3_get_stats(struct device *dev)
+static struct net_device_stats *el3_get_stats(struct device *dev)
 {
 	struct el3_private *lp = (struct el3_private *)dev->priv;
 	unsigned long flags;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c523.c linux/drivers/net/3c523.c
--- v2.1.24/linux/drivers/net/3c523.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/net/3c523.c	Sun Feb  2 15:18:35 1997
@@ -170,7 +170,7 @@
 static int     elmc_open(struct device *dev);
 static int     elmc_close(struct device *dev);
 static int     elmc_send_packet(struct sk_buff *,struct device *);
-static struct  enet_statistics *elmc_get_stats(struct device *dev);
+static struct  net_device_stats *elmc_get_stats(struct device *dev);
 static void    set_multicast_list(struct device *dev);
 
 /* helper-functions */
@@ -183,25 +183,26 @@
 static void    elmc_xmt_int(struct device *dev);
 static void    elmc_rnr_int(struct device *dev);
 
-struct priv {
-  struct enet_statistics stats;
-  unsigned long base;
-  char *memtop;
-  volatile struct rfd_struct  *rfd_last,*rfd_top,*rfd_first;
-  volatile struct scp_struct  *scp;  /* volatile is important */
-  volatile struct iscp_struct *iscp; /* volatile is important */
-  volatile struct scb_struct  *scb;  /* volatile is important */
-  volatile struct tbd_struct  *xmit_buffs[NUM_XMIT_BUFFS];
-  volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
+struct priv 
+{
+	struct net_device_stats stats;
+	unsigned long base;
+	char *memtop;
+	volatile struct rfd_struct	*rfd_last,*rfd_top,*rfd_first;
+	volatile struct scp_struct	*scp;	/* volatile is important */
+	volatile struct iscp_struct *iscp; /* volatile is important */
+	volatile struct scb_struct  *scb;  /* volatile is important */
+	volatile struct tbd_struct  *xmit_buffs[NUM_XMIT_BUFFS];
+	volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 #if (NUM_XMIT_BUFFS == 1)
-  volatile struct nop_cmd_struct *nop_cmds[2];
+	volatile struct nop_cmd_struct *nop_cmds[2];
 #else
-  volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
+	volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
 #endif
-  volatile int    nop_point,num_recv_buffs;
-  volatile char  *xmit_cbuffs[NUM_XMIT_BUFFS];
-  volatile int    xmit_count,xmit_last;
-  volatile int slot;
+	volatile int    nop_point,num_recv_buffs;
+	volatile char  *xmit_cbuffs[NUM_XMIT_BUFFS];
+	volatile int    xmit_count,xmit_last;
+	volatile int slot;
 };
 
 #define elmc_attn586()  {elmc_do_attn586(dev->base_addr,ELMC_CTRL_INTE);}
@@ -1208,9 +1209,8 @@
  * Someone wanna have the statistics
  */
 
-static
-struct enet_statistics*
-elmc_get_stats( struct device *dev ) {
+static struct net_device_stats *elmc_get_stats( struct device *dev ) 
+{
   struct priv *p = (struct priv *) dev->priv;
   unsigned short crc,aln,rsc,ovrn;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.1.24/linux/drivers/net/3c59x.c	Sun Nov 10 20:12:11 1996
+++ linux/drivers/net/3c59x.c	Sun Feb  2 15:18:35 1997
@@ -233,7 +233,7 @@
 	char devname[8];			/* "ethN" string, also for kernel debug. */
 	const char *product_name;
 	struct device *next_module;
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
 	struct timer_list timer;	/* Media selection timer. */
 	int options;				/* User-settable misc. driver options. */
@@ -276,7 +276,7 @@
 static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs);
 static int vortex_close(struct device *dev);
 static void update_stats(int addr, struct device *dev);
-static struct enet_statistics *vortex_get_stats(struct device *dev);
+static struct net_device_stats *vortex_get_stats(struct device *dev);
 static void set_rx_mode(struct device *dev);
 
 
@@ -1067,8 +1067,7 @@
 	return 0;
 }
 
-static struct enet_statistics *
-vortex_get_stats(struct device *dev)
+static struct net_device_stats *vortex_get_stats(struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	unsigned long flags;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.1.24/linux/drivers/net/8390.c	Thu Dec 12 19:37:04 1996
+++ linux/drivers/net/8390.c	Sun Feb  2 15:18:35 1997
@@ -179,17 +179,7 @@
 		dev->trans_start = jiffies;
     }
     
-    /* Sending a NULL skb means some higher layer thinks we've missed an
-       tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
-       itself. */
-    if (skb == NULL) {
-		dev_tint(dev);
-		return 0;
-    }
-    
     length = skb->len;
-    if (skb->len <= 0)
-		return 0;
 
     /* Mask interrupts from the ethercard. */
     outb_p(0x00, e8390_base + EN0_IMR);
@@ -202,6 +192,8 @@
 
     send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
 
+    ei_local->stat.tx_bytes+=send_length;
+    
 #ifdef EI_PINGPONG
 
     /*
@@ -560,6 +552,7 @@
 				skb->dev = dev;
 				skb_put(skb, pkt_len);	/* Make room */
 				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
+				ei_local->stat.rx_bytes+=skb->len;
 				skb->protocol=eth_type_trans(skb,dev);
 				netif_rx(skb);
 				ei_local->stat.rx_packets++;
@@ -663,7 +656,7 @@
 	
 }
 
-static struct enet_statistics *get_stats(struct device *dev)
+static struct net_device_stats *get_stats(struct device *dev)
 {
     short ioaddr = dev->base_addr;
     struct ei_device *ei_local = (struct ei_device *) dev->priv;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/8390.h linux/drivers/net/8390.h
--- v2.1.24/linux/drivers/net/8390.h	Thu Dec 12 19:37:04 1996
+++ linux/drivers/net/8390.h	Sun Feb  2 15:18:35 1997
@@ -75,7 +75,7 @@
   unsigned char reg5;		/* Register '5' in a WD8013 */
   unsigned char saved_irq;	/* Original dev->irq value. */
   /* The new statistics table. */
-  struct enet_statistics stat;
+  struct net_device_stats stat;
 };
 
 /* The maximum number of 8390 interrupt service routines called per IRQ. */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/CONFIG linux/drivers/net/CONFIG
--- v2.1.24/linux/drivers/net/CONFIG	Tue Nov 19 15:53:54 1996
+++ linux/drivers/net/CONFIG	Sun Feb  2 15:18:35 1997
@@ -99,3 +99,4 @@
 DEFXX_OPTS	=
 ELP_OPTS	=
 TULIP_OPTS	=
+CS89x0_OPTS	=
diff -u --recursive --new-file v2.1.24/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.24/linux/drivers/net/Config.in	Thu Jan  2 15:55:16 1997
+++ linux/drivers/net/Config.in	Sun Feb  2 15:18:35 1997
@@ -76,7 +76,8 @@
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
     tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT
-    tristate 'DE425, DE434, DE435, DE450, DE500 support' CONFIG_DE4X5
+    tristate 'CS89x0 support' CONFIG_CS89x0
+    tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
     tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
     tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -104,6 +105,15 @@
   dep_tristate '  SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
 fi
 
+#
+# LocalTalk
+#
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  if [ "$CONFIG_ATALK" != "n" ]; then
+    tristate 'LocalTalk PC support' CONFIG_LTPC
+  fi
+fi
+
 tristate 'PLIP (parallel port) support' CONFIG_PLIP
 
 tristate 'PPP (point-to-point) support' CONFIG_PPP
@@ -137,11 +147,6 @@
   fi
   tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
   tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
-  tristate 'WIC Radio IP bridge' CONFIG_WIC
-fi
-
-if [ "$CONFIG_X25" != "n" ]; then
-  tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER
 fi
 
 tristate 'SLIP (serial line) support' CONFIG_SLIP
@@ -158,5 +163,24 @@
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER
+fi
+#
+# WAN drivers support
+#
+if [ "$CONFIG_WAN_ROUTER" = "y" ]; then
+  bool 'WAN drivers' CONFIG_WAN_DRIVERS
+  if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then
+    bool 'Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA
+    if [ "$CONFIG_VENDOR_SANGOMA" = "y" ]; then
+      int  '  Maximum number of cards' CONFIG_WANPIPE_CARDS 1
+      bool '  WANPIPE X.25 support' CONFIG_WANPIPE_X25
+      bool '  WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
+      bool '  WANPIPE PPP support' CONFIG_WANPIPE_PPP
+    fi
+  fi
+fi
+
+if [ "$CONFIG_X25" != "n" ]; then
+  tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER
 fi
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.1.24/linux/drivers/net/Makefile	Tue Jan 28 18:50:02 1997
+++ linux/drivers/net/Makefile	Sun Feb  2 15:18:36 1997
@@ -77,14 +77,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_WIC),y)
-L_OBJS += wic.o
-else
-  ifeq ($(CONFIG_WIC),m)
-  M_OBJS += wic.o
-  endif
-endif
-
 ifeq ($(CONFIG_SMC9194),y)
 L_OBJS += smc9194.o
 else
@@ -630,6 +622,22 @@
   endif
 endif
 
+ifeq ($(CONFIG_CS89x0),y)
+L_OBJS += cs89x0.o
+else
+  ifeq ($(CONFIG_CS89x0),m)
+  M_OBJS += cs89x0.o
+  endif
+endif
+
+ifeq ($(CONFIG_LTPC),y)
+L_OBJS += ltpc.o
+else
+  ifeq ($(CONFIG_LTPC),m)
+  M_OBJS += ltpc.o
+  endif
+endif
+
 ifeq ($(CONFIG_BAYCOM),y)
 L_OBJS += baycom.o
 CONFIG_HDLCDRV_BUILTIN = y
@@ -661,6 +669,21 @@
 endif
 
 
+ifeq ($(CONFIG_VENDOR_SANGOMA),y)
+  M_OBJS += sdladrv.o
+  M_OBJS += wanpipe.o
+  WANPIPE_OBJS = sdlamain.o
+  ifeq ($(CONFIG_WANPIPE_X25),y)
+    WANPIPE_OBJS += sdla_x25.o
+  endif
+  ifeq ($(CONFIG_WANPIPE_FR),y)
+    WANPIPE_OBJS += sdla_fr.o
+  endif
+  ifeq ($(CONFIG_WANPIPE_PPP),y)
+    WANPIPE_OBJS += sdla_ppp.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 clean:
@@ -725,7 +748,24 @@
 
 dlci.o: dlci.c CONFIG
 
+sdladrv.o: sdladrv.c CONFIG
+
+wanpipe.o: $(WANPIPE_OBJS)
+	ld -r -o $@ $^
+
+sdlamain.o: sdlamain.c CONFIG
+
+sdla_x25.o: sdla_x25.c CONFIG
+
+sdla_fr.o: sdla_fr.c CONFIG
+
+sdla_ppp.o: sdla_ppp.c CONFIG
+
 dgrs.o: dgrs.c dgrs.h CONFIG
 	$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+ltpc.o: ltpc.c ltpc.h CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
 tulip.o: tulip.c CONFIG
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(TULIP_OPTS) -c $<
diff -u --recursive --new-file v2.1.24/linux/drivers/net/README.de4x5 linux/drivers/net/README.de4x5
--- v2.1.24/linux/drivers/net/README.de4x5	Tue May  2 07:10:16 1995
+++ linux/drivers/net/README.de4x5	Sun Feb  2 15:02:05 1997
@@ -1,20 +1,22 @@
-The de425/de434/de435/de500 driver in this distribution  is designed to work
-with  the  Digital Equipment Corporation   series of PCI/EISA ethernet cards
-(DE425, DE434, DE435, DE500) and with all kernels that support PCI.
+This driver has been upgraded to include generic DECchip support through the
+use of the on-board SROM  that is found on all  DECchip cards except for the
+DC21040. The driver  will work with the following  set of cards and probably
+more:
+
+        KINGSTON
+	Linksys
+	ZNYX342
+	SMC8432
+	SMC9332 (w/new SROM)
+	ZNYX31[45]
+	DIGITAL EtherWORKS PCI/EISA (DE425, DE434, DE435, DE450, DE500)
 
 Auto media detection is provided so that the  media choice isn't compiled in
-and is  flexible enough to be able  to  reconfigure on-the-fly. This feature
-hasn't been included for the DE500 unfortunately, due  to a potential patent
-dispute. When I get around to implementing the autosense algorithm by myself
-(which could legally be difficult to prove since I'm  part of the group that
-has implemented the patented algorithm) you'll  have an auto speed selection
-for the de500. If you want the auto speed feature yell at Digital. If enough
-of you do things might change.
-
-The ability to load   this driver as  a loadable  module has been  included,
-although I don't recommend its use with PCI, since PCI dynamically allocates
-where the card will go at boot time (i.e. the  card would have to be present
-in the system at boot time for its address/IRQ to be assigned).
+and is  flexible enough to be able  to  reconfigure on-the-fly. 
+
+The ability to load this driver as  a loadable module  has been included and
+will now load  (and   unload) as many  DECchip  cards  as  it can  find  and
+configure with just one invocation of 'insmod'.
 
 The performance we've achieved  so far has  been measured through the 'ttcp'
 tool at 1.06MB/s for  TCP  and 1.17MB/s for  UDP.   This measures  the total
@@ -32,16 +34,8 @@
 measurement. Their error  is approx +/-20k on a  quiet (private) network and
 also depend on what load the CPU has, CPU speed etc.
 
-ZYNX and SMC cards, which use the PCI DECchip  DC21040, are not specifically
-supported in this driver because
-
-a) I have  no information on them.   
-b) I cannot test  them with the driver.
-c) Donald Becker's 'tulip.c' driver  works with them....well one person says
-   they do and another says they do not, so take your pick!
-
-This driver can be made to work with the ZYNX  (and may be  the SMC) card by
-setting a compile time flag (IS_NOT_DEC) in linux/drivers/net/CONFIG
+I've had  reports  that Alphas  can get 80+Mb/s   when using  100BASE-TX and
+similar figures for 133MHz Pentium Pros.
 
 Enjoy!
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/README.ltpc linux/drivers/net/README.ltpc
--- v2.1.24/linux/drivers/net/README.ltpc	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/README.ltpc	Sun Feb  2 15:18:36 1997
@@ -0,0 +1,98 @@
+This is the ALPHA version of the ltpc driver.
+
+In order to use it, you will need at least version 1.3.3 of the
+netatalk package, and the Apple or Farallon Localtalk PC card.
+There are a number of different Localtalk cards for the PC; this
+driver applies only to the one with the 65c02 processor chip on it.
+
+To include it in the kernel, select the CONFIG_LTPC switch in the
+configuration dialog; at this time (kernel 2.1.23) compiling it as
+a module will not work.
+
+Before starting up the netatalk demons (perhaps in rc.local), you
+need to add a line such as:
+
+/sbin/ifconfig ltalk0 127.0.0.42
+
+
+The driver will autoprobe, and you should see a message like:
+"LocalTalk card found at 240, IR9, DMA1."
+at bootup.
+
+The appropriate netatalk configuration depends on whether you are
+attached to a network that includes appletalk routers or not.  If,
+like me, you are simply connecting to your home Macintoshes and
+printers, you need to set up netatalk to "seed".  The way I do this
+is to have the lines
+
+dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033"
+ltalk0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033"
+
+in my atalkd.conf.  What is going on here is that I need to fool
+netatalk into thinking that there are two appletalk interfaces
+present -- otherwise it refuses to seed.  This is a hack, and a
+more permanent solution would be to alter the netatalk code.
+Note that the dummy driver needs to accept multicasts also -- earlier
+versions of dummy.c may need to be patched.  
+
+
+If you are attached to an extended appletalk network, with routers on
+it, then you don't need to fool around with this -- the appropriate
+line in atalkd.conf is
+
+ltalk0 -phase 1
+
+--------------------------------------
+
+Card Configuration:
+
+The interrupts and so forth are configured via the dipswitch on the
+board.  Set the switches so as not to conflict with other hardware.
+
+       Interrupts -- set at most one.  If none are set, the driver uses
+       polled mode.  Because the card was developed in the XT era, the
+       original documentation refers to IRQ2.  Since you'll be running
+       this on an AT (or later) class machine, that really means IRQ9.
+
+       SW1     IRQ 4
+       SW2     IRQ 3
+       SW3     IRQ 9 (2 in original card documentation only applies to XT)
+
+
+       DMA -- choose DMA 1 or 3, and set both corresponding switches.
+
+       SW4     DMA 3
+       SW5     DMA 1
+       SW6     DMA 3
+       SW7     DMA 1
+
+
+       I/O address -- choose one.
+
+       SW8     220 / 240
+
+--------------------------------------
+
+IP:
+	Many people are interested in this driver in order to use IP
+when Localtalk, but no Ethernet, is available.  While the code to do
+this is not strictly speaking part of this driver, an experimental 
+version is available which seems to work under kernel 2.0.xx.  It is
+not yet functional in the 2.1.xx kernels.
+
+--------------------------------------
+
+BUGS:
+
+2.0.xx:
+
+2.1.xx:	The module support doesn't work yet.
+
+______________________________________
+
+THANKS:
+	Thanks to Alan Cox for helpful discussions early on in this
+work, and to Denis Hainsworth for doing the bleeding-edge testing.
+
+-- Bradford Johnson <bradford@math.umn.edu>
+
diff -u --recursive --new-file v2.1.24/linux/drivers/net/README.multicast linux/drivers/net/README.multicast
--- v2.1.24/linux/drivers/net/README.multicast	Tue Jan 28 18:50:02 1997
+++ linux/drivers/net/README.multicast	Sun Feb  2 15:18:36 1997
@@ -25,6 +25,7 @@
 arcnet		NO		NO		NO		N/A
 at1700		PROMISC		PROMISC		YES		Software
 atp		PROMISC		PROMISC		YES		Software
+cs89x0		YES		YES		YES		Software
 de4x5		YES		NO		YES		Hardware
 de600		NO		NO		NO		N/A
 de620		PROMISC		PROMISC		YES		Software
diff -u --recursive --new-file v2.1.24/linux/drivers/net/README.wanpipe linux/drivers/net/README.wanpipe
--- v2.1.24/linux/drivers/net/README.wanpipe	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/README.wanpipe	Sun Feb  2 15:18:36 1997
@@ -0,0 +1,142 @@
+------------------------------------------------------------------------------
+WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router
+------------------------------------------------------------------------------
+Release 3.0.0
+December 31, 1996
+Author: Gene Kozin <genek@compuserve.com>
+Copyright (c) 1995-1996 Sangoma Technologies Inc.
+------------------------------------------------------------------------------
+
+INTRODUCTION
+
+WANPIPE(tm) is a family of intelligent muliprotocol WAN communication adapters
+for personal computers (ISA bus) designed to provide PC connectivity to
+various communication links, such as leased lines and public data networks, at
+speeds up to T1/E1 using variety of synchronous communications protocols,
+including frame relay, PPP, X.25, SDLC, etc.
+
+WANPIPE driver together with Linux WAN Router module allows you to build
+relatively inexpensive, yet high-prformance multiprotocol WAN router.  For
+more information about Linux WAN Router please read file
+Documentation/networking/wan-router.txt.  You must also obtain WAN Tools
+package to be able to use Linux WAN Router and WANPIPE driver.  The package
+is available via the Internet from Sangoma Technologies' anonymous FTP server:
+
+	ftp.sangoma.com/pub/linux/wantools-X.Y.Z.tgz
+
+For technical questions and/or comments please e-mail to genek@compuserve.com.
+For general inquiries please contact Sangoma Technologies Inc. by
+
+	Hotline:	1-800-388-2475	(USA and Canada, toll free)
+	Phone:		(905) 474-1990
+	Fax:		(905) 474-9223
+	E-mail:		dm@sangoma.com	(David Mandelstam)
+	WWW:		http://www.sangoma.com
+
+
+
+COPYRIGHT AND LICENSING INFORMATION
+
+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, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+
+
+
+NEW IN THIS RELEASE
+
+ o Implemented as WAN Link Driver compliant with Linux WAN Router interface
+ o Added support for X.25 protocol
+ o Miscellaneous bug fixes and performance improvements
+
+
+
+FILE LIST
+
+drivers/net:
+	README.wanpipe	This file
+	sdladrv.c	SDLA support module source code
+	wpmain.c	WANPIPE driver module main source code
+	wpx.c		WANPIPE driver module X.25 source code
+	wpf.c		WANPIPE driver module frame relay source code
+	wpp.c		WANPIPE driver module PPP source code
+	sdla_x25.h	SDLA X.25 firmware API definitions
+	sdla_fr.h	SDLA frame relay firmware API definitions
+	sdla_ppp.h	SDLA PPP firmware API definitions
+
+include/linux:
+	wanpipe.h	WANPIPE API definitions
+	sdladrv.h	SDLA support module API definitions
+	sdlasfm.h	SDLA firmware module definitions
+
+
+
+REVISION HISTORY
+
+3.0.0	December 31, 1996
+
+	o Uses Linux WAN Router interface
+	o Added support for X.25 routing
+	o Miscellaneous bug fixes and performance improvements
+
+2.4.1	December 18, 1996
+
+	o Added support for LMI and Q.933 frame relay link management
+
+2.3.0	October 17, 1996
+
+	o All shell scripts use meta-configuration file
+	o Miscellaneous bug fixes
+
+2.2.0	July 16, 1996
+
+	o Compatible with Linux 2.0
+	o Added uninstall script
+	o User's Manual is available in HTML format
+
+2.1.0	June 20, 1996
+
+	o Added support for synchronous PPP
+	o Added support for S503 adapter
+	o Added API for executing adapter commands
+	o Fixed a re-entrancy problem in frame relaty driver
+	o Changed interface between SDLA driver and protocol support modules
+	o Updated frame relay firmware
+
+2.0.0	May 1, 1996
+
+	o Added interactive installation and configuration scripts
+	o Added System V-style start-up script
+	o Added dynamic memory window address selection in SDLA driver
+	o Miscellaneous bug fixes in SDLA driver
+	o Updated S508 frame relay firmware
+	o Changed SFM file format
+
+1.0.0	February 12, 1996
+
+	o Final release
+	o Added support for Linux 1.3
+	o Updated S508 frame relay firmware
+
+0.9.0	December 21, 1995
+
+	o Added SNAP encapsulation for routed frames
+	o Added support for the frame relay switch emulation mode
+	o Added support for S508 adapter
+	o Added capability to autodetect adapter type
+	o Miscellaneous bug fixes in SDLA and frame relay drivers
+
+0.1.0	October 12, 1995
+
+	o Initial version
+
+>>>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
diff -u --recursive --new-file v2.1.24/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.1.24/linux/drivers/net/Space.c	Tue Jan 28 18:50:02 1997
+++ linux/drivers/net/Space.c	Sun Feb  2 15:18:36 1997
@@ -84,14 +84,14 @@
 extern int a2065_probe(struct device *);
 extern int ariadne_probe(struct device *);
 extern int hydra_probe(struct device *);
+extern int cs89x0_probe(struct device *dev);
 
 /* Detachable devices ("pocket adaptors") */
 extern int atp_init(struct device *);
 extern int de600_probe(struct device *);
 extern int de620_probe(struct device *);
 
-static int
-ethif_probe(struct device *dev)
+static int ethif_probe(struct device *dev)
 {
     u_long base_addr = dev->base_addr;
 
@@ -150,6 +150,9 @@
 #ifdef CONFIG_AT1500
 	&& at1500_probe(dev)
 #endif
+#ifdef CONFIG_CS89x0
+ 	&& cs89x0_probe(dev)
+#endif
 #ifdef CONFIG_AT1700
 	&& at1700_probe(dev)
 #endif
@@ -269,6 +272,17 @@
 #   undef	NEXT_DEV
 #   define	NEXT_DEV	(&arcnet_dev)
 #endif
+
+#if defined(CONFIG_LTPC)
+    extern int ltpc_probe(struct device *);
+    static struct device dev_ltpc = {
+        "ltalk0\0   ",
+                0, 0, 0, 0,
+                0x0, 0,
+                0, 0, 0, NEXT_DEV, ltpc_probe };
+#   undef NEXT_DEV
+#   define NEXT_DEV	(&dev_ltpc)
+#endif  /* LTPC */
 
 /* The first device defaults to I/O base '0', which means autoprobe. */
 #ifndef ETH0_ADDR
diff -u --recursive --new-file v2.1.24/linux/drivers/net/a2065.c linux/drivers/net/a2065.c
--- v2.1.24/linux/drivers/net/a2065.c	Sun Dec 22 16:37:31 1996
+++ linux/drivers/net/a2065.c	Sun Feb  2 15:18:36 1997
@@ -122,7 +122,7 @@
 	int lance_log_rx_bufs, lance_log_tx_bufs;
 	int rx_ring_mod_mask, tx_ring_mod_mask;
 
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	int tpe;		      /* cable-selection is TPE */
 	int auto_select;	      /* cable-selection by carrier */
 	unsigned short busmaster_regval;
@@ -645,7 +645,7 @@
 	return status;
 }
 
-static struct enet_statistics *lance_get_stats (struct device *dev)
+static struct net_device_stats *lance_get_stats (struct device *dev)
 {
 	struct lance_private *lp = (struct lance_private *) dev->priv;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/apricot.c linux/drivers/net/apricot.c
--- v2.1.24/linux/drivers/net/apricot.c	Tue Dec 31 21:41:02 1996
+++ linux/drivers/net/apricot.c	Sun Feb  2 15:18:36 1997
@@ -162,7 +162,7 @@
     struct i596_cmd *cmd_head;
     int cmd_backlog;
     unsigned long last_cmd;
-    struct enet_statistics stats;
+    struct net_device_stats stats;
 };
 
 char init_setup[] = {
@@ -185,7 +185,7 @@
 static int i596_start_xmit(struct sk_buff *skb, struct device *dev);
 static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int i596_close(struct device *dev);
-static struct enet_statistics *i596_get_stats(struct device *dev);
+static struct net_device_stats *i596_get_stats(struct device *dev);
 static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd);
 static void print_eth(char *);
 static void set_multicast_list(struct device *dev);
@@ -942,7 +942,7 @@
     return 0;
 }
 
-static struct enet_statistics *
+static struct net_device_stats *
 i596_get_stats(struct device *dev)
 {
     struct i596_private *lp = (struct i596_private *)dev->priv;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v2.1.24/linux/drivers/net/arcnet.c	Thu Jan  2 15:55:16 1997
+++ linux/drivers/net/arcnet.c	Sun Feb  2 15:18:36 1997
@@ -535,7 +535,7 @@
 
 /* Information that needs to be kept for each board. */
 struct arcnet_local {
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	u_short sequence;	/* sequence number (incs with each packet) */
 	u_char stationid,	/* our 8-bit station address */
 		recbuf,		/* receive buffer # (0 or 1) */
@@ -609,7 +609,7 @@
 static void arcnetA_rx(struct device *dev,u_char *buf,
 	int length,u_char saddr, u_char daddr);
 
-static struct enet_statistics *arcnet_get_stats(struct device *dev);
+static struct net_device_stats *arcnet_get_stats(struct device *dev);
 
 int arcnetA_header(struct sk_buff *skb,struct device *dev,
 		unsigned short type,void *daddr,void *saddr,unsigned len);
@@ -2580,8 +2580,7 @@
  * closed.
  */
 
-static struct enet_statistics *
-arcnet_get_stats(struct device *dev)
+static struct net_device_stats *arcnet_get_stats(struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c
--- v2.1.24/linux/drivers/net/ariadne.c	Sun Dec 22 16:37:31 1996
+++ linux/drivers/net/ariadne.c	Sun Feb  2 15:18:36 1997
@@ -103,7 +103,7 @@
     u_short *rx_buff[RX_RING_SIZE];
     int cur_tx, cur_rx;			/* The next free ring entry */
     int dirty_tx;			/* The ring entries to be free()ed. */
-    struct enet_statistics stats;
+    struct net_device_stats stats;
     char tx_full;
     unsigned long lock;
     int key;
@@ -128,7 +128,7 @@
 static int ariadne_rx(struct device *dev);
 static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp);
 static int ariadne_close(struct device *dev);
-static struct enet_statistics *ariadne_get_stats(struct device *dev);
+static struct net_device_stats *ariadne_get_stats(struct device *dev);
 #ifdef HAVE_MULTICAST
 static void set_multicast_list(struct device *dev);
 #endif
@@ -782,7 +782,7 @@
 }
 
 
-static struct enet_statistics *ariadne_get_stats(struct device *dev)
+static struct net_device_stats *ariadne_get_stats(struct device *dev)
 {
     struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
     struct AriadneBoard *board = priv->board;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- v2.1.24/linux/drivers/net/at1700.c	Tue Dec 31 21:41:03 1996
+++ linux/drivers/net/at1700.c	Sun Feb  2 15:18:36 1997
@@ -67,7 +67,7 @@
 
 /* Information that need to be kept for each board. */
 struct net_local {
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	uint tx_started:1;			/* Number of packet on the Tx queue. */
 	uchar tx_queue;				/* Number of packet on the Tx queue. */
 	ushort tx_queue_len;		/* Current length of the Tx queue. */
@@ -120,7 +120,7 @@
 static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void net_rx(struct device *dev);
 static int net_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 
@@ -592,8 +592,8 @@
 
 /* Get the current statistics.	This may be called with the card open or
    closed. */
-static struct enet_statistics *
-net_get_stats(struct device *dev)
+   
+static struct net_device_stats *net_get_stats(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c
--- v2.1.24/linux/drivers/net/atari_bionet.c	Tue Dec 31 21:41:03 1996
+++ linux/drivers/net/atari_bionet.c	Sun Feb  2 15:18:36 1997
@@ -136,7 +136,7 @@
 /* Information that need to be kept for each board.
  */
 struct net_local {
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	long open_time;			/* for debugging */
 	int  poll_time;			/* polling time varies with net load */
 };
@@ -157,7 +157,7 @@
 static int bionet_send_packet(struct sk_buff *skb, struct device *dev);
 static void bionet_poll_rx(struct device *);
 static int bionet_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void bionet_tick(unsigned long);
 
 static struct timer_list bionet_timer = { NULL, NULL, 0, 0, bionet_tick };
@@ -594,8 +594,8 @@
 /* Get the current statistics.
    This may be called with the card open or closed.
  */
-static struct enet_statistics *
-net_get_stats(struct device *dev) {
+static struct net_device_stats *net_get_stats(struct device *dev) 
+{
 	struct net_local *lp = (struct net_local *)dev->priv;
 	return &lp->stats;
 }
diff -u --recursive --new-file v2.1.24/linux/drivers/net/atari_pamsnet.c linux/drivers/net/atari_pamsnet.c
--- v2.1.24/linux/drivers/net/atari_pamsnet.c	Tue Dec 31 21:41:03 1996
+++ linux/drivers/net/atari_pamsnet.c	Sun Feb  2 15:18:36 1997
@@ -134,7 +134,7 @@
 /* Information that need to be kept for each board.
  */
 struct net_local {
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	long open_time;			/* for debugging */
 	int  poll_time;			/* polling time varies with net load */
 };
@@ -167,7 +167,7 @@
 static int pamsnet_send_packet(struct sk_buff *skb, struct device *dev);
 static void pamsnet_poll_rx(struct device *);
 static int pamsnet_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void pamsnet_tick(unsigned long);
 
 static void pamsnet_intr(int irq, void *data, struct pt_regs *fp);
@@ -866,8 +866,8 @@
 /* Get the current statistics.
    This may be called with the card open or closed.
  */
-static struct enet_statistics *
-net_get_stats(struct device *dev) {
+static struct net_device_stats *net_get_stats(struct device *dev) 
+{
 	struct net_local *lp = (struct net_local *)dev->priv;
 	return &lp->stats;
 }
diff -u --recursive --new-file v2.1.24/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c
--- v2.1.24/linux/drivers/net/atarilance.c	Tue Dec 31 21:41:03 1996
+++ linux/drivers/net/atarilance.c	Sun Feb  2 15:18:36 1997
@@ -223,7 +223,7 @@
 	int					dirty_tx;		/* Ring entries to be freed. */
 						/* copy function */
 	void				*(*memcpy_f)( void *, const void *, size_t );
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 /* These two must be ints for set_bit() */
 	int					tx_full;
 	int					lock;
@@ -346,7 +346,7 @@
 static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp );
 static int lance_rx( struct device *dev );
 static int lance_close( struct device *dev );
-static struct enet_statistics *lance_get_stats( struct device *dev );
+static struct net_device_stats *lance_get_stats( struct device *dev );
 static void set_multicast_list( struct device *dev );
 static int lance_set_mac_address( struct device *dev, void *addr );
 
@@ -1072,7 +1072,7 @@
 }
 
 
-static struct enet_statistics *lance_get_stats( struct device *dev )
+static struct net_device_stats *lance_get_stats( struct device *dev )
 
 {	struct lance_private *lp = (struct lance_private *)dev->priv;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v2.1.24/linux/drivers/net/atp.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/net/atp.c	Sun Feb  2 15:18:36 1997
@@ -139,7 +139,7 @@
 static void net_rx(struct device *dev);
 static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode);
 static int net_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 
@@ -747,8 +747,7 @@
 
 /* Get the current statistics.	This may be called with the card open or
    closed. */
-static struct enet_statistics *
-net_get_stats(struct device *dev)
+static struct net_device_stats *net_get_stats(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	return &lp->stats;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/atp.h linux/drivers/net/atp.h
--- v2.1.24/linux/drivers/net/atp.h	Tue Oct 10 15:03:24 1995
+++ linux/drivers/net/atp.h	Sun Feb  2 15:18:36 1997
@@ -2,12 +2,13 @@
 #include <linux/types.h>
 #include <asm/io.h>
 
-struct net_local {
+struct net_local 
+{
 #ifdef __KERNEL__
-    struct enet_statistics stats;
+	struct net_device_stats stats;
 #endif
-    ushort saved_tx_size;
-    unsigned char
+	ushort saved_tx_size;
+	unsigned char
 	re_tx,			/* Number of packet retransmissions. */
 	tx_unit_busy,
 	addr_mode,		/* Current Rx filter e.g. promiscuous, etc. */
@@ -15,10 +16,10 @@
 };
 
 struct rx_header {
-    ushort pad;			/* The first read is always corrupted. */
-    ushort rx_count;
-    ushort rx_status;		/* Unknown bit assignments :-<.  */
-    ushort cur_addr;		/* Apparently the current buffer address(?) */
+	ushort pad;			/* The first read is always corrupted. */
+	ushort rx_count;
+	ushort rx_status;		/* Unknown bit assignments :-<.  */
+	ushort cur_addr;		/* Apparently the current buffer address(?) */
 };
 
 #define PAR_DATA	0
@@ -40,15 +41,16 @@
 
 enum page0_regs
 {
-    /* The first six registers hold the ethernet physical station address. */
-    PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5,
-    TxCNT0 = 6, TxCNT1 = 7,		/* The transmit byte count. */
-    TxSTAT = 8, RxSTAT = 9,		/* Tx and Rx status. */
-    ISR = 10, IMR = 11,			/* Interrupt status and mask. */
-    CMR1 = 12,				/* Command register 1. */
-    CMR2 = 13,				/* Command register 2. */
-    MAR = 14,				/* Memory address register. */
-    CMR2_h = 0x1d, };
+	/* The first six registers hold the ethernet physical station address. */
+	PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5,
+	TxCNT0 = 6, TxCNT1 = 7,		/* The transmit byte count. */
+	TxSTAT = 8, RxSTAT = 9,		/* Tx and Rx status. */
+	ISR = 10, IMR = 11,		/* Interrupt status and mask. */
+	CMR1 = 12,			/* Command register 1. */
+	CMR2 = 13,			/* Command register 2. */
+	MAR = 14,			/* Memory address register. */
+	CMR2_h = 0x1d, 
+};
 
 enum eepage_regs
 { PROM_CMD = 6, PROM_DATA = 7 };	/* Note that PROM_CMD is in the "high" bits. */
@@ -81,135 +83,139 @@
 
 /* An inline function used below: it differs from inb() by explicitly return an unsigned
    char, saving a truncation. */
+   
 extern inline unsigned char inbyte(unsigned short port)
 {
-    unsigned char _v;
-    __asm__ __volatile__ ("inb %w1,%b0" :"=a" (_v):"d" (port));
-    return _v;
+	unsigned char _v;
+	__asm__ __volatile__ ("inb %w1,%b0" :"=a" (_v):"d" (port));
+	return _v;
 }
 
 /* Read register OFFSET.
    This command should always be terminated with read_end(). */
+
 extern inline unsigned char read_nibble(short port, unsigned char offset)
 {
-    unsigned char retval;
-    outb(EOC+offset, port + PAR_DATA);
-    outb(RdAddr+offset, port + PAR_DATA);
-    inbyte(port + PAR_STATUS);		/* Settling time delay */
-    retval = inbyte(port + PAR_STATUS);
-    outb(EOC+offset, port + PAR_DATA);
+	unsigned char retval;
+	outb(EOC+offset, port + PAR_DATA);
+	outb(RdAddr+offset, port + PAR_DATA);
+	inbyte(port + PAR_STATUS);		/* Settling time delay */
+	retval = inbyte(port + PAR_STATUS);
+	outb(EOC+offset, port + PAR_DATA);
 
-    return retval;
+	return retval;
 }
 
 /* Functions for bulk data read.  The interrupt line is always disabled. */
 /* Get a byte using read mode 0, reading data from the control lines. */
+
 extern inline unsigned char read_byte_mode0(short ioaddr)
 {
-    unsigned char low_nib;
+	unsigned char low_nib;
 
-    outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
-    inbyte(ioaddr + PAR_STATUS);
-    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
-    outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
-    inbyte(ioaddr + PAR_STATUS);	/* Settling time delay -- needed!  */
-    inbyte(ioaddr + PAR_STATUS);	/* Settling time delay -- needed!  */
-    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+	outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
+	inbyte(ioaddr + PAR_STATUS);
+	low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+	outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
+	inbyte(ioaddr + PAR_STATUS);	/* Settling time delay -- needed!  */
+	inbyte(ioaddr + PAR_STATUS);	/* Settling time delay -- needed!  */
+	return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
 }
 
 /* The same as read_byte_mode0(), but does multiple inb()s for stability. */
+
 extern inline unsigned char read_byte_mode2(short ioaddr)
 {
-    unsigned char low_nib;
+	unsigned char low_nib;
 
-    outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
-    inbyte(ioaddr + PAR_STATUS);
-    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
-    outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
-    inbyte(ioaddr + PAR_STATUS);	/* Settling time delay -- needed!  */
-    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+	outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
+	inbyte(ioaddr + PAR_STATUS);
+	low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+	outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
+	inbyte(ioaddr + PAR_STATUS);	/* Settling time delay -- needed!  */
+	return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
 }
 
 /* Read a byte through the data register. */
+
 extern inline unsigned char read_byte_mode4(short ioaddr)
 {
-    unsigned char low_nib;
+	unsigned char low_nib;
 
-    outb(RdAddr | MAR, ioaddr + PAR_DATA);
-    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
-    outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
-    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+	outb(RdAddr | MAR, ioaddr + PAR_DATA);
+	low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+	outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
+	return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
 }
 
 /* Read a byte through the data register, double reading to allow settling. */
+
 extern inline unsigned char read_byte_mode6(short ioaddr)
 {
-    unsigned char low_nib;
+	unsigned char low_nib;
 
-    outb(RdAddr | MAR, ioaddr + PAR_DATA);
-    inbyte(ioaddr + PAR_STATUS);
-    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
-    outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
-    inbyte(ioaddr + PAR_STATUS);
-    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+	outb(RdAddr | MAR, ioaddr + PAR_DATA);
+	inbyte(ioaddr + PAR_STATUS);
+	low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+	outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
+	inbyte(ioaddr + PAR_STATUS);
+	return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
 }
 
-extern inline void
-write_reg(short port, unsigned char reg, unsigned char value)
+extern inline void write_reg(short port, unsigned char reg, unsigned char value)
 {
-    unsigned char outval;
-    outb(EOC | reg, port + PAR_DATA);
-    outval = WrAddr | reg;
-    outb(outval, port + PAR_DATA);
-    outb(outval, port + PAR_DATA);	/* Double write for PS/2. */
+	unsigned char outval;
+	outb(EOC | reg, port + PAR_DATA);
+	outval = WrAddr | reg;
+	outb(outval, port + PAR_DATA);
+	outb(outval, port + PAR_DATA);	/* Double write for PS/2. */
 
-    outval &= 0xf0;
-    outval |= value;
-    outb(outval, port + PAR_DATA);
-    outval &= 0x1f;
-    outb(outval, port + PAR_DATA);
-    outb(outval, port + PAR_DATA);
+	outval &= 0xf0;
+	outval |= value;
+	outb(outval, port + PAR_DATA);
+	outval &= 0x1f;
+	outb(outval, port + PAR_DATA);
+	outb(outval, port + PAR_DATA);
 
-    outb(EOC | outval, port + PAR_DATA);
+	outb(EOC | outval, port + PAR_DATA);
 }
 
-extern inline void
-write_reg_high(short port, unsigned char reg, unsigned char value)
+extern inline void write_reg_high(short port, unsigned char reg, unsigned char value)
 {
-    unsigned char outval = EOC | HNib | reg;
+	unsigned char outval = EOC | HNib | reg;
 
-    outb(outval, port + PAR_DATA);
-    outval &= WrAddr | HNib | 0x0f;
-    outb(outval, port + PAR_DATA);
-    outb(outval, port + PAR_DATA);	/* Double write for PS/2. */
+	outb(outval, port + PAR_DATA);
+	outval &= WrAddr | HNib | 0x0f;
+	outb(outval, port + PAR_DATA);
+	outb(outval, port + PAR_DATA);	/* Double write for PS/2. */
 
-    outval = WrAddr | HNib | value;
-    outb(outval, port + PAR_DATA);
-    outval &= HNib | 0x0f;		/* HNib | value */
-    outb(outval, port + PAR_DATA);
-    outb(outval, port + PAR_DATA);
+	outval = WrAddr | HNib | value;
+	outb(outval, port + PAR_DATA);
+	outval &= HNib | 0x0f;		/* HNib | value */
+	outb(outval, port + PAR_DATA);
+	outb(outval, port + PAR_DATA);
 
-    outb(EOC | HNib | outval, port + PAR_DATA);
+	outb(EOC | HNib | outval, port + PAR_DATA);
 }
 
 /* Write a byte out using nibble mode.  The low nibble is written first. */
-extern inline void
-write_reg_byte(short port, unsigned char reg, unsigned char value)
+
+extern inline void write_reg_byte(short port, unsigned char reg, unsigned char value)
 {
-    unsigned char outval;
-    outb(EOC | reg, port + PAR_DATA); 	/* Reset the address register. */
-    outval = WrAddr | reg;
-    outb(outval, port + PAR_DATA);
-    outb(outval, port + PAR_DATA);	/* Double write for PS/2. */
-
-    outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA);
-    outb(value & 0x0f, port + PAR_DATA);
-    value >>= 4;
-    outb(value, port + PAR_DATA);
-    outb(0x10 | value, port + PAR_DATA);
-    outb(0x10 | value, port + PAR_DATA);
+	unsigned char outval;
+	outb(EOC | reg, port + PAR_DATA); 	/* Reset the address register. */
+	outval = WrAddr | reg;
+	outb(outval, port + PAR_DATA);
+	outb(outval, port + PAR_DATA);		/* Double write for PS/2. */
+
+	outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA);
+	outb(value & 0x0f, port + PAR_DATA);
+	value >>= 4;
+	outb(value, port + PAR_DATA);
+	outb(0x10 | value, port + PAR_DATA);
+	outb(0x10 | value, port + PAR_DATA);
 
-    outb(EOC  | value, port + PAR_DATA); 	/* Reset the address register. */
+	outb(EOC  | value, port + PAR_DATA); 	/* Reset the address register. */
 }
 
 /*
@@ -219,30 +225,32 @@
  * It should only be needed when there is skew between the individual data
  * lines.
  */
+
 extern inline void write_byte_mode0(short ioaddr, unsigned char value)
 {
-    outb(value & 0x0f, ioaddr + PAR_DATA);
-    outb((value>>4) | 0x10, ioaddr + PAR_DATA);
+	outb(value & 0x0f, ioaddr + PAR_DATA);
+	outb((value>>4) | 0x10, ioaddr + PAR_DATA);
 }
 
 extern inline void write_byte_mode1(short ioaddr, unsigned char value)
 {
-    outb(value & 0x0f, ioaddr + PAR_DATA);
-    outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL);
-    outb((value>>4) | 0x10, ioaddr + PAR_DATA);
-    outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL);
+	outb(value & 0x0f, ioaddr + PAR_DATA);
+	outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL);
+	outb((value>>4) | 0x10, ioaddr + PAR_DATA);
+	outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL);
 }
 
 /* Write 16bit VALUE to the packet buffer: the same as above just doubled. */
+
 extern inline void write_word_mode0(short ioaddr, unsigned short value)
 {
-    outb(value & 0x0f, ioaddr + PAR_DATA);
-    value >>= 4;
-    outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
-    value >>= 4;
-    outb(value & 0x0f, ioaddr + PAR_DATA);
-    value >>= 4;
-    outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
+	outb(value & 0x0f, ioaddr + PAR_DATA);
+	value >>= 4;
+	outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
+	value >>= 4;
+	outb(value & 0x0f, ioaddr + PAR_DATA);
+	value >>= 4;
+	outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
 }
 
 /*  EEPROM_Ctrl bits. */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/bpqether.c linux/drivers/net/bpqether.c
--- v2.1.24/linux/drivers/net/bpqether.c	Thu Jan  2 15:55:17 1997
+++ linux/drivers/net/bpqether.c	Sun Feb  2 15:18:36 1997
@@ -122,7 +122,7 @@
 	char   ethname[14];		/* ether device name */
 	struct device *ethdev;		/* link to ethernet device */
 	struct device axdev;		/* bpq device (bpq#) */
-	struct enet_statistics stats;	/* some statistics */
+	struct net_device_stats stats;	/* some statistics */
 	char   dest_addr[6];		/* ether destination address */
 	char   acpt_addr[6];		/* accept ether frames from this address only */
 } *bpq_devices = NULL;
@@ -331,7 +331,7 @@
 /*
  *	Statistics
  */
-static struct enet_statistics *bpq_get_stats(struct device *dev)
+static struct net_device_stats *bpq_get_stats(struct device *dev)
 {
 	struct bpqdev *bpq;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.1.24/linux/drivers/net/cs89x0.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/cs89x0.c	Sun Feb  2 15:18:36 1997
@@ -0,0 +1,1182 @@
+/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */
+/*
+	Written 1996 by Russell Nelson, with reference to skeleton.c
+	written 1993-1994 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	The author may be reached at nelson@crynwr.com, Crynwr
+	Software, 11 Grant St., Potsdam, NY 13676
+
+  Changelog:
+
+  Mike Cruse        : mcruse@cti-ltd.com
+                    : Changes for Linux 2.0 compatibility. 
+                    : Added dev_id parameter in net_interrupt(),
+                    : request_irq() and free_irq(). Just NULL for now.
+
+  Mike Cruse        : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
+                    : in net_open() and net_close() so kerneld would know
+                    : that the module is in use and wouldn't eject the 
+                    : driver prematurely.
+
+  Mike Cruse        : Rewrote init_module() and cleanup_module using 8390.c
+                    : as an example. Disabled autoprobing in init_module(),
+                    : not a good thing to do to other devices while Linux
+                    : is running from all accounts.
+*/
+
+static char *version =
+"cs89x0.c:v1.02 11/26/96 Russell Nelson <nelson@crynwr.com>\n";
+
+/* ======================= configure the driver here ======================= */
+
+/* we also support 1.2.13 */
+#define SUPPORTS_1_2_13 0
+
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 2
+#endif
+
+/* ======================= end of configuration ======================= */
+
+
+/* Always include 'config.h' first in case the user wants to turn on
+   or override something. */
+#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#define PRINTK(x) printk x
+
+/*
+  Sources:
+
+	Crynwr packet driver epktisa.
+
+	Crystal Semiconductor data sheets.
+
+*/
+
+#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 <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "cs89x0.h"
+
+/* First, a few definitions that the brave might change. */
+/* A zero-terminated list of I/O addresses to be probed. */
+static unsigned int netcard_portlist[] =
+   { 0x300, 0x320, 0x340, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
+
+static unsigned int net_debug = NET_DEBUG;
+
+/* The number of low I/O ports used by the ethercard. */
+#define NETCARD_IO_EXTENT	16
+
+/* Information that need to be kept for each board. */
+struct net_local {
+	struct net_device_stats stats;
+	int chip_type;		/* one of: CS8900, CS8920, CS8920M */
+	char chip_revision;	/* revision letter of the chip ('A'...) */
+	int send_cmd;		/* the propercommand used to send a packet. */
+	int auto_neg_cnf;
+	int adapter_cnf;
+	int isa_config;
+	int irq_map;
+	int rx_mode;
+	int curr_rx_cfg;
+        int linectl;
+        int send_underrun;      /* keep track of how many underruns in a row we get */
+	struct sk_buff *skb;
+};
+
+/* Index to functions, as function prototypes. */
+
+extern int cs89x0_probe(struct device *dev);
+
+static int cs89x0_probe1(struct device *dev, int ioaddr);
+static int net_open(struct device *dev);
+static int	net_send_packet(struct sk_buff *skb, struct device *dev);
+#if SUPPORTS_1_2_13
+static void net_interrupt(int irq, struct pt_regs *regs);
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#else
+static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void set_multicast_list(struct device *dev);
+#endif
+static void net_rx(struct device *dev);
+static int net_close(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
+static void reset_chip(struct device *dev);
+static int get_eeprom_data(struct device *dev, int off, int len, int *buffer);
+static int get_eeprom_cksum(int off, int len, int *buffer);
+static int set_mac_address(struct device *dev, void *addr);
+
+
+/* Example routines you must write ;->. */
+#define tx_done(dev) 1
+
+
+/* Check for a network adaptor of this type, and return '0' iff 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).
+   */
+#ifdef HAVE_DEVLIST
+/* Support for a alternate probe manager, which will eliminate the
+   boilerplate below. */
+struct netdev_entry netcard_drv =
+{"netcard", cs89x0_probe1, NETCARD_IO_EXTENT, netcard_portlist};
+#else
+int
+cs89x0_probe(struct device *dev)
+{
+	int i;
+	int base_addr = dev ? dev->base_addr : 0;
+
+	if (base_addr > 0x1ff)		/* Check a single specified location. */
+		return cs89x0_probe1(dev, base_addr);
+	else if (base_addr != 0)	/* Don't probe at all. */
+		return ENXIO;
+
+	for (i = 0; netcard_portlist[i]; i++) {
+		int ioaddr = netcard_portlist[i];
+		if (check_region(ioaddr, NETCARD_IO_EXTENT))
+			continue;
+		if (cs89x0_probe1(dev, ioaddr) == 0)
+			return 0;
+	}
+	printk("cs89x0: no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");
+	return ENODEV;
+}
+#endif
+
+int inline
+readreg(struct device *dev, int portno)
+{
+	outw(portno, dev->base_addr + ADD_PORT);
+	return inw(dev->base_addr + DATA_PORT);
+}
+
+void inline
+writereg(struct device *dev, int portno, int value)
+{
+	outw(portno, dev->base_addr + ADD_PORT);
+	outw(value, dev->base_addr + DATA_PORT);
+}
+
+
+int inline
+readword(struct device *dev, int portno)
+{
+	return inw(dev->base_addr + portno);
+}
+
+void inline
+writeword(struct device *dev, int portno, int value)
+{
+	outw(value, dev->base_addr + portno);
+}
+
+int
+wait_eeprom_ready(struct device *dev)
+{
+	int timeout = jiffies;
+	/* check to see if the EEPROM is ready, a timeout is used -
+	   just in case EEPROM is ready when SI_BUSY in the
+	   PP_SelfST is clear */
+	while(readreg(dev, PP_SelfST) & SI_BUSY)
+		if (jiffies - timeout >= 40)
+			return -1;
+	return 0;
+}
+
+int
+get_eeprom_data(struct device *dev, int off, int len, int *buffer)
+{
+	int i;
+
+	if (net_debug > 3) printk("EEPROM data from %x for %x:\n",off,len);
+	for (i = 0; i < len; i++) {
+		if (wait_eeprom_ready(dev) < 0) return -1;
+		/* Now send the EEPROM read command and EEPROM location to read */
+		writereg(dev, PP_EECMD, (off + i) | EEPROM_READ_CMD);
+		if (wait_eeprom_ready(dev) < 0) return -1;
+		buffer[i] = readreg(dev, PP_EEData);
+		if (net_debug > 3) printk("%04x ", buffer[i]);
+	}
+	if (net_debug > 3) printk("\n");
+        return 0;
+}
+
+int
+get_eeprom_cksum(int off, int len, int *buffer)
+{
+	int i, cksum;
+
+	cksum = 0;
+	for (i = 0; i < len; i++)
+		cksum += buffer[i];
+	cksum &= 0xffff;
+	if (cksum == 0)
+		return 0;
+	return -1;
+}
+
+/* This is the real probe routine.  Linux has a history of friendly device
+   probes on the ISA bus.  A good device probes avoids doing writes, and
+   verifies that the correct device exists and functions.  */
+
+static int cs89x0_probe1(struct device *dev, int ioaddr)
+{
+	struct net_local *lp;
+	static unsigned version_printed = 0;
+	int i;
+	unsigned rev_type = 0;
+	int eeprom_buff[CHKSUM_LEN];
+
+	/* Initialize the device structure. */
+	if (dev->priv == NULL) {
+		dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+                memset(dev->priv, 0, sizeof(struct net_local));
+        }
+	lp = (struct net_local *)dev->priv;
+
+	/* if they give us an odd I/O address, then do ONE write to
+           the address port, to get it back to address zero, where we
+           expect to find the EISA signature word. */
+	if (ioaddr & 1) {
+		ioaddr &= ~1;
+		if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
+			return ENODEV;
+		outw(PP_ChipID, ioaddr + ADD_PORT);
+	}
+
+	if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
+		return ENODEV;
+
+	/* Fill in the 'dev' fields. */
+	dev->base_addr = ioaddr;
+
+	/* get the chip type */
+	rev_type = readreg(dev, PRODUCT_ID_ADD);
+	lp->chip_type = rev_type &~ REVISON_BITS;
+	lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
+
+	/* Check the chip type and revision in order to set the correct send command
+	CS8920 revision C and CS8900 revision F can use the faster send. */
+	lp->send_cmd = TX_AFTER_381;
+	if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
+		lp->send_cmd = TX_NOW;
+	if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
+		lp->send_cmd = TX_NOW;
+
+	if (net_debug  &&  version_printed++ == 0)
+		printk(version);
+
+	printk("%s: cs89%c0%s rev %c found at %#3lx",
+	       dev->name,
+	       lp->chip_type==CS8900?'0':'2',
+	       lp->chip_type==CS8920M?"M":"",
+	       lp->chip_revision,
+	       dev->base_addr);
+
+	reset_chip(dev);
+
+	/* First check to see if an EEPROM is attached*/
+	if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
+		printk("\ncs89x0: No EEPROM, relying on command line....\n");
+	else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
+		printk("\ncs89x0: EEPROM read failed, relying on command line.\n");
+        } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
+                printk("\ncs89x0: EEPROM checksum bad, relyong on command line\n");
+        } else {
+                /* get transmission control word  but keep the autonegotiation bits */
+                if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
+                /* Store adapter configuration */
+                if (!lp->adapter_cnf) lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
+                /* Store ISA configuration */
+                lp->isa_config = eeprom_buff[ISA_CNF_OFFSET/2];
+                /* store the initial memory base address */
+                dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8;
+                for (i = 0; i < ETH_ALEN/2; i++) {
+                        dev->dev_addr[i*2] = eeprom_buff[i];
+                        dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8;
+                }
+        }
+
+
+	printk(" media %s%s%s",
+	       (lp->adapter_cnf & A_CNF_10B_T)?"RJ-45,":"",
+	       (lp->adapter_cnf & A_CNF_AUI)?"AUI,":"",
+	       (lp->adapter_cnf & A_CNF_10B_2)?"BNC,":"");
+
+	lp->irq_map = 0xffff;
+
+	/* If this is a CS8900 then no pnp soft */
+	if (lp->chip_type != CS8900 &&
+	    /* Check if the ISA IRQ has been set  */
+		(i = readreg(dev, PP_CS8920_ISAINT) & 0xff,
+		 (i != 0 && i < CS8920_NO_INTS))) {
+		if (!dev->irq)
+			dev->irq = i;
+	} else {
+		i = lp->isa_config & INT_NO_MASK;
+		if (lp->chip_type == CS8900) {
+			/* the table that follows is dependent upon how you wired up your cs8900
+			 * in your system.  The table is the same as the cs8900 engineering demo
+			 * board.  irq_map also depends on the contents of the table.  Also see
+			 * write_irq, which is the reverse mapping of the table below. */
+			switch(i) {
+			case 0: i = 10; break;
+			case 1: i = 11; break;
+			case 2: i = 12; break;
+			case 3: i =  5; break;
+			default: printk("\ncs89x0: bug: isa_config is %d\n", i);
+			}
+			lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */
+		} else {
+			int irq_map_buff[IRQ_MAP_LEN/2];
+
+			if (get_eeprom_data(dev, IRQ_MAP_EEPROM_DATA,
+					    IRQ_MAP_LEN/2,
+					    irq_map_buff) >= 0) {
+				if ((irq_map_buff[0] & 0xff) == PNP_IRQ_FRMT)
+					lp->irq_map = (irq_map_buff[0]>>8) | (irq_map_buff[1] << 8);
+			}
+		}
+		if (!dev->irq)
+			dev->irq = i;
+	}
+
+	printk(" IRQ %d", dev->irq);
+
+
+	/* print the ethernet address. */
+	for (i = 0; i < ETH_ALEN; i++)
+		printk(" %2.2x", dev->dev_addr[i]);
+
+	/* Grab the region so we can find another board if autoIRQ fails. */
+	request_region(ioaddr, NETCARD_IO_EXTENT,"cs89x0");
+
+	dev->open		= net_open;
+	dev->stop		= net_close;
+	dev->hard_start_xmit = net_send_packet;
+	dev->get_stats	= net_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+	dev->set_mac_address = &set_mac_address;
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+
+	printk("\n");
+	return 0;
+}
+
+
+
+void
+reset_chip(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int reset_start_time;
+
+	writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
+
+	/* wait 30 ms */
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + 3;
+	schedule();
+
+	if (lp->chip_type != CS8900) {
+		/* Hardware problem requires PNP registers to be reconfigured after a reset */
+		outw(PP_CS8920_ISAINT, ioaddr + ADD_PORT);
+		outb(dev->irq, ioaddr + DATA_PORT);
+		outb(0,      ioaddr + DATA_PORT + 1);
+
+		outw(PP_CS8920_ISAMemB, ioaddr + ADD_PORT);
+		outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT);
+		outb((dev->mem_start >> 24) & 0xff,   ioaddr + DATA_PORT + 1);
+	}
+	/* Wait until the chip is reset */
+	reset_start_time = jiffies;
+	while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2)
+		;
+}
+
+
+void
+control_dc_dc(struct device *dev, int on_not_off)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned int selfcontrol;
+	int timenow = jiffies;
+	/* control the DC to DC convertor in the SelfControl register.  */
+
+	selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
+	if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
+		selfcontrol |= HCB1;
+	else
+		selfcontrol &= ~HCB1;
+	writereg(dev, PP_SelfCTL, selfcontrol);
+
+	/* Wait for the DC/DC converter to power up - 500ms */
+	while (jiffies - timenow < 100)
+		;
+
+}
+
+static int
+detect_tp(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int timenow = jiffies;
+
+	if (net_debug > 1) printk("%s: Attempting TP\n", dev->name);
+
+        /* If connected to another full duplex capable 10-Base-T card the link pulses
+           seem to be lost when the auto detect bit in the LineCTL is set.
+           To overcome this the auto detect bit will be cleared whilst testing the
+           10-Base-T interface.  This would not be necessary for the sparrow chip but
+           is simpler to do it anyway. */
+	writereg(dev, PP_LineCTL, lp->linectl &~ AUI_ONLY);
+	control_dc_dc(dev, 0);
+
+        /* Delay for the hardware to work out if the TP cable is present - 150ms */
+	for (timenow = jiffies; jiffies - timenow < 15; )
+                ;
+	if ((readreg(dev, PP_LineST) & LINK_OK) == 0)
+		return 0;
+
+	if (lp->chip_type != CS8900) {
+
+		writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK);
+
+		if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
+			printk("%s: negotiating duplex...\n",dev->name);
+			while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) {
+				if (jiffies - timenow > 4000) {
+					printk("**** Full / half duplex auto-negotiation timed out ****\n");
+					break;
+				}
+			}
+		}
+		if (readreg(dev, PP_AutoNegST) & FDX_ACTIVE)
+			printk("%s: using full duplex\n", dev->name);
+		else
+			printk("%s: using half duplex\n", dev->name);
+	}
+
+	return A_CNF_MEDIA_10B_T;
+}
+
+/* send a test packet - return true if carrier bits are ok */
+int
+send_test_pkt(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
+				 0, 46, /* A 46 in network order */
+				 0, 0, /* DSAP=0 & SSAP=0 fields */
+				 0xf3, 0 /* Control (Test Req + P bit set) */ };
+	long timenow = jiffies;
+
+	writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON);
+
+	memcpy(test_packet,          dev->dev_addr, ETH_ALEN);
+	memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN);
+
+        outw(TX_AFTER_ALL, ioaddr + TX_CMD_PORT);
+        outw(ETH_ZLEN, ioaddr + TX_LEN_PORT);
+
+	/* Test to see if the chip has allocated memory for the packet */
+	while (jiffies - timenow < 5)
+		if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW)
+			break;
+	if (jiffies - timenow >= 5)
+		return 0;	/* this shouldn't happen */
+
+	/* Write the contents of the packet */
+	if (dev->mem_start) {
+		memcpy((void *)dev->mem_start + PP_TxFrame, test_packet, ETH_ZLEN);
+	} else {
+		outsw(ioaddr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1);
+	}
+
+	if (net_debug > 1) printk("Sending test packet ");
+	/* wait a couple of jiffies for packet to be received */
+	for (timenow = jiffies; jiffies - timenow < 3; )
+                ;
+        if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
+                if (net_debug > 1) printk("succeeded\n");
+                return 1;
+        }
+	if (net_debug > 1) printk("failed\n");
+	return 0;
+}
+
+
+int
+detect_aui(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	if (net_debug > 1) printk("%s: Attempting AUI\n", dev->name);
+	control_dc_dc(dev, 0);
+
+	writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);
+
+	if (send_test_pkt(dev))
+		return A_CNF_MEDIA_AUI;
+	else
+		return 0;
+}
+
+int
+detect_bnc(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	if (net_debug > 1) printk("%s: Attempting BNC\n", dev->name);
+	control_dc_dc(dev, 1);
+
+	writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);
+
+	if (send_test_pkt(dev))
+		return A_CNF_MEDIA_10B_2;
+	else
+		return 0;
+}
+
+
+void
+write_irq(struct device *dev, int chip_type, int irq)
+{
+	int i;
+
+	if (chip_type == CS8900) {
+		switch(irq) {
+		case 10: i = 0; break;
+		case 11: i = 1; break;
+		case 12: i = 2; break;
+		case 5: i =  3; break;
+		default: i = 3; break;
+		}
+		writereg(dev, PP_CS8900_ISAINT, i);
+	} else {
+		writereg(dev, PP_CS8920_ISAINT, irq);
+	}
+}
+
+/* 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.
+   */
+static int
+net_open(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int result = 0;
+	int i;
+
+	if (dev->irq < 2) {
+		/* Allow interrupts to be generated by the chip */
+		writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
+		for (i = 2; i < CS8920_NO_INTS; i++) if ((1 << dev->irq) & lp->irq_map) {
+#if SUPPORTS_1_2_13
+			if (request_irq (i, NULL, 0, "bogus") != -EBUSY) {
+#else
+			if (request_irq (i, NULL, 0, "bogus", NULL) != -EBUSY) {
+#endif
+#if 0
+				/* Twinkle the interrupt, and check if it's seen. */
+				autoirq_setup(0);
+				write_irq(dev, lp->chip_type, i);
+				writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT);
+				if (i == autoirq_report(0)	 /* It's a good IRQ line! */
+				    && request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0") == 0)
+					break;
+#else
+				write_irq(dev, lp->chip_type, i);
+				writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT);
+#if SUPPORTS_1_2_13
+				if (request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0") == 0)
+#else
+				if (request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0", NULL) == 0)
+#endif
+					break;
+#endif
+			}
+		}
+
+
+		if (i >= CS8920_NO_INTS) {
+			writereg(dev, PP_BusCTL, 0);	/* disable interrupts. */
+			return -EAGAIN;
+		}
+	} else {
+		if (((1 << dev->irq) & lp->irq_map) == 0) {
+			printk("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
+                               dev->name, dev->irq, lp->irq_map);
+			return -EAGAIN;
+		}
+		writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
+		write_irq(dev, lp->chip_type, dev->irq);
+#if SUPPORTS_1_2_13
+		if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0")) {
+#else
+		if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", NULL)) {
+#endif
+			return -EAGAIN;
+		}
+	}
+
+	irq2dev_map[dev->irq] = dev;
+
+	/* set the Ethernet address */
+	for (i=0; i < ETH_ALEN/2; i++)
+		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
+
+	/* while we're testing the interface, leave interrupts disabled */
+	writereg(dev, PP_BusCTL, MEMORY_ON);
+
+	/* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */
+	if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) && (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH))
+                lp->linectl = LOW_RX_SQUELCH;
+	else
+                lp->linectl = 0;
+
+        /* check to make sure that they have the "right" hardware available */
+	switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
+	case A_CNF_MEDIA_10B_T: result = lp->adapter_cnf & A_CNF_10B_T; break;
+	case A_CNF_MEDIA_AUI:   result = lp->adapter_cnf & A_CNF_AUI; break;
+	case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
+        default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
+        }
+        if (!result) {
+                printk("%s: EEPROM is configured for unavailable media\n", dev->name);
+        release_irq:
+                writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
+#if SUPPORTS_1_2_13
+                free_irq(dev->irq);
+#else
+                free_irq(dev->irq, NULL);
+#endif
+                irq2dev_map[dev->irq] = 0;
+		return -EAGAIN;
+	}
+
+        /* set the hardware to the configured choice */
+	switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
+	case A_CNF_MEDIA_10B_T:
+                result = detect_tp(dev);
+                if (!result) printk("%s: 10Base-T (RJ-45) has no cable\n", dev->name);
+                if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                        result = A_CNF_MEDIA_10B_T; /* Yes! I don't care if I see a link pulse */
+		break;
+	case A_CNF_MEDIA_AUI:
+                result = detect_aui(dev);
+                if (!result) printk("%s: 10Base-5 (AUI) has no cable\n", dev->name);
+                if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                        result = A_CNF_MEDIA_AUI; /* Yes! I don't care if I see a carrrier */
+		break;
+	case A_CNF_MEDIA_10B_2:
+                result = detect_bnc(dev);
+                if (!result) printk("%s: 10Base-2 (BNC) has no cable\n", dev->name);
+                if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                        result = A_CNF_MEDIA_10B_2; /* Yes! I don't care if I can xmit a packet */
+		break;
+	case A_CNF_MEDIA_AUTO:
+		writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET);
+		if (lp->adapter_cnf & A_CNF_10B_T)
+			if ((result = detect_tp(dev)) != 0)
+				break;
+		if (lp->adapter_cnf & A_CNF_AUI)
+			if ((result = detect_aui(dev)) != 0)
+				break;
+		if (lp->adapter_cnf & A_CNF_10B_2)
+			if ((result = detect_bnc(dev)) != 0)
+				break;
+		printk("%s: no media detected\n", dev->name);
+                goto release_irq;
+	}
+	switch(result) {
+	case 0: printk("%s: no network cable attached to configured media\n", dev->name);
+                goto release_irq;
+	case A_CNF_MEDIA_10B_T: printk("%s: using 10Base-T (RJ-45)\n", dev->name);break;
+	case A_CNF_MEDIA_AUI:   printk("%s: using 10Base-5 (AUI)\n", dev->name);break;
+	case A_CNF_MEDIA_10B_2: printk("%s: using 10Base-2 (BNC)\n", dev->name);break;
+	default: printk("%s: unexpected result was %x\n", dev->name, result); goto release_irq;
+	}
+
+	/* Turn on both receive and transmit operations */
+	writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
+
+	/* Receive only error free packets addressed to this card */
+	lp->rx_mode = 0;
+	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
+
+	lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
+	if (lp->isa_config & STREAM_TRANSFER)
+		lp->curr_rx_cfg |= RX_STREAM_ENBL;
+
+	writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
+
+	writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |
+	       TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
+
+	writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |
+		 TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
+
+	/* now that we've got our act together, enable everything */
+	writereg(dev, PP_BusCTL, ENABLE_IRQ
+                 );
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+        MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int
+net_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	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. */
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 5)
+			return 1;
+		if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
+			   tx_done(dev) ? "IRQ conflict" : "network cable problem");
+		/* Try to restart the adaptor. */
+		dev->tbusy=0;
+		dev->trans_start = jiffies;
+	}
+
+	/* 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 {
+		struct net_local *lp = (struct net_local *)dev->priv;
+		short ioaddr = dev->base_addr;
+		unsigned long flags;
+
+		if (net_debug > 3)printk("%s: sent %ld byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+
+		/* keep the upload from being interrupted, since we
+                   ask the chip to start transmitting before the
+                   whole packet has been completely uploaded. */
+		save_flags(flags);
+		cli();
+
+		/* initiate a transmit sequence */
+		outw(lp->send_cmd, ioaddr + TX_CMD_PORT);
+		outw(skb->len, ioaddr + TX_LEN_PORT);
+
+		/* Test to see if the chip has allocated memory for the packet */
+		if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
+			/* Gasp!  It hasn't.  But that shouldn't happen since
+			   we're waiting for TxOk, so return 1 and requeue this packet. */
+			restore_flags(flags);
+			return 1;
+		}
+
+		/* Write the contents of the packet */
+                outsw(ioaddr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
+
+		restore_flags(flags);
+		dev->trans_start = jiffies;
+	}
+	dev_kfree_skb (skb, FREE_WRITE);
+
+	return 0;
+}
+
+/* The typical workload of the driver:
+   Handle the network interface interrupts. */
+static void
+#if SUPPORTS_1_2_13
+net_interrupt(int irq, struct pt_regs * regs)
+#else
+net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+#endif
+{
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	struct net_local *lp;
+	int ioaddr, status;
+
+	if (dev == NULL) {
+		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+	if (dev->interrupt)
+		printk("%s: Re-entering the interrupt handler.\n", dev->name);
+	dev->interrupt = 1;
+
+	ioaddr = dev->base_addr;
+	lp = (struct net_local *)dev->priv;
+
+	/* we MUST read all the events out of the ISQ, otherwise we'll never
+           get interrupted again.  As a consequence, we can't have any limit
+           on the number of times we loop in the interrupt handler.  The
+           hardware guarantees that eventually we'll run out of events.  Of
+           course, if you're on a slow machine, and packets are arriving
+           faster than you can read them off, you're screwed.  Hasta la
+           vista, baby!  */
+	while ((status = readword(dev, ISQ_PORT))) {
+		if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status);
+		switch(status & ISQ_EVENT_MASK) {
+		case ISQ_RECEIVER_EVENT:
+			/* Got a packet(s). */
+			net_rx(dev);
+			break;
+		case ISQ_TRANSMITTER_EVENT:
+			lp->stats.tx_packets++;
+			dev->tbusy = 0;
+			mark_bh(NET_BH);	/* Inform upper layers. */
+			if ((status & TX_OK) == 0) lp->stats.tx_errors++;
+			if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
+			if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
+			if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
+			if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
+			break;
+		case ISQ_BUFFER_EVENT:
+			if (status & READY_FOR_TX) {
+				/* we tried to transmit a packet earlier,
+                                   but inexplicably ran out of buffers.
+                                   That shouldn't happen since we only ever
+                                   load one packet.  Shrug.  Do the right
+                                   thing anyway. */
+				dev->tbusy = 0;
+				mark_bh(NET_BH);	/* Inform upper layers. */
+			}
+			if (status & TX_UNDERRUN) {
+				if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);
+                                lp->send_underrun++;
+                                if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
+                                else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
+                        }
+			break;
+		case ISQ_RX_MISS_EVENT:
+			lp->stats.rx_missed_errors += (status >>6);
+			break;
+		case ISQ_TX_COL_EVENT:
+			lp->stats.collisions += (status >>6);
+			break;
+		}
+	}
+	dev->interrupt = 0;
+	return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+net_rx(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	struct sk_buff *skb;
+	int status, length;
+
+	status = inw(ioaddr + RX_FRAME_PORT);
+	length = inw(ioaddr + RX_FRAME_PORT);
+	if ((status & RX_OK) == 0) {
+		lp->stats.rx_errors++;
+		if (status & RX_RUNT) lp->stats.rx_length_errors++;
+		if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;
+		if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
+			/* per str 172 */
+			lp->stats.rx_crc_errors++;
+		if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
+		return;
+	}
+
+	/* Malloc up new buffer. */
+	skb = alloc_skb(length, GFP_ATOMIC);
+	if (skb == NULL) {
+		printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+		lp->stats.rx_dropped++;
+		return;
+	}
+	skb->len = length;
+	skb->dev = dev;
+
+        insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1);
+	if (length & 1)
+		skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT);
+
+	if (net_debug > 3)printk("%s: received %d byte packet of type %x\n",
+                                 dev->name, length,
+                                 (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+#if !SUPPORTS_1_2_13
+        skb->protocol=eth_type_trans(skb,dev);
+#endif
+	netif_rx(skb);
+	lp->stats.rx_packets++;
+	return;
+}
+
+/* The inverse routine to net_open(). */
+static int
+net_close(struct device *dev)
+{
+
+	writereg(dev, PP_RxCFG, 0);
+	writereg(dev, PP_TxCFG, 0);
+	writereg(dev, PP_BufCFG, 0);
+	writereg(dev, PP_BusCTL, 0);
+
+	dev->start = 0;
+
+#if SUPPORTS_1_2_13
+	free_irq(dev->irq);
+#else
+	free_irq(dev->irq, NULL);
+#endif
+
+	irq2dev_map[dev->irq] = 0;
+
+	/* Update the statistics here. */
+
+        MOD_DEC_USE_COUNT;
+	return 0;
+
+}
+
+/* Get the current statistics.	This may be called with the card open or
+   closed. */
+static struct net_device_stats *
+net_get_stats(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	cli();
+	/* Update the statistics from the device registers. */
+	lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
+	lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
+	sti();
+
+	return &lp->stats;
+}
+
+#if SUPPORTS_1_2_13
+/* 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.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	if (num_addrs == 0)
+		lp->rx_mode = 0;
+	else if (num_addrs > 0)
+		lp->rx_mode = RX_MULTCAST_ACCEPT;
+	else if (num_addrs == -1)
+		lp->rx_mode = RX_ALL_ACCEPT;
+
+	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
+
+	/* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
+	writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
+	     (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
+
+}
+#else
+static void set_multicast_list(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	if(dev->flags&IFF_PROMISC)
+	{
+		lp->rx_mode = RX_ALL_ACCEPT;
+	}
+	else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)
+	{
+		/* The multicast-accept list is initialized to accept-all, and we
+		   rely on higher-level filtering for now. */
+		lp->rx_mode = RX_MULTCAST_ACCEPT;
+	} 
+	else
+		lp->rx_mode = 0;
+
+	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
+
+	/* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
+	writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
+	     (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
+}
+#endif
+
+
+static int
+set_mac_address(struct device *dev, void *addr)
+{
+	int i;
+	if (dev->start)
+		return -EBUSY;
+	printk("%s: Setting MAC address to ", dev->name);
+	for (i = 0; i < 6; i++)
+		printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
+	printk(".\n");
+	/* set the Ethernet address */
+	for (i=0; i < ETH_ALEN/2; i++)
+		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
+
+	return 0;
+}
+#ifdef MODULE
+#if SUPPORTS_1_2_13
+char kernel_version[] = UTS_RELEASE;
+#endif
+static char namespace[16] = "";
+static struct device dev_cs89x0 = {
+        NULL,
+        0, 0, 0, 0,
+        0, 0,
+        0, 0, 0, NULL, NULL };
+
+int io=0;
+int irq=0;
+#endif
+#ifdef MODULE
+int debug=1;
+char *media="auto";
+char *duplex="f";
+
+/*
+* media=t             - specify media type
+   or media=2
+   or media=aui
+   or medai=auto
+* duplex=f            - specify forced half/full/autonegotiate duplex
+   or duplex=h
+   or duplex=auto
+* debug=#             - debug level
+
+
+* Default Chip Configuration:
+  * DMA Burst = enabled
+  * IOCHRDY Enabled = enabled
+    * UseSA = enabled
+    * CS8900 defaults to half-duplex if not specified on command-line
+    * CS8920 defaults to autoneg if not specified on command-line
+    * Use reset defaults for other config parameters
+
+* Assumptions:
+  * media type specified is supported (circuitry is present)
+  * if memory address is > 1MB, then required mem decode hw is present
+  * if 10B-2, then agent other than driver will enable DC/DC converter
+    (hw or software util)
+
+
+*/
+
+int
+init_module(void)
+{
+	struct net_local *lp;
+
+	net_debug = debug;
+        dev_cs89x0.name = namespace;
+	dev_cs89x0.irq = irq;
+	dev_cs89x0.base_addr = io;
+        dev_cs89x0.init = cs89x0_probe;
+        dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	memset(dev_cs89x0.priv, 0, sizeof(struct net_local));
+	lp = (struct net_local *)dev_cs89x0.priv;
+
+        /* boy, they'd better get these right */
+        if (!strcmp(media, "rj45"))
+		lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;
+	if (!strcmp(media, "aui"))
+		lp->adapter_cnf = A_CNF_MEDIA_AUI   | A_CNF_AUI;
+	if (!strcmp(media, "bnc"))
+		lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2;
+
+        if (!strcmp(duplex, "auto"))
+		lp->auto_neg_cnf = AUTO_NEG_ENABLE;
+
+        if (io == 0)  {
+                printk(KERN_NOTICE "cs89x0.c: Module autoprobing not allowed.\n");
+                printk(KERN_NOTICE "cs89x0.c: Append io=0xNNN\n");
+                return -EPERM;
+        }
+        if (register_netdev(&dev_cs89x0) != 0) {
+                printk(KERN_WARNING "cs89x0.c: No card found at 0x%x\n", io);
+                return -ENXIO;
+        }
+	return 0;
+}
+
+void
+cleanup_module(void)
+{
+
+#endif
+#ifdef MODULE
+	outw(0, dev_cs89x0.base_addr + ADD_PORT);
+#endif
+#ifdef MODULE
+
+        if (dev_cs89x0.priv != NULL) {
+                /* Free up the private structure, or leak memory :-)  */
+                kfree(dev_cs89x0.priv);
+                dev_cs89x0.priv = NULL;	/* gets re-allocated by cs89x0_probe1 */
+                /* If we don't do this, we can't re-insmod it later. */
+                release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT);
+                unregister_netdev(&dev_cs89x0);
+        }
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS -c cs89x0.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ *
diff -u --recursive --new-file v2.1.24/linux/drivers/net/cs89x0.h linux/drivers/net/cs89x0.h
--- v2.1.24/linux/drivers/net/cs89x0.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/cs89x0.h	Sun Feb  2 15:18:36 1997
@@ -0,0 +1,456 @@
+/*  Copyright, 1988-1992, Russell Nelson, Crynwr Software
+
+   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, version 1.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   */
+
+#define PP_ChipID 0x0000	/* offset   0h -> Corp -ID              */
+				/* offset   2h -> Model/Product Number  */
+				/* offset   3h -> Chip Revision Number  */
+
+#define PP_ISAIOB 0x0020	/*  IO base address */
+#define PP_CS8900_ISAINT 0x0022	/*  ISA interrupt select */
+#define PP_CS8920_ISAINT 0x0370	/*  ISA interrupt select */
+#define PP_CS8900_ISADMA 0x0024	/*  ISA Rec DMA channel */
+#define PP_CS8920_ISADMA 0x0374	/*  ISA Rec DMA channel */
+#define PP_ISASOF 0x0026	/*  ISA DMA offset */
+#define PP_DmaFrameCnt 0x0028	/*  ISA DMA Frame count */
+#define PP_DmaByteCnt 0x002A	/*  ISA DMA Byte count */
+#define PP_CS8900_ISAMemB 0x002C	/*  Memory base */
+#define PP_CS8920_ISAMemB 0x0348 /*  */
+
+#define PP_ISABootBase 0x0030	/*  Boot Prom base  */
+#define PP_ISABootMask 0x0034	/*  Boot Prom Mask */
+
+/* EEPROM data and command registers */
+#define PP_EECMD 0x0040		/*  NVR Interface Command register */
+#define PP_EEData 0x0042	/*  NVR Interface Data Register */
+#define PP_DebugReg 0x0044	/*  Debug Register */
+
+#define PP_RxCFG 0x0102		/*  Rx Bus config */
+#define PP_RxCTL 0x0104		/*  Receive Control Register */
+#define PP_TxCFG 0x0106		/*  Transmit Config Register */
+#define PP_TxCMD 0x0108		/*  Transmit Command Register */
+#define PP_BufCFG 0x010A	/*  Bus configuration Register */
+#define PP_LineCTL 0x0112	/*  Line Config Register */
+#define PP_SelfCTL 0x0114	/*  Self Command Register */
+#define PP_BusCTL 0x0116	/*  ISA bus control Register */
+#define PP_TestCTL 0x0118	/*  Test Register */
+#define PP_AutoNegCTL 0x011C	/*  Auto Negotiation Ctrl */
+
+#define PP_ISQ 0x0120		/*  Interrupt Status */
+#define PP_RxEvent 0x0124	/*  Rx Event Register */
+#define PP_TxEvent 0x0128	/*  Tx Event Register */
+#define PP_BufEvent 0x012C	/*  Bus Event Register */
+#define PP_RxMiss 0x0130	/*  Receive Miss Count */
+#define PP_TxCol 0x0132		/*  Transmit Collision Count */
+#define PP_LineST 0x0134	/*  Line State Register */
+#define PP_SelfST 0x0136	/*  Self State register */
+#define PP_BusST 0x0138		/*  Bus Status */
+#define PP_TDR 0x013C		/*  Time Domain Reflectometry */
+#define PP_AutoNegST 0x013E	/*  Auto Neg Status */
+#define PP_TxCommand 0x0144	/*  Tx Command */
+#define PP_TxLength 0x0146	/*  Tx Length */
+#define PP_LAF 0x0150		/*  Hash Table */
+#define PP_IA 0x0158		/*  Physical Address Register */
+
+#define PP_RxStatus 0x0400	/*  Receive start of frame */
+#define PP_RxLength 0x0402	/*  Receive Length of frame */
+#define PP_RxFrame 0x0404	/*  Receive frame pointer */
+#define PP_TxFrame 0x0A00	/*  Transmit frame pointer */
+
+/*  Primary I/O Base Address. If no I/O base is supplied by the user, then this */
+/*  can be used as the default I/O base to access the PacketPage Area. */
+#define DEFAULTIOBASE 0x0300
+#define FIRST_IO 0x020C		/*  First I/O port to check */
+#define LAST_IO 0x037C		/*  Last I/O port to check (+10h) */
+#define ADD_MASK 0x3000		/*  Mask it use of the ADD_PORT register */
+#define ADD_SIG 0x3000		/*  Expected ID signature */
+
+#define CHIP_EISA_ID_SIG 0x630E   /*  Product ID Code for Crystal Chip (CS8900 spec 4.3) */
+
+#ifdef IBMEIPKT
+#define EISA_ID_SIG 0x4D24	/*  IBM */
+#define PART_NO_SIG 0x1010	/*  IBM */
+#define MONGOOSE_BIT 0x0000	/*  IBM */
+#else
+#define EISA_ID_SIG 0x630E	/*  PnP Vendor ID (same as chip id for Crystal board) */
+#define PART_NO_SIG 0x4000	/*  ID code CS8920 board (PnP Vendor Product code) */
+#define MONGOOSE_BIT 0x2000	/*  PART_NO_SIG + MONGOOSE_BUT => ID of mongoose */
+#endif
+
+#define PRODUCT_ID_ADD 0x0002   /*  Address of product ID */
+
+/*  Mask to find out the types of  registers */
+#define REG_TYPE_MASK 0x001F
+
+/*  Eeprom Commands */
+#define ERSE_WR_ENBL 0x00F0
+#define ERSE_WR_DISABLE 0x0000
+
+/*  Defines Control/Config register quintuplet numbers */
+#define RX_BUF_CFG 0x0003
+#define RX_CONTROL 0x0005
+#define TX_CFG 0x0007
+#define TX_COMMAND 0x0009
+#define BUF_CFG 0x000B
+#define LINE_CONTROL 0x0013
+#define SELF_CONTROL 0x0015
+#define BUS_CONTROL 0x0017
+#define TEST_CONTROL 0x0019
+
+/*  Defines Status/Count registers quintuplet numbers */
+#define RX_EVENT 0x0004
+#define TX_EVENT 0x0008
+#define BUF_EVENT 0x000C
+#define RX_MISS_COUNT 0x0010
+#define TX_COL_COUNT 0x0012
+#define LINE_STATUS 0x0014
+#define SELF_STATUS 0x0016
+#define BUS_STATUS 0x0018
+#define TDR 0x001C
+
+/* PP_RxCFG - Receive  Configuration and Interrupt Mask bit definition -  Read/write */
+#define SKIP_1 0x0040
+#define RX_STREAM_ENBL 0x0080
+#define RX_OK_ENBL 0x0100
+#define RX_DMA_ONLY 0x0200
+#define AUTO_RX_DMA 0x0400
+#define BUFFER_CRC 0x0800
+#define RX_CRC_ERROR_ENBL 0x1000
+#define RX_RUNT_ENBL 0x2000
+#define RX_EXTRA_DATA_ENBL 0x4000
+
+/* PP_RxCTL - Receive Control bit definition - Read/write */
+#define RX_IA_HASH_ACCEPT 0x0040
+#define RX_PROM_ACCEPT 0x0080
+#define RX_OK_ACCEPT 0x0100
+#define RX_MULTCAST_ACCEPT 0x0200
+#define RX_IA_ACCEPT 0x0400
+#define RX_BROADCAST_ACCEPT 0x0800
+#define RX_BAD_CRC_ACCEPT 0x1000
+#define RX_RUNT_ACCEPT 0x2000
+#define RX_EXTRA_DATA_ACCEPT 0x4000
+#define RX_ALL_ACCEPT (RX_PROM_ACCEPT|RX_BAD_CRC_ACCEPT|RX_RUNT_ACCEPT|RX_EXTRA_DATA_ACCEPT)
+/*  Default receive mode - individually addressed, broadcast, and error free */
+#define DEF_RX_ACCEPT (RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | RX_OK_ACCEPT)
+
+/* PP_TxCFG - Transmit Configuration Interrupt Mask bit definition - Read/write */
+#define TX_LOST_CRS_ENBL 0x0040
+#define TX_SQE_ERROR_ENBL 0x0080
+#define TX_OK_ENBL 0x0100
+#define TX_LATE_COL_ENBL 0x0200
+#define TX_JBR_ENBL 0x0400
+#define TX_ANY_COL_ENBL 0x0800
+#define TX_16_COL_ENBL 0x8000
+
+/* PP_TxCMD - Transmit Command bit definition - Read-only */
+#define TX_START_4_BYTES 0x0000
+#define TX_START_64_BYTES 0x0040
+#define TX_START_128_BYTES 0x0080
+#define TX_START_ALL_BYTES 0x00C0
+#define TX_FORCE 0x0100
+#define TX_ONE_COL 0x0200
+#define TX_TWO_PART_DEFF_DISABLE 0x0400
+#define TX_NO_CRC 0x1000
+#define TX_RUNT 0x2000
+
+/* PP_BufCFG - Buffer Configuration Interrupt Mask bit definition - Read/write */
+#define GENERATE_SW_INTERRUPT 0x0040
+#define RX_DMA_ENBL 0x0080
+#define READY_FOR_TX_ENBL 0x0100
+#define TX_UNDERRUN_ENBL 0x0200
+#define RX_MISS_ENBL 0x0400
+#define RX_128_BYTE_ENBL 0x0800
+#define TX_COL_COUNT_OVRFLOW_ENBL 0x1000
+#define RX_MISS_COUNT_OVRFLOW_ENBL 0x2000
+#define RX_DEST_MATCH_ENBL 0x8000
+
+/* PP_LineCTL - Line Control bit definition - Read/write */
+#define SERIAL_RX_ON 0x0040
+#define SERIAL_TX_ON 0x0080
+#define AUI_ONLY 0x0100
+#define AUTO_AUI_10BASET 0x0200
+#define MODIFIED_BACKOFF 0x0800
+#define NO_AUTO_POLARITY 0x1000
+#define TWO_PART_DEFDIS 0x2000
+#define LOW_RX_SQUELCH 0x4000
+
+/* PP_SelfCTL - Software Self Control bit definition - Read/write */
+#define POWER_ON_RESET 0x0040
+#define SW_STOP 0x0100
+#define SLEEP_ON 0x0200
+#define AUTO_WAKEUP 0x0400
+#define HCB0_ENBL 0x1000
+#define HCB1_ENBL 0x2000
+#define HCB0 0x4000
+#define HCB1 0x8000
+
+/* PP_BusCTL - ISA Bus Control bit definition - Read/write */
+#define RESET_RX_DMA 0x0040
+#define MEMORY_ON 0x0400
+#define DMA_BURST_MODE 0x0800
+#define IO_CHANNEL_READY_ON 0x1000
+#define RX_DMA_SIZE_64K 0x2000
+#define ENABLE_IRQ 0x8000
+
+/* PP_TestCTL - Test Control bit definition - Read/write */
+#define LINK_OFF 0x0080
+#define ENDEC_LOOPBACK 0x0200
+#define AUI_LOOPBACK 0x0400
+#define BACKOFF_OFF 0x0800
+#define FAST_TEST 0x8000
+
+/* PP_RxEvent - Receive Event Bit definition - Read-only */
+#define RX_IA_HASHED 0x0040
+#define RX_DRIBBLE 0x0080
+#define RX_OK 0x0100
+#define RX_HASHED 0x0200
+#define RX_IA 0x0400
+#define RX_BROADCAST 0x0800
+#define RX_CRC_ERROR 0x1000
+#define RX_RUNT 0x2000
+#define RX_EXTRA_DATA 0x4000
+
+#define HASH_INDEX_MASK 0x0FC00
+
+/* PP_TxEvent - Transmit Event Bit definition - Read-only */
+#define TX_LOST_CRS 0x0040
+#define TX_SQE_ERROR 0x0080
+#define TX_OK 0x0100
+#define TX_LATE_COL 0x0200
+#define TX_JBR 0x0400
+#define TX_16_COL 0x8000
+#define TX_SEND_OK_BITS (TX_OK|TX_LOST_CRS)
+#define TX_COL_COUNT_MASK 0x7800
+
+/* PP_BufEvent - Buffer Event Bit definition - Read-only */
+#define SW_INTERRUPT 0x0040
+#define RX_DMA 0x0080
+#define READY_FOR_TX 0x0100
+#define TX_UNDERRUN 0x0200
+#define RX_MISS 0x0400
+#define RX_128_BYTE 0x0800
+#define TX_COL_OVRFLW 0x1000
+#define RX_MISS_OVRFLW 0x2000
+#define RX_DEST_MATCH 0x8000
+
+/* PP_LineST - Ethernet Line Status bit definition - Read-only */
+#define LINK_OK 0x0080
+#define AUI_ON 0x0100
+#define TENBASET_ON 0x0200
+#define POLARITY_OK 0x1000
+#define CRS_OK 0x4000
+
+/* PP_SelfST - Chip Software Status bit definition */
+#define ACTIVE_33V 0x0040
+#define INIT_DONE 0x0080
+#define SI_BUSY 0x0100
+#define EEPROM_PRESENT 0x0200
+#define EEPROM_OK 0x0400
+#define EL_PRESENT 0x0800
+#define EE_SIZE_64 0x1000
+
+/* PP_BusST - ISA Bus Status bit definition */
+#define TX_BID_ERROR 0x0080
+#define READY_FOR_TX_NOW 0x0100
+
+/* PP_AutoNegCTL - Auto Negotiation Control bit definition */
+#define RE_NEG_NOW 0x0040
+#define ALLOW_FDX 0x0080
+#define AUTO_NEG_ENABLE 0x0100
+#define NLP_ENABLE 0x0200
+#define FORCE_FDX 0x8000
+#define AUTO_NEG_BITS (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE)
+#define AUTO_NEG_MASK (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE|ALLOW_FDX|RE_NEG_NOW)
+
+/* PP_AutoNegST - Auto Negotiation Status bit definition */
+#define AUTO_NEG_BUSY 0x0080
+#define FLP_LINK 0x0100
+#define FLP_LINK_GOOD 0x0800
+#define LINK_FAULT 0x1000
+#define HDX_ACTIVE 0x4000
+#define FDX_ACTIVE 0x8000
+
+/*  The following block defines the ISQ event types */
+#define ISQ_RECEIVER_EVENT 0x04
+#define ISQ_TRANSMITTER_EVENT 0x08
+#define ISQ_BUFFER_EVENT 0x0c
+#define ISQ_RX_MISS_EVENT 0x10
+#define ISQ_TX_COL_EVENT 0x12
+
+#define ISQ_EVENT_MASK 0x003F   /*  ISQ mask to find out type of event */
+#define ISQ_HIST 16		/*  small history buffer */
+#define AUTOINCREMENT 0x8000	/*  Bit mask to set bit-15 for autoincrement */
+
+#define TXRXBUFSIZE 0x0600
+#define RXDMABUFSIZE 0x8000
+#define RXDMASIZE 0x4000
+#define TXRX_LENGTH_MASK 0x07FF
+
+/*  rx options bits */
+#define RCV_WITH_RXON	1       /*  Set SerRx ON */
+#define RCV_COUNTS	2       /*  Use Framecnt1 */
+#define RCV_PONG	4       /*  Pong respondent */
+#define RCV_DONG	8       /*  Dong operation */
+#define RCV_POLLING	0x10	/*  Poll RxEvent */
+#define RCV_ISQ		0x20	/*  Use ISQ, int */
+#define RCV_AUTO_DMA	0x100	/*  Set AutoRxDMAE */
+#define RCV_DMA		0x200	/*  Set RxDMA only */
+#define RCV_DMA_ALL	0x400	/*  Copy all DMA'ed */
+#define RCV_FIXED_DATA	0x800	/*  Every frame same */
+#define RCV_IO		0x1000	/*  Use ISA IO only */
+#define RCV_MEMORY	0x2000	/*  Use ISA Memory */
+
+#define RAM_SIZE	0x1000       /*  The card has 4k bytes or RAM */
+#define PKT_START PP_TxFrame  /*  Start of packet RAM */
+
+#define RX_FRAME_PORT	0x0000
+#define TX_FRAME_PORT RX_FRAME_PORT
+#define TX_CMD_PORT	0x0004
+#define TX_NOW		0x0000       /*  Tx packet after   5 bytes copied */
+#define TX_AFTER_381	0x0020       /*  Tx packet after 381 bytes copied */
+#define TX_AFTER_ALL	0x0060       /*  Tx packet after all bytes copied */
+#define TX_LEN_PORT	0x0006
+#define ISQ_PORT	0x0008
+#define ADD_PORT	0x000A
+#define DATA_PORT	0x000C
+
+#define EEPROM_WRITE_EN		0x00F0
+#define EEPROM_WRITE_DIS	0x0000
+#define EEPROM_WRITE_CMD	0x0100
+#define EEPROM_READ_CMD		0x0200
+
+/*  Receive Header */
+/*  Description of header of each packet in receive area of memory */
+#define RBUF_EVENT_LOW	0   /*  Low byte of RxEvent - status of received frame */
+#define RBUF_EVENT_HIGH	1   /*  High byte of RxEvent - status of received frame */
+#define RBUF_LEN_LOW	2   /*  Length of received data - low byte */
+#define RBUF_LEN_HI	3   /*  Length of received data - high byte */
+#define RBUF_HEAD_LEN	4   /*  Length of this header */
+
+#define CHIP_READ 0x1   /*  Used to mark state of the repins code (chip or dma) */
+#define DMA_READ 0x2   /*  Used to mark state of the repins code (chip or dma) */
+
+/*  for bios scan */
+/*  */
+#ifdef CSDEBUG
+/*  use these values for debugging bios scan */
+#define BIOS_START_SEG 0x00000
+#define BIOS_OFFSET_INC 0x0010
+#else
+#define BIOS_START_SEG 0x0c000
+#define BIOS_OFFSET_INC 0x0200
+#endif
+
+#define BIOS_LAST_OFFSET 0x0fc00
+
+/*  Byte offsets into the EEPROM configuration buffer */
+#define ISA_CNF_OFFSET 0x6
+#define TX_CTL_OFFSET (ISA_CNF_OFFSET + 8)			/*  8900 eeprom */
+#define AUTO_NEG_CNF_OFFSET (ISA_CNF_OFFSET + 8)		/*  8920 eeprom */
+
+  /*  the assumption here is that the bits in the eeprom are generally  */
+  /*  in the same position as those in the autonegctl register. */
+  /*  Of course the IMM bit is not in that register so it must be  */
+  /*  masked out */
+#define EE_FORCE_FDX  0x8000
+#define EE_NLP_ENABLE 0x0200
+#define EE_AUTO_NEG_ENABLE 0x0100
+#define EE_ALLOW_FDX 0x0080
+#define EE_AUTO_NEG_CNF_MASK (EE_FORCE_FDX|EE_NLP_ENABLE|EE_AUTO_NEG_ENABLE|EE_ALLOW_FDX)
+
+#define IMM_BIT 0x0040		/*  ignore missing media	 */
+
+#define ADAPTER_CNF_OFFSET (AUTO_NEG_CNF_OFFSET + 2)
+#define A_CNF_10B_T 0x0001
+#define A_CNF_AUI 0x0002
+#define A_CNF_10B_2 0x0004
+#define A_CNF_MEDIA_TYPE 0x0060
+#define A_CNF_MEDIA_AUTO 0x0000
+#define A_CNF_MEDIA_10B_T 0x0020
+#define A_CNF_MEDIA_AUI 0x0040
+#define A_CNF_MEDIA_10B_2 0x0060
+#define A_CNF_DC_DC_POLARITY 0x0080
+#define A_CNF_NO_AUTO_POLARITY 0x2000
+#define A_CNF_LOW_RX_SQUELCH 0x4000
+#define A_CNF_EXTND_10B_2 0x8000
+
+#define PACKET_PAGE_OFFSET 0x8
+
+/*  Bit definitions for the ISA configuration word from the EEPROM */
+#define INT_NO_MASK 0x000F
+#define DMA_NO_MASK 0x0070
+#define ISA_DMA_SIZE 0x0200
+#define ISA_AUTO_RxDMA 0x0400
+#define ISA_RxDMA 0x0800
+#define DMA_BURST 0x1000
+#define STREAM_TRANSFER 0x2000
+#define ANY_ISA_DMA (ISA_AUTO_RxDMA | ISA_RxDMA)
+
+/*  DMA controller registers */
+#define DMA_BASE 0x00     /*  DMA controller base */
+#define DMA_BASE_2 0x0C0    /*  DMA controller base */
+
+#define DMA_STAT 0x0D0    /*  DMA controller status register */
+#define DMA_MASK 0x0D4    /*  DMA controller mask register */
+#define DMA_MODE 0x0D6    /*  DMA controller mode register */
+#define DMA_RESETFF 0x0D8    /*  DMA controller first/last flip flop */
+
+/*  DMA data */
+#define DMA_DISABLE 0x04     /*  Disable channel n */
+#define DMA_ENABLE 0x00     /*  Enable channel n */
+/*  Demand transfers, incr. address, auto init, writes, ch. n */
+#define DMA_RX_MODE 0x14
+/*  Demand transfers, incr. address, auto init, reads, ch. n */
+#define DMA_TX_MODE 0x18
+
+#define DMA_SIZE (16*1024) /*  Size of dma buffer - 16k */
+
+#define CS8900 0x0000
+#define CS8920 0x4000   
+#define CS8920M 0x6000   
+#define REVISON_BITS 0x1F00
+#define EEVER_NUMBER 0x12
+#define CHKSUM_LEN 0x14
+#define CHKSUM_VAL 0x0000
+#define START_EEPROM_DATA 0x001c /*  Offset into eeprom for start of data */
+#define IRQ_MAP_EEPROM_DATA 0x0046 /*  Offset into eeprom for the IRQ map */
+#define IRQ_MAP_LEN 0x0004 /*  No of bytes to read for the IRQ map */
+#define PNP_IRQ_FRMT 0x0022 /*  PNP small item IRQ format */
+#define CS8900_IRQ_MAP 0x1c20 /*  This IRQ map is fixed */
+
+#define CS8920_NO_INTS 0x0F   /*  Max CS8920 interrupt select # */
+
+#define PNP_ADD_PORT 0x0279
+#define PNP_WRITE_PORT 0x0A79
+
+#define GET_PNP_ISA_STRUCT 0x40
+#define PNP_ISA_STRUCT_LEN 0x06
+#define PNP_CSN_CNT_OFF 0x01
+#define PNP_RD_PORT_OFF 0x02
+#define PNP_FUNCTION_OK 0x00
+#define PNP_WAKE 0x03
+#define PNP_RSRC_DATA 0x04
+#define PNP_RSRC_READY 0x01
+#define PNP_STATUS 0x05
+#define PNP_ACTIVATE 0x30
+#define PNP_CNF_IO_H 0x60
+#define PNP_CNF_IO_L 0x61
+#define PNP_CNF_INT 0x70
+#define PNP_CNF_DMA 0x74
+#define PNP_CNF_MEM 0x48
+
+#define BIT0 1
+#define BIT15 0x8000
+
diff -u --recursive --new-file v2.1.24/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.1.24/linux/drivers/net/de4x5.c	Thu Jan  2 15:55:18 1997
+++ linux/drivers/net/de4x5.c	Sun Feb  2 15:18:37 1997
@@ -1,12 +1,13 @@
-/*  de4x5.c: A DIGITAL DE425/DE434/DE435/DE450/DE500 ethernet driver for Linux.
+/*  de4x5.c: A DIGITAL DC21x4x DECchip and DE425/DE434/DE435/DE450/DE500
+             ethernet driver for Linux.
 
     Copyright 1994, 1995 Digital Equipment Corporation.
 
     This software may be used and distributed according to the terms of
     the GNU Public License, incorporated herein by reference.
 
-    This driver is written for the Digital Equipment Corporation series
-    of EtherWORKS ethernet cards:
+    Originally,   this  driver  was    written  for the  Digital   Equipment
+    Corporation series of EtherWORKS ethernet cards:
 
         DE425 TP/COAX EISA
 	DE434 TP PCI
@@ -14,6 +15,24 @@
 	DE450 TP/COAX/AUI PCI
 	DE500 10/100 PCI Fasternet
 
+    but it  will now  attempt  to support all  cards   which conform  to the
+    Digital  Semiconductor SROM    Specification.   The   driver   currently
+    recognises the following chips:
+
+        DC21040     (no SROM)
+	DC21041[A]
+	DC21140[A]
+
+    I plan to  add DC2114[23]  support ASAP,  time permitting.   So far  the
+    driver is known to work with the following cards:
+
+        KINGSTON
+	Linksys
+	ZNYX342
+	SMC8432
+	SMC9332 (w/new SROM)
+	ZNYX31[45]
+
     The driver has been tested on a relatively busy network using the DE425,
     DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
     16M of data to a DECstation 5000/200 as follows:
@@ -32,9 +51,11 @@
     The author may be reached at davies@maniac.ultranet.com.
 
     =========================================================================
-    This driver has been written  substantially  from scratch, although  its
+    This driver  has been written substantially  from scratch,  although its
     inheritance of style and stack interface from 'ewrk3.c' and in turn from
-    Donald Becker's 'lance.c' should be obvious.
+    Donald Becker's 'lance.c' should be obvious. With the module autoload of
+    every  usable DECchip board,  I pinched Donald's  'next_module' field to
+    link my modules together.
 
     Upto 15 EISA cards can be supported under this driver, limited primarily
     by the available IRQ lines.  I have  checked different configurations of
@@ -46,49 +67,42 @@
     to the differences in the EISA and PCI CSR address offsets from the base
     address.
 
-    The ability to load this driver  as a loadable  module has been included
-    and used extensively during the  driver development (to save those  long
-    reboot sequences).  Loadable module support under  PCI and EISA has been
+    The ability to load this  driver as a loadable  module has been included
+    and used extensively  during the driver development  (to save those long
+    reboot sequences).  Loadable module support  under PCI and EISA has been
     achieved by letting the driver autoprobe as if it were compiled into the
-    kernel, except that there is no autoprobing of the IRQ lines. This is of
-    no great consequence except do  make sure you're not sharing  interrupts
-    with anything that cannot   accommodate interrupt sharing!  By  default,
-    the driver will autoprobe for the next available card.
-
-    Essentially, the I/O address and IRQ information  are ignored and filled
-    in later by  the PCI BIOS   during the PCI  probe.  Note  that the board
-    should be in the system at boot time so that its I/O address and IRQ are
-    allocated by the PCI BIOS automatically.
+    kernel. Do make sure  you're not sharing  interrupts with anything  that
+    cannot accommodate  interrupt  sharing!
 
     To utilise this ability, you have to do 8 things:
 
     0) have a copy of the loadable modules code installed on your system.
     1) copy de4x5.c from the  /linux/drivers/net directory to your favourite
     temporary directory.
-    2) edit the source code near line 4146 to reflect the I/O address you're
-    using (only  if you want to manually  load the module),  or assign these
-    when loading by:
+    2) for fixed  autoprobes (not  recommended),  edit the source code  near
+    line 4927 to reflect the I/O address  you're using, or assign these when
+    loading by:
 
-                   insmod de4x5.o io=0xghh         where g = bus number
-		                                        hh = device number
+                   insmod de4x5 io=0xghh           where g = bus number
+		                                        hh = device number   
 
        NB: autoprobing for modules is now supported by default. You may just
            use:
 
-                   insmod de4x5.o
+                   insmod de4x5
 
-           to load the next available board. For a specific board, still use
+           to load all available boards. For a specific board, still use
 	   the 'io=?' above.
     3) compile  de4x5.c, but include -DMODULE in  the command line to ensure
     that the correct bits are compiled (see end of source code).
     4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
     kernel with the de4x5 configuration turned off and reboot.
-    5) insmod de4x5.o [io=0xghh]
-    6) run the net startup bits for your new eth?? interface(s) manually
-    (usually /etc/rc.inet[12] at boot time).
+    5) insmod de4x5 [io=0xghh]
+    6) run the net startup bits for your new eth?? interface(s) manually 
+    (usually /etc/rc.inet[12] at boot time). 
     7) enjoy!
 
-    To unload a module, turn off the associated interface(s)
+    To unload a module, turn off the associated interface(s) 
     'ifconfig eth?? down' then 'rmmod de4x5'.
 
     Automedia detection is included so that in  principal you can disconnect
@@ -99,13 +113,7 @@
     By  default,  the driver will  now   autodetect any  DECchip based card.
     Should you have a need to restrict the driver to DIGITAL only cards, you
     can compile with a  DEC_ONLY define, or if  loading as a module, use the
-    'dec_only=1'  parameter. However, this  "feature" is in no way supported
-    nor  tested in this  driver  and the user  may use  it  at his/her  sole
-    discretion.   I have had  2 conflicting reports that  my  driver will or
-    won't work  with Znyx.   Try  Donald Becker's 'tulip.c' if   this driver
-    doesn't work for you. I will not be supporting Znyx  and SMC cards since
-    I have  no information on  them and  can't test  them in  a system (this
-    applies most particularly to the DC21140 based cards).
+    'dec_only=1'  parameter.
 
     I've changed the timing routines to  use the kernel timer and scheduling
     functions  so that the  hangs  and other assorted problems that occurred
@@ -126,6 +134,17 @@
     aligned  DMA transfers  and  the  Alphas get   alignment traps with  non
     longword aligned data copies (which makes them really slow). No comment.
 
+    I  have added SROM decoding  routines to make this  driver work with any
+    card that  supports the Digital  Semiconductor SROM spec. This will help
+    all  cards running the dc2114x  series chips in particular.  Cards using
+    the dc2104x  chips should run correctly with  the basic  driver.  I'm in
+    debt to <mjacob@feral.com> for the  testing and feedback that helped get
+    this feature working.  So far we have  tested KINGSTON, SMC8432, SMC9332
+    (with the latest SROM complying  with the SROM spec  V3: their first was
+    broken), ZNYX342  and  LinkSys. ZYNX314 (dual  21041  MAC) and  ZNYX 315
+    (quad 21041 MAC)  cards also  appear  to work despite their  incorrectly
+    wired IRQs.
+
     TO DO:
     ------
 
@@ -134,7 +153,7 @@
     ----------------
 
     Version   Date        Description
-
+  
       0.1     17-Nov-94   Initial writing. ALPHA code release.
       0.2     13-Jan-95   Added PCI support for DE435's.
       0.21    19-Jan-95   Added auto media detection.
@@ -143,7 +162,7 @@
 			  Add request/release_region code.
 			  Add loadable modules support for PCI.
 			  Clean up loadable modules support.
-      0.23    28-Feb-95   Added DC21041 and DC21140 support.
+      0.23    28-Feb-95   Added DC21041 and DC21140 support. 
                           Fix missed frame counter value and initialisation.
 			  Fixed EISA probe.
       0.24    11-Apr-95   Change delay routine to use <linux/udelay>.
@@ -172,7 +191,7 @@
                           Add kernel timer code (h/w is too flaky).
 			  Add MII based PHY autosense.
 			  Add new multicasting code.
-			  Add new autosense algorithms for media/mode
+			  Add new autosense algorithms for media/mode 
 			  selection using kernel scheduling/timing.
 			  Re-formatted.
 			  Made changes suggested by <jeff@router.patch.net>:
@@ -199,30 +218,40 @@
                           Add Accton to the list of broken cards.
 			  Fix TX under-run bug for non DC21140 chips.
 			  Fix boot command probe bug in alloc_device() as
-			   reported by <koen.gadeyne@barco.com> and
+			   reported by <koen.gadeyne@barco.com> and 
 			   <orava@nether.tky.hut.fi>.
 			  Add cache locks to prevent a race condition as
-			   reported by <csd@microplex.com> and
+			   reported by <csd@microplex.com> and 
 			   <baba@beckman.uiuc.edu>.
 			  Upgraded alloc_device() code.
       0.431  28-Jun-96    Fix potential bug in queue_pkt() from discussion
                           with <csd@microplex.com>
       0.44   13-Aug-96    Fix RX overflow bug in 2114[023] chips.
                           Fix EISA probe bugs reported by <os2@kpi.kharkov.ua>
-			  and <michael@compurex.com>
+			  and <michael@compurex.com>.
       0.441   9-Sep-96    Change dc21041_autoconf() to probe quiet BNC media
                            with a loopback packet.
       0.442   9-Sep-96    Include AUI in dc21041 media printout. Bug reported
                            by <bhat@mundook.cs.mu.OZ.AU>
-      0.45    8-Dec-96    Include endian functions for PPC use, from work
+      0.45    8-Dec-96    Include endian functions for PPC use, from work 
                            by <cort@cs.nmt.edu>.
       0.451  28-Dec-96    Added fix to allow autoprobe for modules after
-                           suggestion from <mjacob@feral.com>
+                           suggestion from <mjacob@feral.com>.
+      0.5    30-Jan-97    Added SROM decoding functions.
+                          Updated debug flags.
+			  Fix sleep/wakeup calls for PCI cards, bug reported
+			   by <cross@gweep.lkg.dec.com>.
+			  Added multi-MAC, one SROM feature from discussion
+			   with <mjacob@feral.com>.
+			  Added full module autoprobe capability.
+			  Added attempt to use an SMC9332 with broken SROM.
+			  Added fix for ZYNX multi-mac cards that didn't
+			   get their IRQs wired correctly.
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:v0.451 96/12/28 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n";
 
 #include <linux/module.h>
 
@@ -280,6 +309,12 @@
 	int value;
     } spd;
     int addr;               /* MII address for the PHY */
+    u_char  *gep;           /* Start of GEP sequence block in SROM */
+    u_char  *rst;           /* Start of reset sequence in SROM */
+    u_int mc;               /* Media Capabilities */
+    u_int ana;              /* NWay Advertisement */
+    u_int fdx;              /* Full DupleX capabilites for each media */
+    u_int ttm;              /* Transmit Threshold Mode for each media */
 };
 
 #define DE4X5_MAX_PHY 8     /* Allow upto 8 attached PHY devices per board */
@@ -306,11 +341,23 @@
 #define SMC    1
 #define ACCTON 2
 
+/*
+** SROM Repair definitions. If a broken SROM is detected a card may
+** use this information to help figure out what to do. This is a
+** "stab in the dark" and so far for SMC9332's only.
+*/
+static c_char srom_repair_info[][100] = {
+    {0x00,0x1e,0x00,0x00,0x00,0x08,             /* SMC9332 */
+     0x1f,0x01,0x8f,0x01,0x00,0x01,0x00,0x02,
+     0x01,0x00,0x00,0x78,0xe0,0x01,0x00,0x50,
+     0x00,0x18,}
+};
+
 
 #ifdef DE4X5_DEBUG
 static int de4x5_debug = DE4X5_DEBUG;
 #else
-static int de4x5_debug = 1;
+static int de4x5_debug = (0);
 #endif
 
 #ifdef DE4X5_AUTOSENSE              /* Should be done on a per adapter basis */
@@ -374,7 +421,7 @@
 ** Memory Alignment. Each descriptor is 4 longwords long. To force a
 ** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
 ** DESC_ALIGN. ALIGN aligns the start address of the private memory area
-** and hence the RX descriptor ring's first entry.
+** and hence the RX descriptor ring's first entry. 
 */
 #define ALIGN4      ((u_long)4 - 1)     /* 1 longword align */
 #define ALIGN8      ((u_long)8 - 1)     /* 2 longword align */
@@ -455,7 +502,7 @@
     char id_block_crc;
     char reserved2;
     char version;
-    char num_adapters;
+    char num_controllers;
     char ieee_addr[6];
     char info[100];
     short chksum;
@@ -500,7 +547,7 @@
     int tx_new, tx_old;                     /* TX descriptor ring pointers  */
     char setup_frame[SETUP_FRAME_LEN];      /* Holds MCA and PA info.       */
     char frame[64];                         /* Min sized packet for loopback*/
-    struct enet_statistics stats;           /* Public stats                 */
+    struct net_device_stats stats;           /* Public stats                 */
     struct {
 	u_int bins[DE4X5_PKT_STAT_SZ];      /* Private stats counters       */
 	u_int unicast;
@@ -518,16 +565,17 @@
     char txRingSize;
     int  bus;                               /* EISA or PCI                  */
     int  bus_num;                           /* PCI Bus number               */
+    int  device;                            /* Device number on PCI bus     */
     int  state;                             /* Adapter OPENED or CLOSED     */
     int  chipset;                           /* DC21040, DC21041 or DC21140  */
     s32  irq_mask;                          /* Interrupt Mask (Enable) bits */
     s32  irq_en;                            /* Summary interrupt bits       */
     int  media;                             /* Media (eg TP), mode (eg 100B)*/
     int  c_media;                           /* Remember the last media conn */
+    int  fdx;                               /* media full duplex flag       */
     int  linkOK;                            /* Link is OK                   */
     int  autosense;                         /* Allow/disallow autosensing   */
     int  tx_enable;                         /* Enable descriptor polling    */
-    int  lostMedia;                         /* Possibly lost media          */
     int  setup_f;                           /* Setup frame filtering type   */
     int  local_state;                       /* State within a 'media' state */
     struct mii_phy phy[DE4X5_MAX_PHY];      /* List of attached PHY devices */
@@ -543,13 +591,31 @@
 	s32 csr0;                           /* Saved Bus Mode Register      */
 	s32 csr6;                           /* Saved Operating Mode Reg.    */
 	s32 csr7;                           /* Saved IRQ Mask Register      */
+	s32 gep;                            /* Saved General Purpose Reg.   */
+	s32 gepc;                           /* Control info for GEP         */
 	s32 csr13;                          /* Saved SIA Connectivity Reg.  */
 	s32 csr14;                          /* Saved SIA TX/RX Register     */
 	s32 csr15;                          /* Saved SIA General Register   */
 	int save_cnt;                       /* Flag if state already saved  */
 	struct sk_buff *skb;                /* Save the (re-ordered) skb's  */
     } cache;
+    struct de4x5_srom srom;                 /* A copy of the SROM           */
+    struct device *next_module;             /* Link to the next module      */
     int rx_ovf;                             /* Check for 'RX overflow' tag  */
+    int useSROM;                            /* For non-DEC card use SROM    */
+    int useMII;                             /* Infoblock using the MII      */
+    int asBitValid;                         /* Autosense bits in GEP?       */
+    int asPolarity;                         /* 0 => asserted high           */
+    int asBit;                              /* Autosense bit number in GEP  */
+    int defMedium;                          /* SROM default medium          */
+    int tcount;                             /* Last infoblock number        */
+    int infoblock_init;                     /* Initialised this infoblock?  */
+    int infoleaf_offset;                    /* SROM infoleaf for controller */
+    s32 infoblock_csr6;                     /* csr6 value in SROM infoblock */
+    int infoblock_media;                    /* infoblock media              */
+    int (*infoleaf_fn)(struct device *);    /* Pointer to infoleaf function */
+    u_char *rst;                            /* Pointer to Type 5 reset info */
+    u_char  ibn;                            /* Infoblock number             */
 };
 
 /*
@@ -564,9 +630,29 @@
     int chipset;
     struct de4x5_srom srom;
     int autosense;
+    int useSROM;
 } bus;
 
 /*
+** To get around certain poxy cards that don't provide an SROM
+** for the second and more DECchip, I have to key off the first
+** chip's address. I'll assume there's not a bad SROM iff:
+**
+**      o the chipset is the same
+**      o the bus number is the same and > 0
+**      o the sum of all the returned hw address bytes is 0 or 0x5fa
+**
+** Also have to save the irq for those cards whose hardware designers
+** can't follow the PCI to PCI Bridge Architecture spec.
+*/
+struct {
+    int chipset;
+    int bus;
+    int irq;
+    u_char addr[ETH_ALEN];
+} last = {0,};
+
+/*
 ** The transmit ring full condition is described by the tx_old and tx_new
 ** pointers by:
 **    tx_old            = tx_new    Empty ring
@@ -586,7 +672,7 @@
 static int     de4x5_queue_pkt(struct sk_buff *skb, struct device *dev);
 static void    de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int     de4x5_close(struct device *dev);
-static struct  enet_statistics *de4x5_get_stats(struct device *dev);
+static struct  net_device_stats *de4x5_get_stats(struct device *dev);
 static void    de4x5_local_stats(struct device *dev, char *buf, int pkt_len);
 static void    set_multicast_list(struct device *dev);
 static int     de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd);
@@ -611,6 +697,7 @@
 static int     dc21040_autoconf(struct device *dev);
 static int     dc21041_autoconf(struct device *dev);
 static int     dc21140m_autoconf(struct device *dev);
+static int     srom_autoconf(struct device *dev);
 static int     de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn)(struct device *, int), int (*asfn)(struct device *));
 static int     dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct device *, int));
 static int     test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
@@ -648,6 +735,10 @@
 /*static void    srom_busy(u_int command, u_long address);*/
 static void    sendto_srom(u_int command, u_long addr);
 static int     getfrom_srom(u_long addr);
+static void    srom_map_media(struct device *dev);
+static int     srom_infoleaf_info(struct device *dev);
+static void    srom_init(struct device *dev);
+static void    srom_exec(struct device *dev, u_char *p);
 static int     mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr);
 static void    mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr);
 static int     mii_rdata(u_long ioaddr);
@@ -661,6 +752,8 @@
 static int     mii_get_phy(struct device *dev);
 static void    SetMulticastFilter(struct device *dev);
 static int     get_hw_addr(struct device *dev);
+static void    srom_repair(struct device *dev, int card);
+static int     test_bad_enet(struct device *dev, int status);
 
 static void    eisa_probe(struct device *dev, u_long iobase);
 static void    pci_probe(struct device *dev, u_long iobase);
@@ -670,16 +763,29 @@
 static char    *build_setup_frame(struct device *dev, int mode);
 static void    disable_ast(struct device *dev);
 static void    enable_ast(struct device *dev, u32 time_out);
-static long    de4x5_switch_to_srl(struct device *dev);
-static long    de4x5_switch_to_mii(struct device *dev);
+static long    de4x5_switch_mac_port(struct device *dev);
 static void    timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec);
+static void    yawn(struct device *dev, int state);
 static int     de4x5_dev_index(char *s);
+static void    link_modules(struct device *dev, struct device *tmp);
+static struct  device *unlink_modules(struct device *p);
 static void    de4x5_dbg_open(struct device *dev);
 static void    de4x5_dbg_mii(struct device *dev, int k);
 static void    de4x5_dbg_media(struct device *dev);
 static void    de4x5_dbg_srom(struct de4x5_srom *p);
 static void    de4x5_dbg_rx(struct sk_buff *skb, int len);
 static int     de4x5_strncmp(char *a, char *b, int n);
+static int     dc21041_infoleaf(struct device *dev);
+static int     dc21140_infoleaf(struct device *dev);
+static int     dc21142_infoleaf(struct device *dev);
+static int     dc21143_infoleaf(struct device *dev);
+static int     type0_infoblock(struct device *dev, u_char count, u_char *p);
+static int     type1_infoblock(struct device *dev, u_char count, u_char *p);
+static int     type2_infoblock(struct device *dev, u_char count, u_char *p);
+static int     type3_infoblock(struct device *dev, u_char count, u_char *p);
+static int     type4_infoblock(struct device *dev, u_char count, u_char *p);
+static int     type5_infoblock(struct device *dev, u_char count, u_char *p);
+static int     compact_infoblock(struct device *dev, u_char count, u_char *p);
 
 #ifdef MODULE
 int  init_module(void);
@@ -692,7 +798,37 @@
 static char name[DE4X5_NAME_LENGTH + 1];
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
 static int num_de4x5s = 0, num_eth = 0;
-static int cfrv = 0;
+static int cfrv = 0, useSROM = 0;
+
+/*
+** List the SROM infoleaf functions and chipsets
+*/
+struct InfoLeaf {
+    int chipset;
+    int (*fn)(struct device *);
+};
+struct InfoLeaf infoleaf_array[] = {
+    {DC21041, dc21041_infoleaf},
+    {DC21140, dc21140_infoleaf},
+    {DC21142, dc21142_infoleaf},
+    {DC21143, dc21143_infoleaf}
+};
+#define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *)))
+
+/*
+** List the SROM info block functions
+*/
+static int (*dc_infoblock[])(struct device *dev, u_char, u_char *) = {
+    type0_infoblock,
+    type1_infoblock,
+    type2_infoblock,
+    type3_infoblock,
+    type4_infoblock,
+    type5_infoblock,
+    compact_infoblock
+};
+
+#define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1)
 
 /*
 ** Miscellaneous defines...
@@ -709,6 +845,13 @@
     de4x5_ms_delay(1);\
 }
 
+#define PHY_HARD_RESET {\
+    outl(GEP_HRST, DE4X5_GEP);           /* Hard RESET the PHY dev. */\
+    udelay(1000);                        /* Assert for 1ms */\
+    outl(0x00, DE4X5_GEP);\
+    udelay(2000);                        /* Wait for 2ms */\
+}
+
 
 /*
 ** Autoprobing in modules is allowed here. See the top of the file for
@@ -718,23 +861,18 @@
 int
 de4x5_probe(struct device *dev)
 {
-    int tmp = num_de4x5s, status = -ENODEV;
+    int status = -ENODEV;
     u_long iobase = dev->base_addr;
 
     eisa_probe(dev, iobase);
     pci_probe(dev, iobase);
-
-    if ((tmp == num_de4x5s) && (iobase != 0) && loading_module) {
-	printk("%s: de4x5_probe() cannot find device at 0x%04lx.\n", dev->name,
-	       iobase);
-    }
-
+    
     /*
     ** Walk the device list to check that at least one device
     ** initialised OK
     */
     for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
-
+    
     if (dev->priv) status = 0;
     if (iobase == 0) autoprobed = 1;
 
@@ -745,70 +883,70 @@
 de4x5_hw_init(struct device *dev, u_long iobase)
 {
     struct bus_type *lp = &bus;
-    int tmpbus, tmpchs, status=0;
-    int i, media = *((char *)&(lp->srom) + *((char *)&(lp->srom) + 19) * 3);
+    int i, status=0;
     char *tmp;
-
+    
     /* Ensure we're not sleeping */
-    if (lp->chipset == DC21041) {
-	outl(0, PCI_CFDA);
-	de4x5_ms_delay(10);
+    if (lp->bus == EISA) {
+	outb(WAKEUP, PCI_CFPM);
+    } else {
+	pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+				  PCI_CFDA_PSM, WAKEUP);
     }
-
+    de4x5_ms_delay(10);
+    
     RESET_DE4X5;
-
+    
     if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
 	return -ENXIO;                       /* Hardware could not reset */
     }
-
-    /*
+    
+    /* 
     ** Now find out what kind of DC21040/DC21041/DC21140 board we have.
     */
+    useSROM = FALSE;
     if (lp->bus == PCI) {
 	PCI_signature(name, lp);
     } else {
 	EISA_signature(name, EISA_ID0);
     }
-
+    
     if (*name == '\0') {                     /* Not found a board signature */
 	return -ENXIO;
     }
-
+    
     dev->base_addr = iobase;
     if (lp->bus == EISA) {
-	printk("%s: %s at 0x%04lx (EISA slot %ld)",
+	printk("%s: %s at 0x%04lx (EISA slot %ld)", 
 	       dev->name, name, iobase, ((iobase>>12)&0x0f));
     } else {                                 /* PCI port address */
 	printk("%s: %s at 0x%04lx (PCI bus %d, device %d)", dev->name, name,
 	       iobase, lp->bus_num, lp->device);
     }
-
+    
     printk(", h/w address ");
     status = get_hw_addr(dev);
     for (i = 0; i < ETH_ALEN - 1; i++) {     /* get the ethernet addr. */
 	printk("%2.2x:", dev->dev_addr[i]);
     }
     printk("%2.2x,\n", dev->dev_addr[i]);
-
-    tmpbus = lp->bus;
-    tmpchs = lp->chipset;
-
+    
     if (status != 0) {
 	printk("      which has an Ethernet PROM CRC error.\n");
 	return -ENXIO;
     } else {
 	struct de4x5_private *lp;
-
-	/*
+	
+	/* 
 	** Reserve a section of kernel memory for the adapter
 	** private area and the TX/RX descriptor rings.
 	*/
-	dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN,
+	dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN, 
 				     GFP_KERNEL);
 	if (dev->priv == NULL) {
 	    return -ENOMEM;
 	}
-
+	
 	/*
 	** Align to a longword boundary
 	*/
@@ -816,26 +954,20 @@
 	dev->priv = (void *)(((u_long)dev->priv + ALIGN) & ~ALIGN);
 	lp = (struct de4x5_private *)dev->priv;
 	memset(dev->priv, 0, sizeof(struct de4x5_private));
-	lp->bus = tmpbus;
-	lp->chipset = tmpchs;
+	lp->bus = bus.bus;
+	lp->bus_num = bus.bus_num;
+	lp->device = bus.device;
+	lp->chipset = bus.chipset;
 	lp->cache.priv = tmp;
-
-	/*
-	** Check for an MII interface
-	*/
-	if (media & MEDIA_MII) {                   /* MII interface? */
-	    if (!mii_get_phy(dev)) {
-		printk("%s: MII search failed, no device found when one was expected\n", dev->name);
-		return -ENXIO;
-	    }
-	} else {
-	    mii_get_phy(dev);                      /* Search the MII anyway! */
-	}
+	lp->cache.gepc = GEP_INIT;
+	lp->timeout = -1;
+	lp->useSROM = useSROM;
+	memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
 
 	/*
 	** Choose correct autosensing in case someone messed up
 	*/
-	if (de4x5_autosense & AUTO) {
+	if ((de4x5_autosense & AUTO) || lp->useSROM) {
 	    lp->autosense = AUTO;
 	} else {
 	    if (lp->chipset != DC21140) {
@@ -850,12 +982,12 @@
 		lp->autosense = de4x5_autosense & 0x00c0;
 	    }
 	}
-
+	lp->fdx = de4x5_full_duplex;
 	sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
-
+	
 	/*
 	** Set up the RX descriptor ring (Intels)
-	** Allocate contiguous receive buffers, long word aligned (Alphas)
+	** Allocate contiguous receive buffers, long word aligned (Alphas) 
 	*/
 #if !defined(__alpha__) && !defined(__powerpc__) && !defined(DE4X5_DO_MEMCPY)
 	for (i=0; i<NUM_RX_DESC; i++) {
@@ -867,7 +999,7 @@
 	}
 
 #else
-	if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN,
+	if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, 
 				   GFP_KERNEL)) == NULL) {
 	    kfree(lp->cache.priv);
 	    return -ENOMEM;
@@ -885,22 +1017,22 @@
 #endif
 
 	barrier();
-
+	    
 	request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
-				DE4X5_EISA_TOTAL_SIZE),
+				DE4X5_EISA_TOTAL_SIZE), 
 		       lp->adapter_name);
-
+	    
 	lp->rxRingSize = NUM_RX_DESC;
 	lp->txRingSize = NUM_TX_DESC;
-
+	    
 	/* Write the end of list marker to the descriptor lists */
 	lp->rx_ring[lp->rxRingSize - 1].des1 |= cpu_to_le32(RD_RER);
 	lp->tx_ring[lp->txRingSize - 1].des1 |= cpu_to_le32(TD_TER);
-
+	    
 	/* Tell the adapter where the TX/RX rings are located. */
 	outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
 	outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
-
+	    
 	/* Initialise the IRQ mask and Enable/Disable */
 	lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM;
 	lp->irq_en   = IMR_NIM | IMR_AIM;
@@ -909,23 +1041,40 @@
 	create_packet(dev, lp->frame, sizeof(lp->frame));
 
 	/* Check if the RX overflow bug needs testing for */
-	tmpchs = cfrv & 0x000000fe;
-	if ((lp->chipset == DC21140) && (tmpchs == 0x20)) {
+	i = cfrv & 0x000000fe;
+	if ((lp->chipset == DC21140) && (i == 0x20)) {
 	    lp->rx_ovf = 1;
 	}
 
-	/* Initialise the adapter state */
+	/* Initialise the SROM pointers if possible */
+	if (lp->useSROM) {
+	    lp->state = INITIALISED;
+	    de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
+	    if (srom_infoleaf_info(dev)) {
+		return -ENXIO;
+	    }
+	    srom_init(dev);
+	}
+
 	lp->state = CLOSED;
 
+	/*
+	** Check for an MII interface
+	*/
+	if ((lp->chipset != DC21040) && (lp->chipset != DC21041)) {
+	    mii_get_phy(dev);
+	}
+	
 	printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
 	       ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
 
+	printk("INFOLEAF_SIZE: %d\nCOMPACT: %d\n", INFOLEAF_SIZE, COMPACT);
     }
-
-    if (de4x5_debug > 1) {
+    
+    if (de4x5_debug & DEBUG_VERSION) {
 	printk(version);
     }
-
+    
     /* The DE4X5-specific entries in the device structure. */
     dev->open = &de4x5_open;
     dev->hard_start_xmit = &de4x5_queue_pkt;
@@ -933,18 +1082,15 @@
     dev->get_stats = &de4x5_get_stats;
     dev->set_multicast_list = &set_multicast_list;
     dev->do_ioctl = &de4x5_ioctl;
-
+    
     dev->mem_start = 0;
-
-    /* Fill in the generic field of the device structure. */
+    
+    /* Fill in the generic fields of the device structure. */
     ether_setup(dev);
-
+    
     /* Let the adapter sleep to save power */
-    if (lp->chipset == DC21041) {
-	outl(0, DE4X5_SICR);
-	outl(CFDA_PSM, PCI_CFDA);
-    }
-
+    yawn(dev, SLEEP);
+    
     return status;
 }
 
@@ -956,7 +1102,7 @@
     u_long iobase = dev->base_addr;
     int i, status = 0;
     s32 omr;
-
+    
     /* Allocate the RX buffers */
     for (i=0; i<lp->rxRingSize; i++) {
 	if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) {
@@ -968,35 +1114,32 @@
     /*
     ** Wake up the adapter
     */
-    if (lp->chipset == DC21041) {
-	outl(0, PCI_CFDA);
-	de4x5_ms_delay(10);
-    }
+    yawn(dev, WAKEUP);
 
-    /*
-    ** Re-initialize the DE4X5...
+    /* 
+    ** Re-initialize the DE4X5... 
     */
     status = de4x5_init(dev);
-
+    
     lp->state = OPEN;
     de4x5_dbg_open(dev);
-
-    if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ,
+    
+    if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, 
 		                                     lp->adapter_name, dev)) {
 	printk("de4x5_open(): Requested IRQ%d is busy\n",dev->irq);
 	status = -EAGAIN;
     } else {
-	dev->tbusy = 0;
+	dev->tbusy = 0;                         
 	dev->start = 1;
 	dev->interrupt = UNMASK_INTERRUPTS;
 	dev->trans_start = jiffies;
-
+	
 	START_DE4X5;
-
+	
 	de4x5_setup_intr(dev);
     }
-
-    if (de4x5_debug > 1) {
+    
+    if (de4x5_debug & DEBUG_OPEN) {
 	printk("\tsts:  0x%08x\n", inl(DE4X5_STS));
 	printk("\tbmr:  0x%08x\n", inl(DE4X5_BMR));
 	printk("\timr:  0x%08x\n", inl(DE4X5_IMR));
@@ -1006,9 +1149,9 @@
 	printk("\tstrr: 0x%08x\n", inl(DE4X5_STRR));
 	printk("\tsigr: 0x%08x\n", inl(DE4X5_SIGR));
     }
-
+    
     MOD_INC_USE_COUNT;
-
+    
     return status;
 }
 
@@ -1022,15 +1165,15 @@
 */
 static int
 de4x5_init(struct device *dev)
-{
+{  
     /* Lock out other processes whilst setting up the hardware */
     set_bit(0, (void *)&dev->tbusy);
-
+    
     de4x5_sw_reset(dev);
-
+    
     /* Autoconfigure the connected port */
     autoconf_media(dev);
-
+    
     return 0;
 }
 
@@ -1041,22 +1184,25 @@
     u_long iobase = dev->base_addr;
     int i, j, status = 0;
     s32 bmr, omr;
-
+    
     /* Select the MII or SRL port now and RESET the MAC */
-    if (lp->phy[lp->active].id == 0) {
-	de4x5_switch_to_srl(dev);
-    } else {
-	de4x5_switch_to_mii(dev);
+    if (!lp->useSROM) {
+	if (lp->phy[lp->active].id != 0) {
+	    lp->infoblock_csr6 = OMR_PS | OMR_HBD;
+	} else {
+	    lp->infoblock_csr6 = OMR_TTM;
+	}
+	de4x5_switch_mac_port(dev);
     }
 
-    /*
+    /* 
     ** Set the programmable burst length to 8 longwords for all the DC21140
     ** Fasternet chips and 4 longwords for all others: DMA errors result
     ** without these values. Cache align 16 long.
     */
     bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN;
     outl(bmr, DE4X5_BMR);
-
+    
     omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn off promiscuous mode */
     if (lp->chipset == DC21140) {
 	omr |= (OMR_SDP | OMR_SB);
@@ -1064,26 +1210,26 @@
     lp->setup_f = PERFECT;
     outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
     outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
-
+    
     lp->rx_new = lp->rx_old = 0;
     lp->tx_new = lp->tx_old = 0;
-
+    
     for (i = 0; i < lp->rxRingSize; i++) {
 	lp->rx_ring[i].status = cpu_to_le32(R_OWN);
     }
-
+    
     for (i = 0; i < lp->txRingSize; i++) {
 	lp->tx_ring[i].status = cpu_to_le32(0);
     }
-
+    
     barrier();
-
+    
     /* Build the setup frame depending on filtering mode */
     SetMulticastFilter(dev);
-
+    
     load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
     outl(omr|OMR_ST, DE4X5_OMR);
-
+    
     /* Poll for setup frame completion (adapter interrupts are disabled now) */
     sti();                                       /* Ensure timer interrupts */
     for (j=0, i=0;(i<500) && (j==0);i++) {       /* Upto 500ms delay */
@@ -1091,20 +1237,20 @@
 	if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1;
     }
     outl(omr, DE4X5_OMR);                        /* Stop everything! */
-
+    
     if (j == 0) {
-	printk("%s: Setup frame timed out, status %08x\n", dev->name,
+	printk("%s: Setup frame timed out, status %08x\n", dev->name, 
 	       inl(DE4X5_STS));
 	status = -EIO;
     }
-
+    
     lp->tx_new = (++lp->tx_new) % lp->txRingSize;
     lp->tx_old = lp->tx_new;
-
+    
     return status;
 }
 
-/*
+/* 
 ** Writes a socket buffer address to the next available transmit descriptor
 */
 static int
@@ -1121,9 +1267,9 @@
 
     set_bit(0, (void*)&dev->tbusy);              /* Stop send re-tries */
     if (lp->tx_enable == NO) {                   /* Cannot send for now */
-	return -1;
+	return -1;                                
     }
-
+    
     /*
     ** Clean out the TX ring asynchronously to interrupts - sometimes the
     ** interrupts are lost by delayed descriptor status updates relative to
@@ -1143,8 +1289,8 @@
 	} else {
 	    de4x5_put_cache(dev, skb);
 	}
-	if (de4x5_debug > 1) {
-	    printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%ld\n  lostMedia:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
+	if (de4x5_debug & DEBUG_TX) {
+	    printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%ld\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
 	}
     } else if (skb->len > 0) {
 	/* If we already have stuff queued locally, use that first */
@@ -1158,10 +1304,10 @@
 	    set_bit(0, (void*)&dev->tbusy);
 	    load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
 	    outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
-
+		
 	    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
 	    dev->trans_start = jiffies;
-
+		    
 	    if (TX_BUFFS_AVAIL) {
 		dev->tbusy = 0;         /* Another pkt may be queued */
 	    }
@@ -1170,15 +1316,15 @@
 	}
 	if (skb) de4x5_putb_cache(dev, skb);
     }
-
+    
     lp->cache.lock = 0;
 
     return status;
 }
 
 /*
-** The DE4X5 interrupt handler.
-**
+** The DE4X5 interrupt handler. 
+** 
 ** I/O Read/Writes through intermediate PCI bridges are never 'posted',
 ** so that the asserted interrupt always has some real data to work with -
 ** if these I/O accesses are ever changed to memory accesses, ensure the
@@ -1194,41 +1340,40 @@
     struct de4x5_private *lp;
     s32 imr, omr, sts, limit;
     u_long iobase;
-
+    
     if (dev == NULL) {
 	printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
 	return;
     }
     lp = (struct de4x5_private *)dev->priv;
     iobase = dev->base_addr;
-
+	
     if (dev->interrupt)
       printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
+	
     DISABLE_IRQs;                        /* Ensure non re-entrancy */
     dev->interrupt = MASK_INTERRUPTS;
-
+	
     for (limit=0; limit<8; limit++) {
 	sts = inl(DE4X5_STS);            /* Read IRQ status */
 	outl(sts, DE4X5_STS);            /* Reset the board interrupts */
-
+	    
 	if (!(sts & lp->irq_mask)) break;/* All done */
-
+	    
 	if (sts & (STS_RI | STS_RU))     /* Rx interrupt (packet[s] arrived) */
 	  de4x5_rx(dev);
-
+	    
 	if (sts & (STS_TI | STS_TU))     /* Tx interrupt (packet sent) */
-	  de4x5_tx(dev);
-
+	  de4x5_tx(dev); 
+	    
 	if (sts & STS_LNF) {             /* TP Link has failed */
-	    lp->lostMedia = LOST_MEDIA_THRESHOLD + 1;
 	    lp->irq_mask &= ~IMR_LFM;
 	}
-
+	    
 	if (sts & STS_UNF) {             /* Transmit underrun */
 	    de4x5_txur(dev);
 	}
-
+	    
 	if (sts & STS_SE) {              /* Bus Error */
 	    STOP_DE4X5;
 	    printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",
@@ -1247,7 +1392,7 @@
 
     dev->interrupt = UNMASK_INTERRUPTS;
     ENABLE_IRQs;
-
+    
     return;
 }
 
@@ -1258,11 +1403,11 @@
     u_long iobase = dev->base_addr;
     int entry;
     s32 status;
-
+    
     for (entry=lp->rx_new; (s32)le32_to_cpu(lp->rx_ring[entry].status)>=0;
 	                                                    entry=lp->rx_new) {
 	status = (s32)le32_to_cpu(lp->rx_ring[entry].status);
-
+	
 	if (lp->rx_ovf) {
 	    if (inl(DE4X5_MFC) & MFC_FOCM) {
 		de4x5_rx_ovfc(dev);
@@ -1273,9 +1418,9 @@
 	if (status & RD_FS) {                 /* Remember the start of frame */
 	    lp->rx_old = entry;
 	}
-
+	
 	if (status & RD_LS) {                 /* Valid frame status */
-	    lp->linkOK++;
+	    if (lp->tx_enable) lp->linkOK++;
 	    if (status & RD_ES) {	      /* There was an error. */
 		lp->stats.rx_errors++;        /* Update the error stats. */
 		if (status & (RD_RF | RD_TL)) lp->stats.rx_frame_errors++;
@@ -1290,9 +1435,9 @@
 		struct sk_buff *skb;
 		short pkt_len = (short)(le32_to_cpu(lp->rx_ring[entry].status)
 					                            >> 16) - 4;
-
+		
 		if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
-		    printk("%s: Insufficient memory; nuking packet.\n",
+		    printk("%s: Insufficient memory; nuking packet.\n", 
 			                                            dev->name);
 		    lp->stats.rx_dropped++;   /* Really, deferred. */
 		    break;
@@ -1302,12 +1447,12 @@
 		/* Push up the protocol stack */
 		skb->protocol=eth_type_trans(skb,dev);
 		netif_rx(skb);
-
+		    
 		/* Update stats */
 		lp->stats.rx_packets++;
 		de4x5_local_stats(dev, skb->data, pkt_len);
 	    }
-
+	    
 	    /* Change buffer ownership for this frame, back to the adapter */
 	    for (;lp->rx_old!=entry;lp->rx_old=(++lp->rx_old)%lp->rxRingSize) {
 		lp->rx_ring[lp->rx_old].status = cpu_to_le32(R_OWN);
@@ -1316,13 +1461,13 @@
 	    lp->rx_ring[entry].status = cpu_to_le32(R_OWN);
 	    barrier();
 	}
-
+	
 	/*
 	** Update entry information
 	*/
 	lp->rx_new = (++lp->rx_new) % lp->rxRingSize;
     }
-
+    
     return 0;
 }
 
@@ -1336,33 +1481,29 @@
     u_long iobase = dev->base_addr;
     int entry;
     s32 status;
-
+    
     for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
 	status = (s32)le32_to_cpu(lp->tx_ring[entry].status);
 	if (status < 0) {                     /* Buffer not sent yet */
 	    break;
 	} else if (status != 0x7fffffff) {    /* Not setup frame */
 	    if (status & TD_ES) {             /* An error happened */
-		lp->stats.tx_errors++;
+		lp->stats.tx_errors++; 
 		if (status & TD_NC) lp->stats.tx_carrier_errors++;
 		if (status & TD_LC) lp->stats.tx_window_errors++;
 		if (status & TD_UF) lp->stats.tx_fifo_errors++;
 		if (status & TD_EC) lp->pktStats.excessive_collisions++;
 		if (status & TD_DE) lp->stats.tx_aborted_errors++;
-
-		if (status & (TD_LO | TD_NC | TD_EC | TD_LF)) {
-		    lp->lostMedia++;
-		}
+	    
 		if (TX_PKT_PENDING) {
 		    outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */
 		}
 	    } else {                      /* Packet sent */
 		lp->stats.tx_packets++;
-		lp->lostMedia = 0;        /* Remove transient problem */
-		lp->linkOK++;
+		if (lp->tx_enable) lp->linkOK++;
 	    }
 	    /* Update the collision counter */
-	    lp->stats.collisions += ((status & TD_EC) ? 16 :
+	    lp->stats.collisions += ((status & TD_EC) ? 16 : 
 				                      ((status & TD_CC) >> 3));
 
 	    /* Free the buffer. */
@@ -1371,7 +1512,7 @@
 		lp->tx_skb[entry] = NULL;
 	    }
 	}
-
+	
 	/* Update all the pointers */
 	lp->tx_old = (++lp->tx_old) % lp->txRingSize;
     }
@@ -1380,7 +1521,7 @@
 	dev->tbusy = 0;                  /* Clear TX busy flag */
 	if (dev->interrupt) mark_bh(NET_BH);
     }
-
+	
     return 0;
 }
 
@@ -1389,10 +1530,12 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int next_tick = DE4X5_AUTOSENSE_MS;
-
+    
     disable_ast(dev);
-
-    if (lp->chipset == DC21140) {
+    
+    if (lp->useSROM) {
+	next_tick = srom_autoconf(dev);
+    } else if (lp->chipset == DC21140) {
 	next_tick = dc21140m_autoconf(dev);
     } else if (lp->chipset == DC21041) {
 	next_tick = dc21041_autoconf(dev);
@@ -1401,7 +1544,7 @@
     }
     lp->linkOK = 0;
     enable_ast(dev, next_tick);
-
+    
     return 0;
 }
 
@@ -1424,11 +1567,11 @@
 	}
 	outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
     }
-
+    
     return 0;
 }
 
-static int
+static int 
 de4x5_rx_ovfc(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
@@ -1445,7 +1588,7 @@
     }
 
     outl(omr, DE4X5_OMR);
-
+    
     return 0;
 }
 
@@ -1455,22 +1598,22 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     s32 imr, omr;
-
+    
     disable_ast(dev);
     dev->start = 0;
     dev->tbusy = 1;
-
-    if (de4x5_debug > 1) {
+    
+    if (de4x5_debug & DEBUG_CLOSE) {
 	printk("%s: Shutting down ethercard, status was %8.8x.\n",
 	       dev->name, inl(DE4X5_STS));
     }
-
-    /*
+    
+    /* 
     ** We stop the DE4X5 here... mask interrupts and stop TX & RX
     */
     DISABLE_IRQs;
     STOP_DE4X5;
-
+    
     /* Free the associated irq */
     free_irq(dev->irq, dev);
     lp->state = CLOSED;
@@ -1478,26 +1621,22 @@
     /* Free any socket buffers */
     de4x5_free_rx_buffs(dev);
     de4x5_free_tx_buffs(dev);
-
+    
     MOD_DEC_USE_COUNT;
-
+    
     /* Put the adapter to sleep to save power */
-    if (lp->chipset == DC21041) {
-	outl(0, DE4X5_SICR);
-	outl(CFDA_PSM, PCI_CFDA);
-    }
-
+    yawn(dev, SLEEP);
+    
     return 0;
 }
 
-static struct enet_statistics *
-de4x5_get_stats(struct device *dev)
+static struct net_device_stats *de4x5_get_stats(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-
+    
     lp->stats.rx_missed_errors = (int)(inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
-
+    
     return &lp->stats;
 }
 
@@ -1523,7 +1662,7 @@
 	       (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
         lp->pktStats.unicast++;
     }
-
+		
     lp->pktStats.bins[0]++;       /* Duplicates stats.rx_packets */
     if (lp->pktStats.bins[0] == 0) { /* Reset counters */
         memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
@@ -1536,7 +1675,7 @@
 load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
+    
     lp->tx_ring[lp->tx_new].buf = cpu_to_le32(virt_to_bus(buf));
     lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER);
     lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags);
@@ -1544,7 +1683,7 @@
     barrier();
     lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN);
     barrier();
-
+    
     return;
 }
 
@@ -1564,17 +1703,17 @@
 	    omr = inl(DE4X5_OMR);
 	    omr |= OMR_PR;
 	    outl(omr, DE4X5_OMR);
-	} else {
+	} else { 
 	    SetMulticastFilter(dev);
-	    load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
+	    load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
 			                                SETUP_FRAME_LEN, NULL);
-
+	    
 	    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
 	    outl(POLL_DEMAND, DE4X5_TPD);       /* Start the TX */
 	    dev->trans_start = jiffies;
 	}
     }
-
+    
     return;
 }
 
@@ -1598,26 +1737,26 @@
     omr = inl(DE4X5_OMR);
     omr &= ~(OMR_PR | OMR_PM);
     pa = build_setup_frame(dev, ALL);        /* Build the basic frame */
-
+    
     if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) {
 	omr |= OMR_PM;                       /* Pass all multicasts */
     } else if (lp->setup_f == HASH_PERF) {   /* Hash Filtering */
 	for (i=0;i<dev->mc_count;i++) {      /* for each address in the list */
 	    addrs=dmi->dmi_addr;
 	    dmi=dmi->next;
-	    if ((*addrs & 0x01) == 1) {      /* multicast address? */
+	    if ((*addrs & 0x01) == 1) {      /* multicast address? */ 
 		crc = 0xffffffff;            /* init CRC for each address */
 		for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
-		                             /* process each address bit */
+		                             /* process each address bit */ 
 		    for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
 			crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
 		    }
 		}
 		hashcode = crc & HASH_BITS;  /* hashcode is 9 LSb of CRC */
-
+		
 		byte = hashcode >> 3;        /* bit[3-8] -> byte in filter */
 		bit = 1 << (hashcode & 0x07);/* bit[0-2] -> bit in byte */
-
+		
 		byte <<= 1;                  /* calc offset into setup frame */
 		if (byte & 0x02) {
 		    byte -= 1;
@@ -1629,14 +1768,14 @@
 	for (j=0; j<dev->mc_count; j++) {
 	    addrs=dmi->dmi_addr;
 	    dmi=dmi->next;
-	    for (i=0; i<ETH_ALEN; i++) {
+	    for (i=0; i<ETH_ALEN; i++) { 
 		*(pa + (i&1)) = *addrs++;
 		if (i & 0x01) pa += 4;
 	    }
 	}
     }
     outl(omr, DE4X5_OMR);
-
+    
     return;
 }
 
@@ -1647,18 +1786,18 @@
 static void
 eisa_probe(struct device *dev, u_long ioaddr)
 {
-    int i, maxSlots, status;
-    u_short vendor, device;
-    s32 cfid;
+    int i, maxSlots, status, device;
+    u_short vendor;
+    u32 cfid;
     u_long iobase;
     struct bus_type *lp = &bus;
     char name[DE4X5_STRLEN];
     struct device *tmp;
-
-    if (!ioaddr && autoprobed) return;     /* Been here before ! */
-
+    
+    if (autoprobed) return;                /* Been here before ! */
+    
     lp->bus = EISA;
-
+    
     if (ioaddr == 0) {                     /* Autoprobing */
 	iobase = EISA_SLOT_INC;            /* Get the first slot address */
 	i = 1;
@@ -1668,31 +1807,33 @@
 	i = (ioaddr >> 12);
 	maxSlots = i + 1;
     }
-
-    for (status = -ENODEV;
-	 (i<maxSlots) && (dev!=NULL) && (!loading_module || (num_de4x5s == 0));
-	 i++, iobase+=EISA_SLOT_INC) {
+    
+    for (status= -ENODEV;(i<maxSlots)&&(dev!=NULL);i++,iobase+=EISA_SLOT_INC) {
 	if (EISA_signature(name, EISA_ID)) {
-	    cfid = inl(PCI_CFID);
-	    cfrv = inl(PCI_CFRV);
-	    device = (u_short)(cfid >> 16);
+	    cfid = (u32) inl(PCI_CFID);
+	    cfrv = (u_short) inl(PCI_CFRV);
+	    device = (cfid >> 8) & 0x00ffff00;
 	    vendor = (u_short) cfid;
-
+	    
 	    /* Read the EISA Configuration Registers */
 	    dev->irq = inb(EISA_REG0);
 	    dev->irq = de4x5_irq[(dev->irq >> 1) & 0x03];
 
+	    if (is_DC2114x) device |= (cfrv & 0x00f0);
 	    lp->chipset = device;
 	    DevicePresent(DE4X5_APROM);
 	    /* Write the PCI Configuration Registers */
 	    outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
 	    outl(0x00006000, PCI_CFLT);
 	    outl(iobase, PCI_CBIO);
-
+	    
 	    if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
 		if ((tmp = alloc_device(dev, iobase)) != NULL) {
 		    if ((status = de4x5_hw_init(tmp, iobase)) == 0) {
 			num_de4x5s++;
+			if (loading_module) link_modules(dev, tmp);
+		    } else if (loading_module && (tmp != dev)) {
+			kfree(tmp);
 		    }
 		}
 	    } else if (autoprobed) {
@@ -1700,7 +1841,7 @@
 	    }
 	}
     }
-
+    
     return;
 }
 
@@ -1724,18 +1865,18 @@
 {
     u_char irq;
     u_char pb, pbus, dev_num, dnum, dev_fn;
-    u_short vendor, device, index, status;
+    u_short vendor, index, status;
     u_int class = DE4X5_CLASS_CODE;
-    u_int iobase;
+    u_int device, iobase;
     struct bus_type *lp = &bus;
     struct device *tmp;
 
-    if ((!ioaddr || !loading_module) && autoprobed) return;
-
+    if (autoprobed) return;
+    
     if (!pcibios_present()) return;          /* No PCI bus in this machine! */
-
+    
     lp->bus = PCI;
-
+    
     if ((ioaddr < 0x1000) && loading_module) {
 	pbus = (u_short)(ioaddr >> 8);
 	dnum = (u_short)(ioaddr & 0xff);
@@ -1744,26 +1885,35 @@
 	dnum = 0;
     }
 
-    for (index=0;
-	 (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND) &&
-	 (!loading_module || (num_de4x5s == 0));
+    for (index=0; 
+	 (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
 	 index++) {
 	dev_num = PCI_SLOT(dev_fn);
 
 	if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
+	    device = 0;
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
-	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device);
-	    if (!(is_DC21040 || is_DC21041 || is_DC21140)) continue;
+	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, (u_short *)&device);
+	    device <<= 8;
+	    if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
+		continue;
+	    }
+
+	    /* Get the chip configuration revision register */
+	    pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
 
 	    /* Set the device number information */
 	    lp->device = dev_num;
 	    lp->bus_num = pb;
-
+	    
 	    /* Set the chipset information */
+	    if (is_DC2114x) device |= (cfrv & 0x00f0);
 	    lp->chipset = device;
 
-	    /* Get the chip configuration revision register */
-	    pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
+	    if (is_DC21142 || is_DC21143) {
+		printk("de4x5: Detected a %s chip. Currently this is unsupported in this driver.\nPlease email the author to request its inclusion!\n", (is_DC21142?"DC21142":"DC21143"));
+		continue;
+	    }
 
 	    /* Get the board I/O address */
 	    pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
@@ -1772,7 +1922,7 @@
 	    /* Fetch the IRQ to be used */
 	    pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq);
 	    if ((irq == 0) || (irq == (u_char) 0xff)) continue;
-
+	    
 	    /* Check if I/O accesses and Bus Mastering are enabled */
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
 	    if (!(status & PCI_COMMAND_IO)) continue;
@@ -1789,15 +1939,18 @@
 		    tmp->irq = irq;
 		    if ((status = de4x5_hw_init(tmp, iobase)) == 0) {
 			num_de4x5s++;
+			if (loading_module) link_modules(dev, tmp);
+		    } else if (loading_module && (tmp != dev)) {
+			kfree(tmp);
 		    }
 		}
 	    } else if (autoprobed) {
-		printk("%s: region already allocated at 0x%04x.\n", dev->name,
+		printk("%s: region already allocated at 0x%04x.\n", dev->name, 
 		       (u_short)iobase);
 	    }
 	}
     }
-
+    
     return;
 }
 
@@ -1813,8 +1966,16 @@
     struct device *adev = NULL;
     int fixed = 0, new_dev = 0;
 
+    if (!dev) return dev;
     num_eth = de4x5_dev_index(dev->name);
-    if (loading_module) return dev;
+
+    if (loading_module) {
+	if (dev->priv) {
+	    dev = insert_device(dev, iobase, de4x5_probe);
+	}
+	num_eth++;
+	return dev;
+    }
 
     while (1) {
 	if (((dev->base_addr == DE4X5_NDA) || (dev->base_addr==0)) && !adev) {
@@ -1838,13 +1999,13 @@
 	new_dev = 0;
     }
 
-    if (((dev->next == NULL) &&
+    if (((dev->next == NULL) &&  
 	((dev->base_addr != DE4X5_NDA) && (dev->base_addr != 0)) && !fixed) ||
 	new_dev) {
 	num_eth++;                         /* New device */
 	dev = insert_device(dev, iobase, de4x5_probe);
     }
-
+    
     return dev;
 }
 
@@ -1862,20 +2023,22 @@
 	printk("eth%d: Device not initialised, insufficient memory\n",num_eth);
 	return NULL;
     } else {
-	new->next = dev->next;
-	dev->next = new;
-	dev = dev->next;               /* point to the new device */
-	dev->name = (char *)(dev + 1);
-	if (num_eth > 9999) {
-	    sprintf(dev->name,"eth????");/* New device name */
-	} else {
-	    sprintf(dev->name,"eth%d", num_eth);/* New device name */
+	memset((char *)new, 0, sizeof(struct device)+8);
+	new->name = (char *)(new + 1);
+	new->base_addr = iobase;       /* assign the io address */
+	new->init = init;              /* initialisation routine */
+	if (!loading_module) {
+	    new->next = dev->next;
+	    dev->next = new;
+	    if (num_eth > 9999) {
+		sprintf(new->name,"eth????");/* New device name */
+	    } else {
+		sprintf(new->name,"eth%d", num_eth);/* New device name */
+	    }
 	}
-	dev->base_addr = iobase;       /* assign the io address */
-	dev->init = init;              /* initialisation routine */
     }
 
-    return dev;
+    return new;
 }
 
 static int
@@ -1893,11 +2056,54 @@
     return i;
 }
 
+static void
+link_modules(struct device *dev, struct device *tmp)
+{
+    struct device *p=dev;
+
+    if (p) {
+	while (((struct de4x5_private *)(p->priv))->next_module) {
+	    p = ((struct de4x5_private *)(p->priv))->next_module;
+	}
+
+	if (dev != tmp) {
+	    ((struct de4x5_private *)(p->priv))->next_module = tmp;
+	} else {
+	    ((struct de4x5_private *)(p->priv))->next_module = NULL;
+	}
+    }
+
+    return;
+}
+
+static struct device *
+unlink_modules(struct device *p)
+{
+    struct device *next = NULL;
+
+    if (p->priv) {                          /* Private areas allocated?  */
+	struct de4x5_private *lp = (struct de4x5_private *)p->priv;
+
+	next = lp->next_module;
+	if (lp->cache.buf) {                /* MAC buffers allocated?    */
+	    kfree(lp->cache.buf);           /* Free the MAC buffers      */
+	}
+	kfree(lp->cache.priv);              /* Free the private area     */
+	release_region(p->base_addr, (lp->bus == PCI ? 
+				      DE4X5_PCI_TOTAL_SIZE :
+				      DE4X5_EISA_TOTAL_SIZE));
+    }
+    unregister_netdev(p);
+    kfree(p);                               /* Free the device structure */
+    
+    return next;
+}
+
 /*
 ** Auto configure the media here rather than setting the port at compile
 ** time. This routine is called by de4x5_init() and when a loss of media is
 ** detected (excessive collisions, loss of carrier, no carrier or link fail
-** [TP] or no recent receive activity) to check whether the user has been
+** [TP] or no recent receive activity) to check whether the user has been 
 ** sneaky and changed the port on us.
 */
 static int
@@ -1906,21 +2112,24 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int next_tick = DE4X5_AUTOSENSE_MS;;
-
+    
     lp->linkOK = 0;
     lp->c_media = AUTO;                     /* Bogus last media */
     disable_ast(dev);
     inl(DE4X5_MFC);                         /* Zero the lost frames counter */
     lp->media = INIT;
-    if (lp->chipset == DC21040) {
+    if (lp->useSROM) {
+	next_tick = srom_autoconf(dev);
+    } else if (lp->chipset == DC21040) {
 	next_tick = dc21040_autoconf(dev);
     } else if (lp->chipset == DC21041) {
 	next_tick = dc21041_autoconf(dev);
     } else if (lp->chipset == DC21140) {
 	next_tick = dc21140m_autoconf(dev);
     }
-    enable_ast(dev, next_tick);
 
+    enable_ast(dev, next_tick);
+    
     return (lp->media);
 }
 
@@ -1943,7 +2152,7 @@
     u_long iobase = dev->base_addr;
     int next_tick = DE4X5_AUTOSENSE_MS;
     s32 imr;
-
+    
     switch (lp->media) {
       case INIT:
 	DISABLE_IRQs;
@@ -1962,36 +2171,36 @@
 	lp->local_state = 0;
 	next_tick = dc21040_autoconf(dev);
 	break;
-
+	
       case TP:
-	next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI,
+	next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, 
 		                                         TP_SUSPECT, test_tp);
 	break;
-
+	
       case TP_SUSPECT:
 	next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
 	break;
-
+	
       case BNC:
       case AUI:
       case BNC_AUI:
-	next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA,
+	next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, 
 		                                  BNC_AUI_SUSPECT, ping_media);
 	break;
-
+	
       case BNC_AUI_SUSPECT:
 	next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
 	break;
-
+	
       case EXT_SIA:
-	next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000,
+	next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, 
 		                              NC, EXT_SIA_SUSPECT, ping_media);
 	break;
-
+	
       case EXT_SIA_SUSPECT:
 	next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
 	break;
-
+	
       case NC:
 	/* default to TP for all */
 	reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
@@ -2003,13 +2212,13 @@
 	lp->tx_enable = NO;
 	break;
     }
-
+    
     return next_tick;
 }
 
 static int
 dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout,
-	      int next_state, int suspect_state,
+	      int next_state, int suspect_state, 
 	      int (*fn)(struct device *, int))
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
@@ -2022,7 +2231,7 @@
 	lp->local_state++;
 	next_tick = 500;
 	break;
-
+	    
       case 1:
 	if (!lp->tx_enable) {
 	    linkBad = fn(dev, timeout);
@@ -2042,7 +2251,7 @@
 	}
 	break;
     }
-
+    
     return next_tick;
 }
 
@@ -2057,7 +2266,7 @@
 
     switch (lp->local_state) {
       case 1:
-	if (lp->linkOK && !LOST_MEDIA) {
+	if (lp->linkOK) {
 	    lp->media = prev_state;
 	} else {
 	    lp->local_state++;
@@ -2096,7 +2305,7 @@
     u_long iobase = dev->base_addr;
     s32 sts, irqs, irq_mask, imr, omr;
     int next_tick = DE4X5_AUTOSENSE_MS;
-
+    
     switch (lp->media) {
       case INIT:
 	DISABLE_IRQs;
@@ -2117,11 +2326,11 @@
 	lp->local_state = 0;
 	next_tick = dc21041_autoconf(dev);
 	break;
-
+	
       case TP_NW:
 	if (lp->timeout < 0) {
 	    omr = inl(DE4X5_OMR);/* Set up full duplex for the autonegotiate */
-	    outl(omr | OMR_FD, DE4X5_OMR);
+	    outl(omr | OMR_FDX, DE4X5_OMR);
 	}
 	irqs = STS_LNF | STS_LNP;
 	irq_mask = IMR_LFM | IMR_LPM;
@@ -2137,7 +2346,7 @@
 	    next_tick = dc21041_autoconf(dev);
 	}
 	break;
-
+	
       case ANS:
 	if (!lp->tx_enable) {
 	    irqs = STS_LNP;
@@ -2159,16 +2368,16 @@
 	    next_tick = 3000;
 	}
 	break;
-
+	
       case ANS_SUSPECT:
 	next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
 	break;
-
+	
       case TP:
 	if (!lp->tx_enable) {
 	    if (lp->timeout < 0) {
 		omr = inl(DE4X5_OMR);          /* Set up half duplex for TP */
-		outl(omr & ~OMR_FD, DE4X5_OMR);
+		outl(omr & ~OMR_FDX, DE4X5_OMR);
 	    }
 	    irqs = STS_LNF | STS_LNP;
 	    irq_mask = IMR_LFM | IMR_LPM;
@@ -2193,16 +2402,16 @@
 	    next_tick = 3000;
 	}
 	break;
-
+	
       case TP_SUSPECT:
 	next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
 	break;
-
+	
       case AUI:
 	if (!lp->tx_enable) {
 	    if (lp->timeout < 0) {
 		omr = inl(DE4X5_OMR);          /* Set up half duplex for AUI */
-		outl(omr & ~OMR_FD, DE4X5_OMR);
+		outl(omr & ~OMR_FDX, DE4X5_OMR);
 	    }
 	    irqs = 0;
 	    irq_mask = 0;
@@ -2223,17 +2432,17 @@
 	    next_tick = 3000;
 	}
 	break;
-
+	
       case AUI_SUSPECT:
 	next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
 	break;
-
+	
       case BNC:
 	switch (lp->local_state) {
 	  case 0:
 	    if (lp->timeout < 0) {
 		omr = inl(DE4X5_OMR);          /* Set up half duplex for BNC */
-		outl(omr & ~OMR_FD, DE4X5_OMR);
+		outl(omr & ~OMR_FDX, DE4X5_OMR);
 	    }
 	    irqs = 0;
 	    irq_mask = 0;
@@ -2245,7 +2454,7 @@
 		next_tick = dc21041_autoconf(dev);
 	    }
 	    break;
-
+	    
 	  case 1:
 	    if (!lp->tx_enable) {
 		if ((sts = ping_media(dev, 3000)) < 0) {
@@ -2265,14 +2474,14 @@
 	    break;
 	}
 	break;
-
+	
       case BNC_SUSPECT:
 	next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
 	break;
-
+	
       case NC:
 	omr = inl(DE4X5_OMR);    /* Set up full duplex for the autonegotiate */
-	outl(omr | OMR_FD, DE4X5_OMR);
+	outl(omr | OMR_FDX, DE4X5_OMR);
 	reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */
 	if (lp->media != lp->c_media) {
 	    de4x5_dbg_media(dev);
@@ -2282,7 +2491,7 @@
 	lp->tx_enable = NO;
 	break;
     }
-
+    
     return next_tick;
 }
 
@@ -2300,38 +2509,43 @@
     u_long imr, omr;
 
     switch(lp->media) {
-      case INIT:
+      case INIT: 
 	DISABLE_IRQs;
 	lp->tx_enable = FALSE;
-	lp->timeout = -1;
+        lp->linkOK = 0;
+/*	lp->timeout = -1;*/
 	if ((next_tick = de4x5_reset_phy(dev)) < 0) {
 	    next_tick &= ~TIMER_CB;
 	} else {
 	    de4x5_save_skbs(dev);          /* Save non transmitted skb's */
-	    lp->tmp = MII_SR_ASSC;         /* Fake out the MII speed set */
-	    SET_10Mb;
-	    if (lp->autosense == _100Mb) {
-		lp->media = _100Mb;
-	    } else if (lp->autosense == _10Mb) {
-		lp->media = _10Mb;
-	    } else if ((lp->autosense == AUTO) &&
-		                     ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
-		ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
-		ana &= (de4x5_full_duplex ? ~0 : ~MII_ANA_FDAM);
-		mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-		lp->media = ANS;
-	    } else if (lp->autosense == AUTO) {
-		lp->media = SPD_DET;
-	    } else if (is_spd_100(dev) && is_100_up(dev)) {
-		lp->media = _100Mb;
+	    if (lp->useSROM) {
+		srom_map_media(dev);
 	    } else {
-		lp->media = NC;
+		lp->tmp = MII_SR_ASSC;     /* Fake out the MII speed set */
+		SET_10Mb;
+		if (lp->autosense == _100Mb) {
+		    lp->media = _100Mb;
+		} else if (lp->autosense == _10Mb) {
+		    lp->media = _10Mb;
+		} else if ((lp->autosense == AUTO) && 
+			            ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
+		    ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
+		    ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
+		    mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+		    lp->media = ANS;
+		} else if (lp->autosense == AUTO) {
+		    lp->media = SPD_DET;
+		} else if (is_spd_100(dev) && is_100_up(dev)) {
+		    lp->media = _100Mb;
+		} else {
+		    lp->media = NC;
+		}
 	    }
 	    lp->local_state = 0;
 	    next_tick = dc21140m_autoconf(dev);
 	}
 	break;
-
+	
       case ANS:
 	switch (lp->local_state) {
 	  case 0:
@@ -2351,7 +2565,7 @@
 		next_tick = dc21140m_autoconf(dev);
 	    }
 	    break;
-
+	    
 	  case 1:
 	    if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
 		next_tick = sr & ~TIMER_CB;
@@ -2362,13 +2576,13 @@
 		    lp->tmp = MII_SR_ASSC;
 		    anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
 		    ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-		    if (!(anlpa & MII_ANLPA_RF) &&
+		    if (!(anlpa & MII_ANLPA_RF) && 
 			 (cap = anlpa & MII_ANLPA_TAF & ana)) {
 			if (cap & MII_ANA_100M) {
-			    de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
 			    lp->media = _100Mb;
 			} else if (cap & MII_ANA_10M) {
-			    de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
 
 			    lp->media = _10Mb;
 			}
@@ -2379,7 +2593,7 @@
 	    break;
 	}
 	break;
-
+	
       case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
         if (lp->timeout < 0) {
 	    lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
@@ -2399,9 +2613,9 @@
 	    next_tick = dc21140m_autoconf(dev);
 	}
 	break;
-
+	
       case _100Mb:                               /* Set 100Mb/s */
-	next_tick = 3000;
+        next_tick = 3000;
 	if (!lp->tx_enable) {
 	    SET_100Mb;
 	    de4x5_init_connection(dev);
@@ -2409,14 +2623,15 @@
 	    if (!lp->linkOK && (lp->autosense == AUTO)) {
 		if (!(is_spd_100(dev) && is_100_up(dev))) {
 		    lp->media = INIT;
+		    lp->tcount++;
 		    next_tick = DE4X5_AUTOSENSE_MS;
 		}
 	    }
 	}
 	break;
-
+	
       case _10Mb:                                /* Set 10Mb/s */
-	next_tick = 3000;
+        next_tick = 3000;
 	if (!lp->tx_enable) {
 	    SET_10Mb;
 	    de4x5_init_connection(dev);
@@ -2424,12 +2639,13 @@
 	    if (!lp->linkOK && (lp->autosense == AUTO)) {
 		if (!(!is_spd_100(dev) && is_10_up(dev))) {
 		    lp->media = INIT;
+		    lp->tcount++;
 		    next_tick = DE4X5_AUTOSENSE_MS;
 		}
 	    }
 	}
 	break;
-
+	
       case NC:
         if (lp->media != lp->c_media) {
 	    de4x5_dbg_media(dev);
@@ -2439,10 +2655,76 @@
 	lp->tx_enable = FALSE;
 	break;
     }
-
+    
     return next_tick;
 }
 
+static int
+srom_autoconf(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    return lp->infoleaf_fn(dev);
+}
+
+/*
+** This mapping keeps the original media codes and FDX flag unchanged.
+** While it isn't strictly necessary, it helps me for the moment...
+*/
+static void
+srom_map_media(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    lp->fdx = 0;
+    switch(lp->infoblock_media) {
+      case SROM_10BASETF:
+	lp->fdx = TRUE;
+      case SROM_10BASET:
+	if (lp->chipset == DC21140) {
+	    lp->media = _10Mb;
+	} else {
+	    lp->media = TP;
+	}
+	break;
+
+      case SROM_10BASE2:
+	lp->media = BNC;
+	break;
+
+      case SROM_10BASE5:
+	lp->media = AUI;
+	break;
+
+      case SROM_100BASETF:
+	lp->fdx = TRUE;
+      case SROM_100BASET:
+	lp->media = _100Mb;
+	break;
+
+      case SROM_100BASET4:
+	lp->media = _100Mb;
+	break;
+
+      case SROM_100BASEFF:
+	lp->fdx = TRUE;
+      case SROM_100BASEF: 
+	lp->media = _100Mb;
+	break;
+
+      case ANS:
+	lp->media = ANS;
+	break;
+
+      default: 
+	printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, 
+	                                                  lp->infoblock_media);
+	break;
+    }
+
+    return;
+}
+
 static void
 de4x5_init_connection(struct device *dev)
 {
@@ -2457,7 +2739,6 @@
     cli();
     de4x5_rx(dev);
     de4x5_setup_intr(dev);
-    lp->lostMedia = 0;
     lp->tx_enable = YES;
     dev->tbusy = 0;
     sti();
@@ -2467,6 +2748,9 @@
     return;
 }
 
+/*
+** General PHY reset function.
+*/
 static int
 de4x5_reset_phy(struct device *dev)
 {
@@ -2474,15 +2758,26 @@
     u_long iobase = dev->base_addr;
     int next_tick = 0;
 
-    if (lp->phy[lp->active].id) {
+    if ((lp->useSROM) || (lp->phy[lp->active].id)) {
 	if (lp->timeout < 0) {
-	    outl(GEP_HRST, DE4X5_GEP);           /* Hard RESET the PHY dev. */
-	    udelay(1000);                        /* Assert for 1ms */
-	    outl(0x00, DE4X5_GEP);
-	    udelay(2000);                        /* Wait for 2ms */
-	    mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+	    if (lp->useSROM) {
+		if (lp->phy[lp->active].rst) { /* MII device specific reset */
+		    srom_exec(dev, lp->phy[lp->active].rst);
+		} else if (lp->rst) {          /* Type 5 infoblock reset */
+		    srom_exec(dev, lp->rst);
+		}
+	    } else {
+		PHY_HARD_RESET;
+	    }
+	    if (lp->useMII) {
+	        mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+            }
+        }
+	if (lp->useMII) {
+	    next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
 	}
-	next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
+    } else if (lp->chipset == DC21140) {
+	PHY_HARD_RESET;
     }
 
     return next_tick;
@@ -2494,7 +2789,7 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     s32 sts, csr12;
-
+    
     if (lp->timeout < 0) {
 	lp->timeout = msec/100;
 	reset_init_sia(dev, csr13, csr14, csr15);
@@ -2505,22 +2800,22 @@
 	/* clear all pending interrupts */
 	sts = inl(DE4X5_STS);
 	outl(sts, DE4X5_STS);
-
+	
 	/* clear csr12 NRA and SRA bits */
 	if (lp->chipset == DC21041) {
 	    csr12 = inl(DE4X5_SISR);
 	    outl(csr12, DE4X5_SISR);
 	}
     }
-
+    
     sts = inl(DE4X5_STS) & ~TIMER_CB;
-
+    
     if (!(sts & irqs) && --lp->timeout) {
 	sts = 100 | TIMER_CB;
     } else {
 	lp->timeout = -1;
     }
-
+    
     return sts;
 }
 
@@ -2530,11 +2825,11 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int sisr;
-
+    
     if (lp->timeout < 0) {
 	lp->timeout = msec/100;
     }
-
+    
     sisr = (inl(DE4X5_SISR) & ~TIMER_CB) & (SISR_LKF | SISR_NCR);
 
     if (sisr && --lp->timeout) {
@@ -2542,7 +2837,7 @@
     } else {
 	lp->timeout = -1;
     }
-
+    
     return sisr;
 }
 
@@ -2552,12 +2847,12 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
     int gep = 0;
-
+    
     if (lp->timeout < 0) {
 	lp->timeout = msec/100;
     }
-
-    if (lp->phy[lp->active].id) {
+    
+    if (lp->phy[lp->active].id || lp->useSROM) {
 	gep = ((is_100_up(dev) && is_spd_100(dev)) ? GEP_SLNK : 0);
     } else {
 	gep = (~inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP));
@@ -2567,7 +2862,7 @@
     } else {
 	lp->timeout = -1;
     }
-
+    
     return gep;
 }
 
@@ -2580,21 +2875,21 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int test, iobase = dev->base_addr;
-
+    
     if (lp->timeout < 0) {
 	lp->timeout = msec/100;
     }
-
+    
     if (pol) pol = ~0;
     reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
     test = (reg ^ pol) & mask;
-
+    
     if (test && --lp->timeout) {
 	reg = 100 | TIMER_CB;
     } else {
 	lp->timeout = -1;
     }
-
+    
     return reg;
 }
 
@@ -2604,15 +2899,19 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int spd;
-
-    if (lp->phy[lp->active].id) {
+    
+    if (lp->useSROM && !lp->useMII) {
+	spd = (lp->asBitValid & 
+	       (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
+ 		 (lp->linkOK & ~lp->asBitValid);
+    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
 	spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII);
 	spd = ~(spd ^ lp->phy[lp->active].spd.value);
 	spd &= lp->phy[lp->active].spd.mask;
     } else {
 	spd = ((~inl(DE4X5_GEP)) & GEP_SLNK);
     }
-
+    
     return spd;
 }
 
@@ -2621,8 +2920,12 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-
-    if (lp->phy[lp->active].id) {
+    
+    if (lp->useSROM && !lp->useMII) {
+	return ((lp->asBitValid & 
+		 (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
+		(lp->linkOK & ~lp->asBitValid));
+    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
 	/* Double read for sticky bits & temporary drops */
 	mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
 	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
@@ -2636,8 +2939,12 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-
-    if (lp->phy[lp->active].id) {
+    
+    if (lp->useSROM && !lp->useMII) {
+	return ((lp->asBitValid & 
+		 (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
+		(lp->linkOK & ~lp->asBitValid));
+    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
 	/* Double read for sticky bits & temporary drops */
 	mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
 	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
@@ -2651,8 +2958,8 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-
-    if (lp->phy[lp->active].id) {
+    
+    if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
 	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
     } else {
 	return 0;
@@ -2669,24 +2976,24 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int sisr;
-
+    
     if (lp->timeout < 0) {
 	lp->timeout = msec/100;
-
+	
 	lp->tmp = lp->tx_new;                /* Remember the ring position */
 	load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), NULL);
 	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
 	outl(POLL_DEMAND, DE4X5_TPD);
     }
-
+    
     sisr = inl(DE4X5_SISR);
 
-    if ((!(sisr & SISR_NCR)) &&
-	((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) &&
+    if ((!(sisr & SISR_NCR)) && 
+	((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) && 
 	 (--lp->timeout)) {
 	sisr = 100 | TIMER_CB;
     } else {
-	if ((!(sisr & SISR_NCR)) &&
+	if ((!(sisr & SISR_NCR)) && 
 	    !(le32_to_cpu(lp->tx_ring[lp->tmp].status) & (T_OWN | TD_ES)) &&
 	    lp->timeout) {
 	    sisr = 0;
@@ -2695,7 +3002,7 @@
 	}
 	lp->timeout = -1;
     }
-
+    
     return sisr;
 }
 
@@ -2742,15 +3049,15 @@
     skb_reserve(p, 2);	                               /* Align */
     if (index < lp->rx_old) {                          /* Wrapped buffer */
 	short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
-	memcpy(skb_put(p,tlen),
+	memcpy(skb_put(p,tlen), 
 	       bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),tlen);
-	memcpy(skb_put(p,len-tlen),
+	memcpy(skb_put(p,len-tlen), 
 	       bus_to_virt(le32_to_cpu(lp->rx_ring[0].buf)), len-tlen);
     } else {                                           /* Linear buffer */
-	memcpy(skb_put(p,len),
+	memcpy(skb_put(p,len), 
 	       bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),len);
     }
-
+		    
     return p;
 #endif
 }
@@ -2837,7 +3144,7 @@
 	lp->cache.save_cnt--;
 	START_DE4X5;
     }
-
+        
     return;
 }
 
@@ -2846,7 +3153,6 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    s32 gep;
 
     switch(flag) {
       case DE4X5_SAVE_STATE:
@@ -2865,14 +3171,10 @@
 	outl(lp->cache.csr6, DE4X5_OMR);
 	outl(lp->cache.csr7, DE4X5_IMR);
 	if (lp->chipset == DC21140) {
-	    outl(GEP_INIT, DE4X5_GEP);
-	    gep = (lp->media == _100Mb ? GEP_MODE : 0);
-	    if (!lp->phy[lp->active].id && !de4x5_full_duplex) {
-		gep |= GEP_FDXD;
-	    }
-	    outl(gep, DE4X5_GEP);
+	    outl(lp->cache.gepc, DE4X5_GEP);
+	    outl(lp->cache.gep, DE4X5_GEP);
 	} else {
-	    reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14,
+	    reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, 
 			                                      lp->cache.csr15);
 	}
 	break;
@@ -2934,25 +3236,25 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     s32 sts, ans;
-
+    
     if (lp->timeout < 0) {
 	lp->timeout = msec/100;
 	outl(irq_mask, DE4X5_IMR);
-
+	
 	/* clear all pending interrupts */
 	sts = inl(DE4X5_STS);
 	outl(sts, DE4X5_STS);
     }
-
+    
     ans = inl(DE4X5_SISR) & SISR_ANS;
     sts = inl(DE4X5_STS) & ~TIMER_CB;
-
+    
     if (!(sts & irqs) && (ans ^ ANS_NWOK) && --lp->timeout) {
 	sts = 100 | TIMER_CB;
     } else {
 	lp->timeout = -1;
     }
-
+    
     return sts;
 }
 
@@ -2962,7 +3264,7 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     s32 imr, sts;
-
+    
     if (inl(DE4X5_OMR) & OMR_SR) {   /* Only unmask if TX/RX is enabled */
 	imr = 0;
 	UNMASK_IRQs;
@@ -2970,7 +3272,7 @@
 	outl(sts, DE4X5_STS);
 	ENABLE_IRQs;
     }
-
+    
     return;
 }
 
@@ -2982,7 +3284,7 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-
+    
     RESET_SIA;
     outl(sigr, DE4X5_SIGR);
     outl(strr, DE4X5_STRR);
@@ -2992,24 +3294,24 @@
 }
 
 /*
-** Create a loopback ethernet packet with an invalid CRC
+** Create a loopback ethernet packet
 */
 static void
 create_packet(struct device *dev, char *frame, int len)
 {
     int i;
     char *buf = frame;
-
+    
     for (i=0; i<ETH_ALEN; i++) {             /* Use this source address */
 	*buf++ = dev->dev_addr[i];
     }
     for (i=0; i<ETH_ALEN; i++) {             /* Use this destination address */
 	*buf++ = dev->dev_addr[i];
     }
-
+    
     *buf++ = 0;                              /* Packet length (2 bytes) */
     *buf++ = 1;
-
+    
     return;
 }
 
@@ -3020,7 +3322,7 @@
 de4x5_us_delay(u32 usec)
 {
     udelay(usec);
-
+    
     return;
 }
 
@@ -3031,11 +3333,11 @@
 de4x5_ms_delay(u32 msec)
 {
     u_int i;
-
+    
     for (i=0; i<msec; i++) {
 	de4x5_us_delay(1000);
     }
-
+    
     return;
 }
 
@@ -3053,17 +3355,17 @@
 	char Id[4];
     } Eisa;
     int i, status = 0, siglen = sizeof(signatures)/sizeof(c_char *);
-
+    
     *name = '\0';
     Eisa.ID = inl(eisa_id);
-
+    
     ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
     ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
     ManCode[2]=(((Eisa.Id[2]>>4)&0x0f)+0x30);
     ManCode[3]=((Eisa.Id[2]&0x0f)+0x30);
     ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
     ManCode[5]='\0';
-
+    
     for (i=0;i<siglen;i++) {
 	if (strstr(ManCode, signatures[i]) != NULL) {
 	    strcpy(name,ManCode);
@@ -3071,7 +3373,7 @@
 	    break;
 	}
     }
-
+    
     return status;                         /* return the device name string */
 }
 
@@ -3083,16 +3385,13 @@
 {
     c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
     int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
-
+    
     if (lp->chipset == DC21040) {
 	strcpy(name, "DE434/5");
-    } else {
+	return status;
+    } else {                           /* Search for a DEC name in the SROM */
 	int i = *((char *)&lp->srom + 19) * 3;
-	if (lp->chipset == DC21041) {
-	    strncpy(name, (char *)&lp->srom + 26 + i, 8);
-	} else if (lp->chipset == DC21140) {
-	    strncpy(name, (char *)&lp->srom + 26 + i, 8);
-	}
+	strncpy(name, (char *)&lp->srom + 26 + i, 8);
     }
     name[8] = '\0';
     for (i=0; i<siglen; i++) {
@@ -3104,11 +3403,16 @@
 	} else {                        /* Use chip name to avoid confusion */
 	    strcpy(name, (((lp->chipset == DC21040) ? "DC21040" :
 			   ((lp->chipset == DC21041) ? "DC21041" :
-			    ((lp->chipset == DC21140) ? "DC21140" : "UNKNOWN"
-			     )))));
+			    ((lp->chipset == DC21140) ? "DC21140" :
+			     ((lp->chipset == DC21142) ? "DC21142" :
+			      ((lp->chipset == DC21143) ? "DC21143" : "UNKNOWN"
+			     )))))));
+	}
+	if (lp->chipset != DC21041) {
+	    useSROM = TRUE;             /* card is not recognisably DEC */
 	}
     }
-
+    
     return status;
 }
 
@@ -3121,7 +3425,7 @@
 {
     int i;
     struct bus_type *lp = &bus;
-
+    
     if (lp->chipset == DC21040) {
 	outl(0, aprom_addr);           /* Reset Ethernet Address ROM Pointer */
     } else {                           /* Read new srom */
@@ -3131,10 +3435,16 @@
 	}
 	de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
     }
-
+    
     return;
 }
 
+/*
+** For the bad status case and no SROM, then add one to the previous
+** address. However, need to add one backwards in case we have 0xff
+** as one or more of the bytes. Only the last 3 bytes should be checked
+** as the first three are invariant - assigned to an organisation.
+*/
 static int
 get_hw_addr(struct device *dev)
 {
@@ -3147,7 +3457,7 @@
     for (i=0,k=0,j=0;j<3;j++) {
 	k <<= 1;
 	if (k > 0xffff) k-=0xffff;
-
+	
 	if (lp->bus == PCI) {
 	    if (lp->chipset == DC21040) {
 		while ((tmp = inl(DE4X5_APROM)) < 0);
@@ -3169,11 +3479,11 @@
 	    k += (u_short) ((tmp = inb(EISA_APROM)) << 8);
 	    dev->dev_addr[i++] = (u_char) tmp;
 	}
-
+	
 	if (k > 0xffff) k-=0xffff;
     }
     if (k == 0xffff) k=0;
-
+    
     if (lp->bus == PCI) {
 	if (lp->chipset == DC21040) {
 	    while ((tmp = inl(DE4X5_APROM)) < 0);
@@ -3188,6 +3498,12 @@
 	if ((k != chksum) && (dec_only)) status = -1;
     }
 
+    /* If possible, try to fix a broken card - SMC only so far */
+    srom_repair(dev, broken);
+
+    /* Test for a bad enet address */
+    status = test_bad_enet(dev, status);
+
     return status;
 }
 
@@ -3227,6 +3543,55 @@
     return ret;
 }
 
+static void
+srom_repair(struct device *dev, int card)
+{
+    struct bus_type *lp = &bus;
+
+    switch(card) {
+      case SMC:
+	memset((char *)&bus.srom, 0, sizeof(struct de4x5_srom));
+	memcpy(lp->srom.ieee_addr, (char *)dev->dev_addr, ETH_ALEN);
+	memcpy(lp->srom.info, (char *)&srom_repair_info[SMC-1], 100);
+	useSROM = TRUE;
+	break;
+    }
+
+    return;
+}
+
+static int
+test_bad_enet(struct device *dev, int status)
+{
+    struct bus_type *lp = &bus;
+    int i, tmp;
+
+    for (tmp=0,i=0; i<ETH_ALEN; i++) tmp += (u_char)dev->dev_addr[i];
+    if ((tmp == 0) || (tmp == 0x5fa)) {
+	if ((lp->chipset == last.chipset) && 
+	    (lp->bus_num == last.bus) && (lp->bus_num > 0)) {
+	    for (i=0; i<ETH_ALEN; i++) dev->dev_addr[i] = last.addr[i];
+	    for (i=ETH_ALEN-1; i>2; --i) {
+		dev->dev_addr[i] += 1;
+		if (dev->dev_addr[i] != 0) break;
+	    }
+	    for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
+	    if (((*((int *)dev->dev_addr) & 0x00ffffff) == 0x95c000) &&
+		(lp->chipset == DC21040)) {
+		dev->irq = last.irq;
+	    }
+	    status = 0;
+	}
+    } else if (!status) {
+	last.chipset = lp->chipset;
+	last.bus = lp->bus_num;
+	last.irq = dev->irq;
+	for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
+    }
+
+    return status;
+}
+
 /*
 ** SROM Read
 */
@@ -3234,11 +3599,11 @@
 srom_rd(u_long addr, u_char offset)
 {
     sendto_srom(SROM_RD | SROM_SR, addr);
-
+    
     srom_latch(SROM_RD | SROM_SR | DT_CS, addr);
     srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr);
     srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset);
-
+    
     return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
 }
 
@@ -3248,7 +3613,7 @@
     sendto_srom(command, addr);
     sendto_srom(command | DT_CLK, addr);
     sendto_srom(command, addr);
-
+    
     return;
 }
 
@@ -3258,7 +3623,7 @@
     srom_latch(command, addr);
     srom_latch(command, addr);
     srom_latch((command & 0x0000ff00) | DT_CS, addr);
-
+    
     return;
 }
 
@@ -3267,18 +3632,18 @@
 {
     int i;
     char a;
-
+    
     a = (char)(offset << 2);
     for (i=0; i<6; i++, a <<= 1) {
 	srom_latch(command | ((a < 0) ? DT_IN : 0), addr);
     }
     de4x5_us_delay(1);
-
+    
     i = (getfrom_srom(addr) >> 3) & 0x01;
     if (i != 0) {
 	printk("Bad SROM address phase.....\n");
     }
-
+    
     return;
 }
 
@@ -3288,17 +3653,17 @@
     int i;
     short word = 0;
     s32 tmp;
-
+    
     for (i=0; i<16; i++) {
 	sendto_srom(command  | DT_CLK, addr);
 	tmp = getfrom_srom(addr);
 	sendto_srom(command, addr);
-
+	
 	word = (word << 1) | ((tmp >> 3) & 0x01);
     }
-
+    
     sendto_srom(command & 0x0000ff00, addr);
-
+    
     return word;
 }
 
@@ -3307,13 +3672,13 @@
 srom_busy(u_int command, u_long addr)
 {
    sendto_srom((command & 0x0000ff00) | DT_CS, addr);
-
+   
    while (!((getfrom_srom(addr) >> 3) & 0x01)) {
        de4x5_ms_delay(1);
    }
-
+   
    sendto_srom(command & 0x0000ff00, addr);
-
+   
    return;
 }
 */
@@ -3323,7 +3688,7 @@
 {
     outl(command, addr);
     udelay(1);
-
+    
     return;
 }
 
@@ -3331,13 +3696,406 @@
 getfrom_srom(u_long addr)
 {
     s32 tmp;
-
+    
     tmp = inl(addr);
     udelay(1);
-
+    
     return tmp;
 }
 
+static int
+srom_infoleaf_info(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i, count;
+    u_char *p;
+
+    /* Find the infoleaf decoder function that matches this chipset */
+    for (i=0; i<INFOLEAF_SIZE; i++) {
+	if (lp->chipset == infoleaf_array[i].chipset) break;
+    }
+    if (i == INFOLEAF_SIZE) {
+	lp->useSROM = FALSE;
+	printk("%s: Cannot find correct chipset for SROM decoding!\n", 
+	                                                          dev->name);
+	return -ENXIO;
+    }
+
+    lp->infoleaf_fn = infoleaf_array[i].fn;
+
+    /* Find the information offset that this function should use */
+    count = *((u_char *)&lp->srom + 19);
+    p  = (u_char *)&lp->srom + 26;
+
+    if (count > 1) {
+	for (i=count; i; --i, p+=3) {
+	    if (lp->device == *p) break;
+	}
+	if (i == 0) {
+	    lp->useSROM = FALSE;
+	    printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n", 
+	                                               dev->name, lp->device);
+	    return -ENXIO;
+	}
+    }
+
+    lp->infoleaf_offset = (u_short)*((u_short *)(p+1));
+
+    return 0;
+}
+
+/*
+** This routine loads any type 1 or 3 MII info into the mii device
+** struct and executes any type 5 code to reset PHY devices for this
+** controller.
+** The info for the MII devices will be valid since the index used
+** will follow the discovery process from MII address 1-31 then 0.
+*/
+static void
+srom_init(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    u_char count;
+
+    if (lp->chipset == DC21140) {
+	p+=2;
+	lp->cache.gepc = (*p++ | GEP_CTRL);
+	outl(lp->cache.gepc, DE4X5_GEP);
+    } else if (lp->chipset == DC21142) {
+	p+=2;
+    } else if (lp->chipset == DC21143) {
+	p+=2;
+    }
+
+    /* Block count */
+    count = *p++;
+
+    /* Jump the infoblocks to find types */
+    for (;count; --count) {
+	if (*p < 128) {
+	    p += COMPACT_LEN;
+	} else if (*(p+1) == 5) {
+	    type5_infoblock(dev, 1, p);
+	    p += ((*p & BLOCK_LEN) + 1);
+	} else if (*(p+1) == 3) {
+	    type3_infoblock(dev, 1, p);
+	    p += ((*p & BLOCK_LEN) + 1);
+	} else if (*(p+1) == 1) {
+	    type1_infoblock(dev, 1, p);
+	    p += ((*p & BLOCK_LEN) + 1);
+	} else {
+	    p += ((*p & BLOCK_LEN) + 1);
+	}
+    }
+
+    return;
+}
+
+static void
+srom_exec(struct device *dev, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char count = *p++;
+
+    while (count--) {
+	if (lp->chipset == DC21140) {
+	    outl(*p++, DE4X5_GEP);
+	}
+	udelay(2000);                       /* 2ms per action */
+    }
+
+    return;
+}
+
+/*
+** Basically this function is a NOP since it will never be called,
+** unless I implement the DC21041 SROM functions. There's no need
+** since the existing code will be satisfactory for all boards.
+*/
+static int 
+dc21041_infoleaf(struct device *dev)
+{
+    return DE4X5_AUTOSENSE_MS;
+}
+
+static int 
+dc21140_infoleaf(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char count = 0;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
+    /* Read the connection type */
+    p+=2;
+
+    /* GEP control */
+    lp->cache.gepc = (*p++ | GEP_CTRL);
+
+    /* Block count */
+    count = *p++;
+
+    /* Recursively figure out the info blocks */
+    if (*p < 128) {
+	next_tick = dc_infoblock[COMPACT](dev, count, p);
+    } else {
+	next_tick = dc_infoblock[*(p+1)](dev, count, p);
+    }
+
+    if (lp->tcount == count) {
+	lp->media = NC;
+        if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
+	lp->media = INIT;
+	lp->tcount = 0;
+	lp->tx_enable = FALSE;
+    }
+
+    return next_tick & ~TIMER_CB;
+}
+
+static int 
+dc21142_infoleaf(struct device *dev)
+{
+printk("dc21142_infoleaf()\n");
+    return DE4X5_AUTOSENSE_MS;
+}
+
+static int 
+dc21143_infoleaf(struct device *dev)
+{
+printk("dc21143_infoleaf()\n");
+    return DE4X5_AUTOSENSE_MS;
+}
+
+/*
+** The compact infoblock is only designed for DC21140[A] chips, so
+** we'll reuse the dc21140m_autoconf function. Non MII media only.
+*/
+static int 
+compact_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char flags, csr6;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+COMPACT_LEN) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+COMPACT_LEN);
+	} else {
+	    return dc_infoblock[*(p+COMPACT_LEN+1)](dev, count, p+COMPACT_LEN);
+	}
+    }
+
+    if (lp->media == INIT) {
+        outl(lp->cache.gepc, DE4X5_GEP);
+	lp->infoblock_media = (*p++) & COMPACT_MC;
+	lp->cache.gep = *p++;
+	csr6 = *p++;
+	flags = *p++;
+
+	lp->asBitValid = (flags & 0x80) ? 0 : -1;
+	lp->defMedium = (flags & 0x40) ? -1 : 0;
+	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+	lp->infoblock_csr6 = (csr6 & 0x71) << 18;
+	lp->useMII = FALSE;
+
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc21140m_autoconf(dev);
+}
+
+/*
+** This block describes non MII media for the DC21140[A] only.
+ */
+static int 
+type0_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    if (lp->media == INIT) {
+        outl(lp->cache.gepc, DE4X5_GEP);
+	p+=2;
+	lp->infoblock_media = (*p++) & BLOCK0_MC;
+	lp->cache.gep = *p++;
+	csr6 = *p++;
+	flags = *p++;
+
+	lp->asBitValid = (flags & 0x80) ? 0 : -1;
+	lp->defMedium = (flags & 0x40) ? -1 : 0;
+	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+	lp->infoblock_csr6 = (csr6 & 0x71) << 18;
+	lp->useMII = FALSE;
+
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc21140m_autoconf(dev);
+}
+
+/* These functions are under construction! */
+
+static int 
+type1_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char len = (*p & BLOCK_LEN)+1;
+    int ana;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    if (lp->state == INITIALISED) {
+	lp->ibn = 1; p += 2;
+	lp->active = *p++;
+	lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
+	lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
+	lp->phy[lp->active].mc  = *(u_short *)p; p += 2;
+	lp->phy[lp->active].ana = *(u_short *)p; p += 2;
+	lp->phy[lp->active].fdx = *(u_short *)p; p += 2;
+	lp->phy[lp->active].ttm = *(u_short *)p;
+	return 0;
+    } else if (lp->media == INIT) {
+	if (lp->phy[lp->active].gep) {
+	    srom_exec(dev, lp->phy[lp->active].gep);
+	}
+        ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
+	mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+	lp->infoblock_csr6 = OMR_PS | OMR_HBD;
+	lp->useMII = TRUE;
+	lp->infoblock_media = ANS;
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc21140m_autoconf(dev);
+}
+
+static int 
+type2_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    return DE4X5_AUTOSENSE_MS;
+}
+
+static int 
+type3_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    if (lp->state == INITIALISED) {
+	lp->ibn = 3; p += 2;
+        lp->active = *p++;
+	lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
+	lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
+	lp->phy[lp->active].mc  = *(u_short *)p; p += 2;
+	lp->phy[lp->active].ana = *(u_short *)p; p += 2;
+	lp->phy[lp->active].fdx = *(u_short *)p; p += 2;
+	lp->phy[lp->active].ttm = *(u_short *)p;
+	return 0;
+    } else if (lp->media == INIT) {
+	p+=2;
+	lp->infoblock_media = (*p++) & BLOCK0_MC;
+	lp->cache.gep = *p++;
+	csr6 = *p++;
+	flags = *p++;
+
+	lp->asBitValid = (flags & 0x80) ? 0 : -1;
+	lp->defMedium = (flags & 0x40) ? -1 : 0;
+	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+	lp->infoblock_csr6 = (csr6 & 0x71) << 18;
+	lp->useMII = TRUE;
+
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc21140m_autoconf(dev);
+}
+
+static int 
+type4_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    return DE4X5_AUTOSENSE_MS;
+}
+
+/*
+** This block type provides information for resetting external devices
+** (chips) through the General Purpose Register.
+*/
+static int 
+type5_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char i, j, len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    /* Must be initializing to run this code */
+    if ((lp->state == INITIALISED) || (lp->media == INIT)) {
+	p+=2;
+        lp->rst = p;
+	i = *p++;
+	for (j=0;i;--i) {
+	    if (lp->chipset == DC21140) {
+		if (!j) {
+		    outl(*p++ | GEP_CTRL, DE4X5_GEP);
+		    j++;
+		}
+		outl(*p++, DE4X5_GEP);
+	    } else if (lp->chipset == DC21142) {
+	    } else if (lp->chipset == DC21143) {
+	    }
+	}
+	    
+    }
+
+    return DE4X5_AUTOSENSE_MS;
+}
+
 /*
 ** MII Read/Write
 */
@@ -3351,7 +4109,7 @@
     mii_address(phyaddr, ioaddr);          /* PHY address to be accessed     */
     mii_address(phyreg, ioaddr);           /* PHY Register to read           */
     mii_ta(MII_STRD, ioaddr);              /* Turn around time - 2 MDC       */
-
+    
     return mii_rdata(ioaddr);              /* Read data                      */
 }
 
@@ -3366,7 +4124,7 @@
     mii_ta(MII_STWR, ioaddr);              /* Turn around time - 2 MDC       */
     data = mii_swap(data, 16);             /* Swap data bit ordering         */
     mii_wdata(data, 16, ioaddr);           /* Write data                     */
-
+    
     return;
 }
 
@@ -3375,12 +4133,12 @@
 {
     int i;
     s32 tmp = 0;
-
+    
     for (i=0; i<16; i++) {
 	tmp <<= 1;
 	tmp |= getfrom_mii(MII_MRD | MII_RD, ioaddr);
     }
-
+    
     return tmp;
 }
 
@@ -3388,12 +4146,12 @@
 mii_wdata(int data, int len, u_long ioaddr)
 {
     int i;
-
+    
     for (i=0; i<len; i++) {
 	sendto_mii(MII_MWR | MII_WR, data, ioaddr);
 	data >>= 1;
     }
-
+    
     return;
 }
 
@@ -3401,13 +4159,13 @@
 mii_address(u_char addr, u_long ioaddr)
 {
     int i;
-
+    
     addr = mii_swap(addr, 5);
     for (i=0; i<5; i++) {
 	sendto_mii(MII_MWR | MII_WR, addr, ioaddr);
 	addr >>= 1;
     }
-
+    
     return;
 }
 
@@ -3415,12 +4173,12 @@
 mii_ta(u_long rw, u_long ioaddr)
 {
     if (rw == MII_STWR) {
-	sendto_mii(MII_MWR | MII_WR, 1, ioaddr);
-	sendto_mii(MII_MWR | MII_WR, 0, ioaddr);
+	sendto_mii(MII_MWR | MII_WR, 1, ioaddr);  
+	sendto_mii(MII_MWR | MII_WR, 0, ioaddr);  
     } else {
 	getfrom_mii(MII_MRD | MII_RD, ioaddr);        /* Tri-state MDIO */
     }
-
+    
     return;
 }
 
@@ -3428,13 +4186,13 @@
 mii_swap(int data, int len)
 {
     int i, tmp = 0;
-
+    
     for (i=0; i<len; i++) {
 	tmp <<= 1;
 	tmp |= (data & 1);
 	data >>= 1;
     }
-
+    
     return tmp;
 }
 
@@ -3442,13 +4200,13 @@
 sendto_mii(u32 command, int data, u_long ioaddr)
 {
     u32 j;
-
+    
     j = (data & 1) << 17;
     outl(command | j, ioaddr);
     udelay(1);
     outl(command | MII_MDC | j, ioaddr);
     udelay(1);
-
+    
     return;
 }
 
@@ -3459,7 +4217,7 @@
     udelay(1);
     outl(command | MII_MDC, ioaddr);
     udelay(1);
-
+    
     return ((inl(ioaddr) >> 19) & 1);
 }
 
@@ -3511,24 +4269,26 @@
     return r2;                                  /* (I did it) My way */
 }
 
+/*
+** The SROM spec forces us to search addresses [1-31 0]. Bummer.
+*/
 static int
 mii_get_phy(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
-    int i, j, k, limit=sizeof(phy_info)/sizeof(struct phy_table);
+    int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table);
     int id;
-
-    /* Issue a hard PHY reset - Broadcom is screwed up otherwise */
-    outl(GEP_HRST, DE4X5_GEP);
-    udelay(1000);                                  /* Assert for 1ms */
-    outl(0x00, DE4X5_GEP);
-    udelay(2000);                                  /* Wait for 2ms */
+    
+    lp->active = 0;
+    lp->useMII = TRUE;
 
     /* Search the MII address space for possible PHY devices */
-    lp->active = 0;
-    for (lp->mii_cnt=0, i=1; i<DE4X5_MAX_MII; i++) {
-	id = mii_get_oui(i, DE4X5_MII);
+    for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(++i)%DE4X5_MAX_MII) {
+	lp->phy[lp->active].addr = i;
+	if (i==0) n++;                             /* Count cycles */
+	while (de4x5_reset_phy(dev)<0) udelay(100);/* Wait for reset */
+	id = mii_get_oui(i, DE4X5_MII); 
 	if ((id == 0) || (id == -1)) continue;     /* Valid ID? */
 	for (j=0; j<limit; j++) {                  /* Search PHY table */
 	    if (id != phy_info[j].id) continue;    /* ID match? */
@@ -3538,21 +4298,23 @@
 		       (char *)&phy_info[j], sizeof(struct phy_table));
 		lp->phy[k].addr = i;
 		lp->mii_cnt++;
+		lp->active++;
 	    } else {
 		i = DE4X5_MAX_MII;                 /* Stop the search */
 		j = limit;
 	    }
 	}
     }
-    if (lp->phy[lp->active].id) {                  /* Reset the PHY devices */
+    lp->active = 0;
+    if (lp->phy[0].id) {                           /* Reset the PHY devices */
 	for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/
 	    mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII);
 	    while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST);
-
+	    
 	    de4x5_dbg_mii(dev, k);
 	}
     }
-
+    
     return lp->mii_cnt;
 }
 
@@ -3562,12 +4324,12 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int i;
     char *pa = lp->setup_frame;
-
+    
     /* Initialise the setup frame */
     if (mode == ALL) {
 	memset(lp->setup_frame, 0, SETUP_FRAME_LEN);
     }
-
+    
     if (lp->setup_f == HASH_PERF) {
 	for (pa=lp->setup_frame+IMPERF_PA_OFFSET, i=0; i<ETH_ALEN; i++) {
 	    *(pa + i) = dev->dev_addr[i];                 /* Host address */
@@ -3584,7 +4346,7 @@
 	    if (i & 0x01) pa += 4;
 	}
     }
-
+    
     return pa;                     /* Points to the next entry */
 }
 
@@ -3592,7 +4354,7 @@
 enable_ast(struct device *dev, u32 time_out)
 {
     timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out);
-
+    
     return;
 }
 
@@ -3600,60 +4362,33 @@
 disable_ast(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
+    
     del_timer(&lp->timer);
-
+    
     return;
 }
 
 static long
-de4x5_switch_to_mii(struct device *dev)
+de4x5_switch_mac_port(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
-    long omr;
+    s32 omr;
 
     /* Assert the OMR_PS bit in CSR6 */
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
-    omr |= (OMR_PS | OMR_HBD);
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR |
+			                                             OMR_FDX));
+    omr |= lp->infoblock_csr6;
+    if (omr & OMR_PS) omr |= OMR_HBD;
     outl(omr, DE4X5_OMR);
-
+    
     /* Soft Reset */
     RESET_DE4X5;
-
+    
     /* Restore the GEP */
     if (lp->chipset == DC21140) {
-	outl(GEP_INIT, DE4X5_GEP);
-	outl(0, DE4X5_GEP);
-    }
-
-    /* Restore CSR6 */
-    outl(omr, DE4X5_OMR);
-
-    /* Reset CSR8 */
-    inl(DE4X5_MFC);
-
-    return omr;
-}
-
-static long
-de4x5_switch_to_srl(struct device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int iobase = dev->base_addr;
-    long omr;
-
-    /* Deassert the OMR_PS bit in CSR6 */
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
-    outl(omr, DE4X5_OMR);
-
-    /* Soft Reset */
-    RESET_DE4X5;
-
-    /* Restore the GEP */
-    if (lp->chipset == DC21140) {
-	outl(GEP_INIT, DE4X5_GEP);
-	outl(0, DE4X5_GEP);
+	outl(lp->cache.gepc, DE4X5_GEP);
+	outl(lp->cache.gep, DE4X5_GEP);
     }
 
     /* Restore CSR6 */
@@ -3670,19 +4405,67 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int dt;
-
+    
     /* First, cancel any pending timer events */
     del_timer(&lp->timer);
-
+    
     /* Convert msec to ticks */
     dt = (msec * HZ) / 1000;
     if (dt==0) dt=1;
-
+    
     /* Set up timer */
     lp->timer.expires = jiffies + dt;
     lp->timer.function = fn;
     lp->timer.data = data;
     add_timer(&lp->timer);
+    
+    return;
+}
+
+static void
+yawn(struct device *dev, int state)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int iobase = dev->base_addr;
+
+    if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) return;
+
+    if(lp->bus == EISA) {
+	switch(state) {
+	  case WAKEUP:
+	    outb(WAKEUP, PCI_CFPM);
+	    de4x5_ms_delay(10);
+	    break;
+
+	  case SNOOZE:
+	    outb(SNOOZE, PCI_CFPM);
+	    break;
+
+	  case SLEEP:
+	    outl(0, DE4X5_SICR);
+	    outb(SLEEP, PCI_CFPM);
+	    break;
+	}
+    } else {
+	switch(state) {
+	  case WAKEUP:
+	    pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+				      PCI_CFDA_PSM, WAKEUP);
+	    de4x5_ms_delay(10);
+	    break;
+
+	  case SNOOZE:
+	    pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+				      PCI_CFDA_PSM, SNOOZE);
+	    break;
+
+	  case SLEEP:
+	    outl(0, DE4X5_SICR);
+	    pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+				      PCI_CFDA_PSM, SLEEP);
+	    break;
+	}
+    }
 
     return;
 }
@@ -3692,8 +4475,8 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int i;
-
-    if (de4x5_debug > 1) {
+    
+    if (de4x5_debug & DEBUG_OPEN) {
 	printk("%s: de4x5 opening with irq %d\n",dev->name,dev->irq);
 	printk("\tphysical address: ");
 	for (i=0;i<6;i++) {
@@ -3730,11 +4513,11 @@
 	    }
 	}
 	printk("...0x%8.8x\n", le32_to_cpu(lp->tx_ring[i].buf));
-	printk("Ring size: \nRX: %d\nTX: %d\n",
-	       (short)lp->rxRingSize,
-	       (short)lp->txRingSize);
+	printk("Ring size: \nRX: %d\nTX: %d\n", 
+	       (short)lp->rxRingSize, 
+	       (short)lp->txRingSize); 
     }
-
+    
     return;
 }
 
@@ -3743,8 +4526,8 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
-
-    if (de4x5_debug > 2) {
+    
+    if (de4x5_debug & DEBUG_MII) {
 	printk("\nMII CR:  %x\n",mii_rd(MII_CR,lp->phy[k].addr,DE4X5_MII));
 	printk("MII SR:  %x\n",mii_rd(MII_SR,lp->phy[k].addr,DE4X5_MII));
 	printk("MII ID0: %x\n",mii_rd(MII_ID0,lp->phy[k].addr,DE4X5_MII));
@@ -3761,7 +4544,7 @@
 	    printk("MII 20:  %x\n",mii_rd(0x14,lp->phy[k].addr,DE4X5_MII));
 	}
     }
-
+    
     return;
 }
 
@@ -3769,18 +4552,18 @@
 de4x5_dbg_media(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
+    
     if (lp->media != lp->c_media) {
-	if (de4x5_debug > 0) {
+	if (de4x5_debug & DEBUG_MEDIA) {
 	    if (lp->chipset != DC21140) {
 		printk("%s: media is %s\n", dev->name,
 		       (lp->media == NC  ? "unconnected!" :
 			(lp->media == TP  ? "TP." :
 			 (lp->media == ANS ? "TP/Nway." :
-			  (lp->media == BNC ? "BNC." :
-			   (lp->media == AUI ? "AUI." :
-			    (lp->media == BNC_AUI ? "BNC/AUI." :
-			     (lp->media == EXT_SIA ? "EXT SIA." :
+			  (lp->media == BNC ? "BNC." : 
+			   (lp->media == AUI ? "AUI." : 
+			    (lp->media == BNC_AUI ? "BNC/AUI." : 
+			     (lp->media == EXT_SIA ? "EXT SIA." : 
 			      "???."
 			      ))))))));
 	    } else {
@@ -3794,7 +4577,7 @@
 	}
 	lp->c_media = lp->media;
     }
-
+    
     return;
 }
 
@@ -3803,10 +4586,12 @@
 {
     int i;
 
-    if (de4x5_debug > 1) {
-	printk("Sub-system Vendor ID: %04x\n", (u_short)*(p->sub_vendor_id));
-	printk("Sub-system ID:        %04x\n", (u_short)*(p->sub_system_id));
+    if (de4x5_debug & DEBUG_SROM) {
+	printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id));
+	printk("Sub-system ID:        %04x\n", *((u_short *)p->sub_system_id));
 	printk("ID Block CRC:         %02x\n", (u_char)(p->id_block_crc));
+	printk("SROM version:         %02x\n", (u_char)(p->version));
+	printk("# controllers:         %02x\n", (u_char)(p->num_controllers));
 
 	printk("Hardware Address:     ");
 	for (i=0;i<ETH_ALEN-1;i++) {
@@ -3827,7 +4612,7 @@
 {
     int i, j;
 
-    if (de4x5_debug > 2) {
+    if (de4x5_debug & DEBUG_RX) {
 	printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
 	       (u_char)skb->data[0],
 	       (u_char)skb->data[1],
@@ -3844,7 +4629,7 @@
 	       (u_char)skb->data[12],
 	       (u_char)skb->data[13],
 	       len);
-	if (de4x5_debug > 3) {
+	if (de4x5_debug & DEBUG_RX) {
 	    for (j=0; len>0;j+=16, len-=16) {
 		printk("    %03x: ",j);
 		for (i=0; i<16 && i<len; i++) {
@@ -3875,7 +4660,7 @@
 	u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
 	u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
     } tmp;
-
+    
     switch(ioc->cmd) {
       case DE4X5_GET_HWADDR:           /* Get the hardware address */
 	ioc->len = ETH_ALEN;
@@ -3886,7 +4671,7 @@
 	    tmp.addr[i] = dev->dev_addr[i];
 	}
 	copy_to_user(ioc->data, tmp.addr, ioc->len);
-
+	
 	break;
       case DE4X5_SET_HWADDR:           /* Set the hardware address */
 	status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN);
@@ -3903,12 +4688,12 @@
 	build_setup_frame(dev, PHYS_ADDR_ONLY);
 	/* Set up the descriptor and give ownership to the card */
 	while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
-	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
+	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
 		                                        SETUP_FRAME_LEN, NULL);
 	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
 	outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
 	dev->tbusy = 0;                              /* Unlock the TX ring */
-
+	
 	break;
       case DE4X5_SET_PROM:             /* Set Promiscuous Mode */
 	if (suser()) {
@@ -3918,7 +4703,7 @@
 	} else {
 	    status = -EPERM;
 	}
-
+	
 	break;
       case DE4X5_CLR_PROM:             /* Clear Promiscuous Mode */
 	if (suser()) {
@@ -3928,19 +4713,19 @@
 	} else {
 	    status = -EPERM;
 	}
-
+	
 	break;
       case DE4X5_SAY_BOO:              /* Say "Boo!" to the kernel log file */
 	printk("%s: Boo!\n", dev->name);
-
+	
 	break;
       case DE4X5_GET_MCA:              /* Get the multicast address table */
 	ioc->len = (HASH_TABLE_LEN >> 3);
 	status = verify_area(VERIFY_WRITE, ioc->data, ioc->len);
 	if (!status) {
-	    copy_to_user(ioc->data, lp->setup_frame, ioc->len);
+	    copy_to_user(ioc->data, lp->setup_frame, ioc->len); 
 	}
-
+	
 	break;
       case DE4X5_SET_MCA:              /* Set a multicast address */
 	if (suser()) {
@@ -3956,7 +4741,7 @@
 	} else {
 	    status = -EPERM;
 	}
-
+	
 	break;
       case DE4X5_CLR_MCA:              /* Clear all multicast addresses */
 	if (suser()) {
@@ -3965,7 +4750,7 @@
 	} else {
 	    status = -EPERM;
 	}
-
+	
 	break;
       case DE4X5_MCA_EN:               /* Enable pass all multicast addressing */
 	if (suser()) {
@@ -3975,18 +4760,18 @@
 	} else {
 	    status = -EPERM;
 	}
-
+	
 	break;
       case DE4X5_GET_STATS:            /* Get the driver statistics */
 	ioc->len = sizeof(lp->pktStats);
 	status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
 	if (status)
 	  break;
-
+	
 	cli();
-	copy_to_user(ioc->data, &lp->pktStats, ioc->len);
+	copy_to_user(ioc->data, &lp->pktStats, ioc->len); 
 	sti();
-
+	
 	break;
       case DE4X5_CLR_STATS:            /* Zero out the driver statistics */
 	if (suser()) {
@@ -3996,14 +4781,14 @@
 	} else {
 	    status = -EPERM;
 	}
-
+	
 	break;
       case DE4X5_GET_OMR:              /* Get the OMR Register contents */
 	tmp.addr[0] = inl(DE4X5_OMR);
 	if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) {
 	    copy_to_user(ioc->data, tmp.addr, 1);
 	}
-
+	
 	break;
       case DE4X5_SET_OMR:              /* Set the OMR Register contents */
 	if (suser()) {
@@ -4014,7 +4799,7 @@
 	} else {
 	    status = -EPERM;
 	}
-
+	
 	break;
       case DE4X5_GET_REG:              /* Get the DE4X5 Registers */
 	j = 0;
@@ -4031,9 +4816,9 @@
 	    copy_to_user(ioc->data, tmp.addr, ioc->len);
 	}
 	break;
-
+	
 #define DE4X5_DUMP              0x0f /* Dump the DE4X5 Status */
-
+	
       case DE4X5_DUMP:
 	j = 0;
 	tmp.addr[j++] = dev->irq;
@@ -4043,7 +4828,7 @@
 	tmp.addr[j++] = lp->rxRingSize;
 	tmp.lval[j>>2] = (long)lp->rx_ring; j+=4;
 	tmp.lval[j>>2] = (long)lp->tx_ring; j+=4;
-
+	
 	for (i=0;i<lp->rxRingSize-1;i++){
 	    if (i < 3) {
 		tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
@@ -4056,7 +4841,7 @@
 	    }
 	}
 	tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
-
+	
 	for (i=0;i<lp->rxRingSize-1;i++){
 	    if (i < 3) {
 		tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4;
@@ -4069,14 +4854,14 @@
 	    }
 	}
 	tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4;
-
+	
 	for (i=0;i<lp->rxRingSize;i++){
 	    tmp.lval[j>>2] = le32_to_cpu(lp->rx_ring[i].status); j+=4;
 	}
 	for (i=0;i<lp->txRingSize;i++){
 	    tmp.lval[j>>2] = le32_to_cpu(lp->tx_ring[i].status); j+=4;
 	}
-
+	
 	tmp.lval[j>>2] = inl(DE4X5_BMR);  j+=4;
 	tmp.lval[j>>2] = inl(DE4X5_TPD);  j+=4;
 	tmp.lval[j>>2] = inl(DE4X5_RPD);  j+=4;
@@ -4085,18 +4870,18 @@
 	tmp.lval[j>>2] = inl(DE4X5_STS);  j+=4;
 	tmp.lval[j>>2] = inl(DE4X5_OMR);  j+=4;
 	tmp.lval[j>>2] = inl(DE4X5_IMR);  j+=4;
-	tmp.lval[j>>2] = lp->chipset; j+=4;
+	tmp.lval[j>>2] = lp->chipset; j+=4; 
 	if (lp->chipset == DC21140) {
 	    tmp.lval[j>>2] = inl(DE4X5_GEP);  j+=4;
 	} else {
 	    tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4;
 	    tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
 	    tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4;
-	    tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4;
+	    tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4; 
 	}
-	tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4;
-	if (lp->phy[lp->active].id) {
-	    tmp.lval[j>>2] = lp->active; j+=4;
+	tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4; 
+	if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+	    tmp.lval[j>>2] = lp->active; j+=4; 
 	    tmp.lval[j>>2]=mii_rd(MII_CR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
 	    tmp.lval[j>>2]=mii_rd(MII_SR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
 	    tmp.lval[j>>2]=mii_rd(MII_ID0,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
@@ -4113,20 +4898,20 @@
 		tmp.lval[j>>2]=mii_rd(0x14,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
 	    }
 	}
-
+	
 	tmp.addr[j++] = lp->txRingSize;
 	tmp.addr[j++] = dev->tbusy;
-
+	
 	ioc->len = j;
 	if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
 	    copy_to_user(ioc->data, tmp.addr, ioc->len);
 	}
-
+	
 	break;
       default:
 	status = -EOPNOTSUPP;
     }
-
+    
     return status;
 }
 
@@ -4135,81 +4920,33 @@
 ** Note now that module autoprobing is allowed under EISA and PCI. The
 ** IRQ lines will not be auto-detected; instead I'll rely on the BIOSes
 ** to "do the right thing".
-**
-** The module autoprobe will only load one instance of the driver and
-** hardware.
 */
-static char devicename[9] = { 0, };
-static struct device thisDE4X5 = {
-    devicename,   /* device name inserted by /linux/drivers/net/net_init.c  */
-    0, 0, 0, 0,
-    0, 0,         /* I/O address, IRQ                                       */
-    0, 0, 0, NULL, de4x5_probe };
-
-static int io=0x0; /* EDIT THESE LINES FOR YOUR CONFIGURATION              */
-MODULE_PARM(io, "i");
+#define LP(a) ((struct de4x5_private *)(a))
+static struct device *mdev = NULL;
+static int io=0x0;/* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED        */
 
 int
 init_module(void)
 {
-    struct device *p  = (struct device *)&thisDE4X5;
+    struct device *p;
 
-    thisDE4X5.base_addr = io;                   /* Now autoprobe the module */
-    thisDE4X5.irq = 0;
+    if ((mdev = insert_device(NULL, io, de4x5_probe)) == NULL) 
+      return -ENOMEM;
 
-    for (; p!=NULL; p=p->next) {
+    for (p = mdev; p != NULL; p = LP(p->priv)->next_module) {
 	if (register_netdev(p) != 0)
 	  return -EIO;
     }
-    io=0;
+
     return 0;
 }
 
 void
 cleanup_module(void)
 {
-    struct de4x5_private *lp = (struct de4x5_private *) thisDE4X5.priv;
-    struct device *p  = (struct device *)&thisDE4X5;
-    int keep_loaded = 0;
-
-    for (; p!=NULL; p=p->next) {
-	keep_loaded += (p->flags & IFF_UP);     /* Is an interface up?       */
-    }
-
-    if (keep_loaded) {
-	printk("de4x5: Cannot unload modules - %d interface%s%s still active.\n",
-	       keep_loaded, (keep_loaded>1 ? "s ": " "),
-	       (keep_loaded>1 ? "are": "is"));
-	return;
-    }
-
-    for (p=thisDE4X5.next; p!=NULL; p=p->next) {
-	if (p->priv) {                          /* Private area allocated?   */
-	    struct de4x5_private *lp = (struct de4x5_private *)p->priv;
-	    if (lp->cache.buf) {                /* MAC buffers allocated?    */
-		kfree(lp->cache.buf);           /* Free the MAC buffers      */
-	    }
-	    release_region(p->base_addr, (lp->bus == PCI ?
-					  DE4X5_PCI_TOTAL_SIZE :
-					  DE4X5_EISA_TOTAL_SIZE));
-	    kfree(lp->cache.priv);              /* Free the private area     */
-	}
-	unregister_netdev(p);
-	kfree(p);                               /* Free the device structure */
-    }
-
-    if (thisDE4X5.priv) {
-	if (lp->cache.buf) {                    /* Are MAC buffers allocated */
-            kfree(lp->cache.buf);
-	}
-	release_region(thisDE4X5.base_addr,
-		      (lp->bus == PCI ?
-		       DE4X5_PCI_TOTAL_SIZE :
-		       DE4X5_EISA_TOTAL_SIZE));
-	kfree(lp->cache.priv);
-	thisDE4X5.priv = NULL;
+    while (mdev != NULL) {
+	mdev = unlink_modules(mdev);
     }
-    unregister_netdev(&thisDE4X5);
 
     return;
 }
diff -u --recursive --new-file v2.1.24/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- v2.1.24/linux/drivers/net/de4x5.h	Tue Aug 20 08:45:26 1996
+++ linux/drivers/net/de4x5.h	Sun Feb  2 15:02:05 1997
@@ -62,6 +62,8 @@
 #define PCI_CBER     iobase+0x0030   /* PCI Expansion ROM Base Address Reg. */
 #define PCI_CFIT     iobase+0x003c   /* PCI Configuration Interrupt Register */
 #define PCI_CFDA     iobase+0x0040   /* PCI Driver Area Register */
+#define PCI_CFDD     iobase+0x0041   /* PCI Driver Dependent Area Register */
+#define PCI_CFPM     iobase+0x0043   /* PCI Power Management Area Register */
 
 /*
 ** EISA Configuration Register 0 bit definitions
@@ -95,16 +97,20 @@
 #define ER3_LSR       0x02           /* Local Software Reset */
 
 /*
-** PCI Configuration ID Register (PCI_CFID)
+** PCI Configuration ID Register (PCI_CFID). The Device IDs are left
+** shifted 8 bits to allow detection of DC21142 and DC21143 variants with
+** the configuration revision register step number.
 */
 #define CFID_DID    0xff00           /* Device ID */
 #define CFID_VID    0x00ff           /* Vendor ID */
-#define DC21040_DID 0x0002           /* Unique Device ID # */
+#define DC21040_DID 0x0200           /* Unique Device ID # */
 #define DC21040_VID 0x1011           /* DC21040 Manufacturer */
-#define DC21041_DID 0x0014           /* Unique Device ID # */
+#define DC21041_DID 0x1400           /* Unique Device ID # */
 #define DC21041_VID 0x1011           /* DC21041 Manufacturer */
-#define DC21140_DID 0x0009           /* Unique Device ID # */
+#define DC21140_DID 0x0900           /* Unique Device ID # */
 #define DC21140_VID 0x1011           /* DC21140 Manufacturer */
+#define DC2114x_DID 0x1900           /* Unique Device ID # */
+#define DC2114x_VID 0x1011           /* DC2114[23] Manufacturer */
 
 /*
 ** Chipset defines
@@ -112,10 +118,16 @@
 #define DC21040     DC21040_DID
 #define DC21041     DC21041_DID
 #define DC21140     DC21140_DID
+#define DC2114x     DC2114x_DID
+#define DC21142     (DC2114x_DID | 0x0010)
+#define DC21143     (DC2114x_DID | 0x0020)
 
 #define is_DC21040 ((vendor == DC21040_VID) && (device == DC21040_DID))
 #define is_DC21041 ((vendor == DC21041_VID) && (device == DC21041_DID))
 #define is_DC21140 ((vendor == DC21140_VID) && (device == DC21140_DID))
+#define is_DC2114x ((vendor == DC2114x_VID) && (device == DC2114x_DID))
+#define is_DC21142 ((vendor == DC2114x_VID) && (device == DC21142))
+#define is_DC21143 ((vendor == DC2114x_VID) && (device == DC21143))
 
 /*
 ** PCI Configuration Command/Status Register (PCI_CFCS)
@@ -164,9 +176,14 @@
 #define CBER_ROME   0x00000001       /* ROM Enable */
 
 /*
-** PCI Configuration Driver Area Register (PCI_CFDA)
+** PCI Configuration Power Management Area Register (PCI_CFPM)
 */
-#define CFDA_PSM    0x80000000       /* Power Saving Mode */
+#define SLEEP       0x80             /* Power Saving Sleep Mode */
+#define SNOOZE      0x40             /* Power Saving Snooze Mode */
+#define WAKEUP      0x00             /* Power Saving Wakeup */
+
+#define PCI_CFDA_DSU 0x41            /* 8 bit Configuration Space Address */
+#define PCI_CFDA_PSM 0x43            /* 8 bit Configuration Space Address */
 
 /*
 ** DC21040 Bus Mode Register (DE4X5_BMR)
@@ -298,7 +315,7 @@
 #define OMR_ST     0x00002000       /* Start/Stop Transmission Command */
 #define OMR_FC     0x00001000       /* Force Collision Mode */
 #define OMR_OM     0x00000c00       /* Operating Mode */
-#define OMR_FD     0x00000200       /* Full Duplex Mode */
+#define OMR_FDX    0x00000200       /* Full Duplex Mode */
 #define OMR_FKD    0x00000100       /* Flaky Oscillator Disable */
 #define OMR_PM     0x00000080       /* Pass All Multicast */
 #define OMR_PR     0x00000040       /* Promiscuous Mode */
@@ -478,6 +495,74 @@
 #define MEDIA_BNC      0x0001      /* BNC Media present */
 
 /*
+** SROM Definitions (Digital Semiconductor Format)
+*/
+#define SROM_SSVID     0x0000      /* Sub-system Vendor ID offset */
+#define SROM_SSID      0x0002      /* Sub-system ID offset */
+#define SROM_CISPL     0x0004      /* CardBus CIS Pointer low offset */
+#define SROM_CISPH     0x0006      /* CardBus CIS Pointer high offset */
+#define SROM_IDCRC     0x0010      /* ID Block CRC offset*/
+#define SROM_RSVD2     0x0011      /* ID Reserved 2 offset */
+#define SROM_SFV       0x0012      /* SROM Format Version offset */
+#define SROM_CCNT      0x0013      /* Controller Count offset */
+#define SROM_HWADD     0x0014      /* Hardware Address offset */
+#define SROM_MRSVD     0x007c      /* Manufacturer Reserved offset*/
+#define SROM_CRC       0x007e      /* SROM CRC offset */
+
+/*
+** SROM Media Connection Definitions
+*/
+#define SROM_10BT      0x0000      /*  10BASE-T half duplex */
+#define SROM_10BTN     0x0100      /*  10BASE-T with Nway */
+#define SROM_10BTF     0x0204      /*  10BASE-T full duplex */
+#define SROM_10BTNLP   0x0400      /*  10BASE-T without Link Pass test */
+#define SROM_10B2      0x0001      /*  10BASE-2 (BNC) */
+#define SROM_10B5      0x0002      /*  10BASE-5 (AUI) */
+#define SROM_100BTH    0x0003      /*  100BASE-T half duplex */
+#define SROM_100BTF    0x0205      /*  100BASE-T full duplex */
+#define SROM_100BT4    0x0006      /*  100BASE-T4 */
+#define SROM_100BFX    0x0007      /*  100BASE-FX half duplex (Fiber) */
+#define SROM_M10BT     0x0009      /*  MII 10BASE-T half duplex */
+#define SROM_M10BTF    0x020a      /*  MII 10BASE-T full duplex */
+#define SROM_M100BT    0x000d      /*  MII 100BASE-T half duplex */
+#define SROM_M100BTF   0x020e      /*  MII 100BASE-T full duplex */
+#define SROM_M100BT4   0x000f      /*  MII 100BASE-T4 */
+#define SROM_M100BF    0x0010      /*  MII 100BASE-FX half duplex */
+#define SROM_M100BFF   0x0211      /*  MII 100BASE-FX full duplex */
+#define SROM_PDA       0x0800      /*  Powerup & Dynamic Autosense */
+#define SROM_PAO       0x8800      /*  Powerup Autosense Only */
+#define SROM_NSMI      0xffff      /*  No Selected Media Information */
+
+/*
+** SROM Media Definitions
+*/
+#define SROM_10BASET   0x0000      /*  10BASE-T half duplex */
+#define SROM_10BASE2   0x0001      /*  10BASE-2 (BNC) */
+#define SROM_10BASE5   0x0002      /*  10BASE-5 (AUI) */
+#define SROM_100BASET  0x0003      /*  100BASE-T half duplex */
+#define SROM_10BASETF  0x0004      /*  10BASE-T full duplex */
+#define SROM_100BASETF 0x0005      /*  100BASE-T full duplex */
+#define SROM_100BASET4 0x0006      /*  100BASE-T4 */
+#define SROM_100BASEF  0x0007      /*  100BASE-FX half duplex */
+#define SROM_100BASEFF 0x0008      /*  100BASE-FX full duplex */
+
+#define BLOCK_LEN      0x7f        /* Extended blocks length mask */
+
+/*
+** SROM Compact Format Block Masks
+*/
+#define COMPACT_FI      0x80       /* Format Indicator */
+#define COMPACT_LEN     0x04       /* Length */
+#define COMPACT_MC      0x3f       /* Media Code */
+
+/*
+** SROM Extended Format Block Type 0 Masks
+*/
+#define BLOCK0_FI      0x80        /* Format Indicator */
+#define BLOCK0_MCS     0x80        /* Media Code byte Sign */
+#define BLOCK0_MC      0x3f        /* Media Code */
+
+/*
 ** DC21040 Full Duplex Register (DE4X5_FDR)
 */
 #define FDR_FDACV  0x0000ffff      /* Full Duplex Auto Configuration Value */
@@ -501,7 +586,7 @@
 #define GEP_FLED 0x00000002        /* Force Activity LED on   (output) */
 #define GEP_MODE 0x00000001        /* 0: 10Mb/s,  1: 100Mb/s           */
 #define GEP_INIT 0x0000011f        /* Setup inputs (0) and outputs (1) */
-
+#define GEP_CTRL 0x00000100        /* GEP control bit                  */
 
 /*
 ** DC21040 SIA Status Register (DE4X5_SISR)
@@ -685,6 +770,20 @@
 #define TIMER_CB        0x80000000 /* Timer callback detection */
 
 /*
+** DE4X5 DEBUG Options
+*/
+#define DEBUG_NONE      0x0000     /* No DEBUG messages */
+#define DEBUG_VERSION   0x0001     /* Print version message */
+#define DEBUG_MEDIA     0x0002     /* Print media messages */
+#define DEBUG_TX        0x0004     /* Print TX (queue_pkt) messages */
+#define DEBUG_RX        0x0008     /* Print RX (de4x5_rx) messages */
+#define DEBUG_SROM      0x0010     /* Print SROM messages */
+#define DEBUG_MII       0x0020     /* Print MII messages */
+#define DEBUG_OPEN      0x0040     /* Print de4x5_open() messages */
+#define DEBUG_CLOSE     0x0080     /* Print de4x5_close() messages */
+#define DEBUG_PCICFG    0x0100
+
+/*
 ** Miscellaneous
 */
 #define PCI  0
@@ -728,11 +827,16 @@
 */
 #define NO                   0
 #define FALSE                0
-#define CLOSED               0
 
 #define YES                  ~0
 #define TRUE                 ~0
-#define OPEN                 ~0
+
+/*
+** Adapter state
+*/
+#define INITIALISED          0     /* After h/w initialised and mem alloc'd */
+#define CLOSED               1     /* Ready for opening */
+#define OPEN                 2     /* Running */
 
 /*
 ** IEEE OUIs for various PHY vendor/chip combos - Reg 2 values only. Since
@@ -748,55 +852,68 @@
 ** Speed Selection stuff
 */
 #define SET_10Mb {\
-  if (lp->phy[lp->active].id) {\
-    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD);\
+  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
+    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX);\
     if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
-      mii_wr(MII_CR_10|(de4x5_full_duplex?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
+      mii_wr(MII_CR_10|(lp->fdx?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
     }\
-    omr |= ((de4x5_full_duplex ? OMR_FD : 0) | OMR_TTM);\
+    omr |= ((lp->fdx ? OMR_FDX : 0) | OMR_TTM);\
     outl(omr, DE4X5_OMR);\
-    outl(0, DE4X5_GEP);\
+    lp->cache.gep = 0;\
+  } else if (lp->useSROM && !lp->useMII) {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
+    outl(omr | lp->infoblock_csr6, DE4X5_OMR);\
   } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
-    omr |= (de4x5_full_duplex ? OMR_FD : 0);\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
     outl(omr | OMR_TTM, DE4X5_OMR);\
-    outl((de4x5_full_duplex ? 0 : GEP_FDXD), DE4X5_GEP);\
+    lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD);\
   }\
 }
 
 #define SET_100Mb {\
-  if (lp->phy[lp->active].id) {\
+  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
     int fdx=0;\
     if (lp->phy[lp->active].id == NATIONAL_TX) {\
         mii_wr(mii_rd(0x18, lp->phy[lp->active].addr, DE4X5_MII) & ~0x2000,\
                       0x18, lp->phy[lp->active].addr, DE4X5_MII);\
     }\
-    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD);\
+    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX);\
     sr = mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);\
-    if (!(sr & MII_ANA_T4AM) && de4x5_full_duplex) fdx=1;\
+    if (!(sr & MII_ANA_T4AM) && lp->fdx) fdx=1;\
     if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
       mii_wr(MII_CR_100|(fdx?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
     }\
-    if (fdx) omr |= OMR_FD;\
+    if (fdx) omr |= OMR_FDX;\
     outl(omr, DE4X5_OMR);\
+    lp->cache.gep = 0;\
+  } else if (lp->useSROM && !lp->useMII) {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
+    outl(omr | lp->infoblock_csr6 | OMR_HBD, DE4X5_OMR);\
   } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
-    omr |= (de4x5_full_duplex ? OMR_FD : 0);\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
     outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
-    outl((de4x5_full_duplex ? 0 : GEP_FDXD) | GEP_MODE, DE4X5_GEP);\
+    lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD) | GEP_MODE;\
   }\
 }
 
 /* FIX ME so I don't jam 10Mb networks */
 #define SET_100Mb_PDET {\
-  if (lp->phy[lp->active].id) {\
+  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
     mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
-    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
+    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    outl(omr, DE4X5_OMR);\
+    lp->cache.gep = 0;\
+  } else if (lp->useSROM && !lp->useMII) {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     outl(omr, DE4X5_OMR);\
   } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
-    outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);\
+    lp->cache.gep = (GEP_FDXD | GEP_MODE);\
   }\
 }
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v2.1.24/linux/drivers/net/de600.c	Tue Dec 31 21:41:03 1996
+++ linux/drivers/net/de600.c	Sun Feb  2 15:18:37 1997
@@ -88,8 +88,6 @@
 #define DE600_DEBUG 0
 #define PRINTK(x) /**/
 #endif
-unsigned int de600_debug = DE600_DEBUG;
-MODULE_PARM(de600_debug, "i");
 
 #include <linux/module.h>
 
@@ -111,12 +109,14 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
+unsigned int de600_debug = DE600_DEBUG;
+MODULE_PARM(de600_debug, "i");
+
 #ifdef FAKE_SMALL_MAX
 static unsigned long de600_rspace(struct sock *sk);
 #include <net/sock.h>
 #endif
 
-#define netstats enet_statistics
 typedef unsigned char byte;
 
 /**************************************************
@@ -244,7 +244,7 @@
 /* Put in the device structure. */
 static int	de600_open(struct device *dev);
 static int	de600_close(struct device *dev);
-static struct netstats *get_stats(struct device *dev);
+static struct net_device_stats *get_stats(struct device *dev);
 static int	de600_start_xmit(struct sk_buff *skb, struct device *dev);
 
 /* Dispatch from interrupts. */
@@ -374,10 +374,10 @@
 	return 0;
 }
 
-static struct netstats *
+static struct net_device_stats *
 get_stats(struct device *dev)
 {
-    return (struct netstats *)(dev->priv);
+    return (struct net_device_stats *)(dev->priv);
 }
 
 static inline void
@@ -556,7 +556,7 @@
 	if (!(irq_status & TX_FAILED16)) {
 		tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
 		++free_tx_pages;
-		((struct netstats *)(dev->priv))->tx_packets++;
+		((struct net_device_stats *)(dev->priv))->tx_packets++;
 		dev->tbusy = 0;
 	}
 
@@ -623,7 +623,7 @@
 	for (i = size; i > 0; --i, ++buffer)
 		*buffer = de600_read_byte(READ_DATA, dev);
 
-	((struct netstats *)(dev->priv))->rx_packets++; /* count all receives */
+	((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */
 
 	skb->protocol=eth_type_trans(skb,dev);
 
@@ -639,8 +639,8 @@
 de600_probe(struct device *dev)
 {
 	int	i;
-	static struct netstats de600_netstats;
-	/*dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);*/
+	static struct net_device_stats de600_netstats;
+	/*dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);*/
 
 	printk("%s: D-Link DE-600 pocket adapter", dev->name);
 	/* Alpha testers must have the version number to report bugs. */
@@ -697,10 +697,9 @@
 	printk("\n");
 
 	/* Initialize the device structure. */
-	/*dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);*/
 	dev->priv = &de600_netstats;
 
-	memset(dev->priv, 0, sizeof(struct netstats));
+	memset(dev->priv, 0, sizeof(struct net_device_stats));
 	dev->get_stats = get_stats;
 
 	dev->open = de600_open;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v2.1.24/linux/drivers/net/de620.c	Tue Dec 31 21:41:03 1996
+++ linux/drivers/net/de620.c	Sun Feb  2 15:18:38 1997
@@ -140,7 +140,6 @@
 /* Constant definitions for the DE-620 registers, commands and bits */
 #include "de620.h"
 
-#define netstats enet_statistics
 typedef unsigned char byte;
 
 /*******************************************************
@@ -212,7 +211,7 @@
 /* Put in the device structure. */
 static int	de620_open(struct device *);
 static int	de620_close(struct device *);
-static struct netstats *get_stats(struct device *);
+static struct	net_device_stats *get_stats(struct device *);
 static void	de620_set_multicast_list(struct device *);
 static int	de620_start_xmit(struct sk_buff *, struct device *);
 
@@ -477,10 +476,9 @@
  * Return current statistics
  *
  */
-static struct netstats *
-get_stats(struct device *dev)
+static struct net_device_stats *get_stats(struct device *dev)
 {
-	return (struct netstats *)(dev->priv);
+	return (struct net_device_stats *)(dev->priv);
 }
 
 /*********************************************
@@ -590,7 +588,7 @@
 	dev->trans_start = jiffies;
 	dev->tbusy = (using_txbuf == (TXBF0 | TXBF1)); /* Boolean! */
 
-	((struct netstats *)(dev->priv))->tx_packets++;
+	((struct net_device_stats *)(dev->priv))->tx_packets++;
 
 	restore_flags(flags); /* interrupts maybe back on */
 
@@ -681,7 +679,7 @@
 		printk("%s: Ring overrun? Restoring...\n", dev->name);
 		/* You win some, you loose some. And sometimes plenty... */
 		adapter_init(dev);
-		((struct netstats *)(dev->priv))->rx_over_errors++;
+		((struct net_device_stats *)(dev->priv))->rx_over_errors++;
 		return 0;
 	}
 
@@ -701,7 +699,7 @@
 		next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
 		de620_send_command(dev, W_DUMMY);
 		de620_set_register(dev, W_NPRF, next_rx_page);
-		((struct netstats *)(dev->priv))->rx_over_errors++;
+		((struct net_device_stats *)(dev->priv))->rx_over_errors++;
 		return 0;
 	}
 	next_rx_page = pagelink;
@@ -715,7 +713,7 @@
 		if (skb == NULL) { /* Yeah, but no place to put it... */
 			printk("%s: Couldn't allocate a sk_buff of size %d.\n",
 				dev->name, size);
-			((struct netstats *)(dev->priv))->rx_dropped++;
+			((struct net_device_stats *)(dev->priv))->rx_dropped++;
 		}
 		else { /* Yep! Go get it! */
 			skb_reserve(skb,2);	/* Align */
@@ -729,7 +727,7 @@
 			skb->protocol=eth_type_trans(skb,dev);
 			netif_rx(skb); /* deliver it "upstairs" */
 			/* count all receives */
-			((struct netstats *)(dev->priv))->rx_packets++;
+			((struct net_device_stats *)(dev->priv))->rx_packets++;
 		}
 	}
 
@@ -838,7 +836,7 @@
 int
 de620_probe(struct device *dev)
 {
-	static struct netstats de620_netstats;
+	static struct net_device_stats de620_netstats;
 	int i;
 	byte checkbyte = 0xa5;
 
@@ -892,10 +890,9 @@
 		printk(" UTP)\n");
 
 	/* Initialize the device structure. */
-	/*dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);*/
 	dev->priv = &de620_netstats;
 
-	memset(dev->priv, 0, sizeof(struct netstats));
+	memset(dev->priv, 0, sizeof(struct net_device_stats));
 	dev->get_stats = get_stats;
 	dev->open = de620_open;
 	dev->stop = de620_close;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
--- v2.1.24/linux/drivers/net/defxx.c	Thu Jan  2 15:55:18 1997
+++ linux/drivers/net/defxx.c	Sun Feb  2 15:18:39 1997
@@ -247,7 +247,7 @@
 static void		dfx_int_common(DFX_board_t *bp);
 static void		dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
-static struct	enet_statistics *dfx_ctl_get_stats(struct device *dev);
+static struct		net_device_stats *dfx_ctl_get_stats(struct device *dev);
 static void		dfx_ctl_set_multicast_list(struct device *dev);
 static int		dfx_ctl_set_mac_address(struct device *dev, void *addr);
 static int		dfx_ctl_update_cam(DFX_board_t *bp);
@@ -1991,7 +1991,7 @@
  *   None
  */
 
-struct enet_statistics *dfx_ctl_get_stats(
+struct net_device_stats *dfx_ctl_get_stats(
 	struct device *dev
 	)
 
@@ -2013,7 +2013,7 @@
 
 	bp->cmd_req_virt->cmd_type = PI_CMD_K_SMT_MIB_GET;
 	if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
-		return((struct enet_statistics *) &bp->stats);
+		return((struct net_device_stats *) &bp->stats);
 
 	/* Fill the bp->stats structure with the SMT MIB object values */
 
@@ -2114,7 +2114,7 @@
 
 	bp->cmd_req_virt->cmd_type = PI_CMD_K_CNTRS_GET;
 	if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
-		return((struct enet_statistics *) &bp->stats);
+		return((struct net_device_stats *) &bp->stats);
 
 	/* Fill the bp->stats structure with the FDDI counter values */
 
@@ -2130,7 +2130,7 @@
 	bp->stats.port_lem_cts[0]			= bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls;
 	bp->stats.port_lem_cts[1]			= bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls;
 
-	return((struct enet_statistics *) &bp->stats);
+	return((struct net_device_stats *) &bp->stats);
 	}
 
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.1.24/linux/drivers/net/depca.c	Tue Dec 31 21:41:03 1996
+++ linux/drivers/net/depca.c	Sun Feb  2 15:18:39 1997
@@ -352,7 +352,7 @@
     u_long dma_buffs;		   /* LANCE Rx and Tx buffers start address. */
     int	rx_new, tx_new;		   /* The next free ring entry               */
     int rx_old, tx_old;	           /* The ring entries to be free()ed.       */
-    struct enet_statistics stats;
+    struct net_device_stats stats;
     struct {                       /* Private stats counters                 */
 	u32 bins[DEPCA_PKT_STAT_SZ];
 	u32 unicast;
@@ -387,7 +387,7 @@
 static void   depca_interrupt(int irq, void *dev_id, struct pt_regs * regs);
 static int    depca_close(struct device *dev);
 static int    depca_ioctl(struct device *dev, struct ifreq *rq, int cmd);
-static struct enet_statistics *depca_get_stats(struct device *dev);
+static struct net_device_stats *depca_get_stats(struct device *dev);
 static void   set_multicast_list(struct device *dev);
 
 /*
@@ -1113,7 +1113,7 @@
   return status;
 }
 
-static struct enet_statistics *
+static struct net_device_stats *
 depca_get_stats(struct device *dev)
 {
     struct depca_private *lp = (struct depca_private *)dev->priv;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- v2.1.24/linux/drivers/net/dgrs.c	Tue Dec 31 21:41:03 1996
+++ linux/drivers/net/dgrs.c	Sun Feb  2 15:18:39 1997
@@ -195,7 +195,7 @@
 	 */
 	char			devname[8];	/* "ethN" string */
 	struct device		*next_dev;
-	struct enet_statistics	stats;
+	struct net_device_stats	stats;
 
 	/*
 	 *	DGRS specific data
@@ -687,8 +687,8 @@
  *	output port by setting the special "dstchan" member at the
  *	end of the traditional 82596 RFD structure.
  */
-static int
-dgrs_start_xmit(struct sk_buff *skb, struct device *devN)
+
+static int dgrs_start_xmit(struct sk_buff *skb, struct device *devN)
 {
 	DGRS_PRIV	*privN = (DGRS_PRIV *) devN->priv;
 	struct device	*dev0;
@@ -793,9 +793,9 @@
 	dev->interrupt = 0;
 	dev->start = 1;
 
-	#ifdef MODULE
-		MOD_INC_USE_COUNT;
-	#endif
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
 
 	return (0);
 }
@@ -803,15 +803,14 @@
 /*
  *	Close the interface
  */
-static int
-dgrs_close( struct device *dev )
+static int dgrs_close( struct device *dev )
 {
 	dev->start = 0;
 	dev->tbusy = 1;
 
-	#ifdef MODULE
-		MOD_DEC_USE_COUNT;
-	#endif
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
 
 	return (0);
 }
@@ -819,8 +818,7 @@
 /*
  *	Get statistics
  */
-static struct enet_statistics *
-dgrs_get_stats( struct device *dev )
+static struct net_device_stats *dgrs_get_stats( struct device *dev )
 {
 	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;
 
@@ -830,8 +828,8 @@
 /*
  *	Set multicast list and/or promiscuous mode
  */
-static void
-dgrs_set_multicast_list( struct device *dev)
+
+static void dgrs_set_multicast_list( struct device *dev)
 {
 	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;
 
@@ -841,63 +839,60 @@
 /*
  *	Unique ioctl's
  */
-static int
-dgrs_ioctl(struct device *devN, struct ifreq *ifr, int cmd)
+static int dgrs_ioctl(struct device *devN, struct ifreq *ifr, int cmd)
 {
 	DGRS_PRIV	*privN = (DGRS_PRIV *) devN->priv;
 	DGRS_IOCTL	ioc;
 	int		i, rc;
 
-	rc = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(DGRS_IOCTL));
-	if (rc) return (rc);
-	if (cmd != DGRSIOCTL) return -EINVAL;
+	if (cmd != DGRSIOCTL)
+		return -EINVAL;
 
-	COPY_FROM_USER(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL));
+	if(COPY_FROM_USER(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL)))
+		return -EFAULT;
 
 	switch (ioc.cmd)
 	{
-	case DGRS_GETMEM:
-		if (ioc.len != sizeof(ulong))
-			return -EINVAL;
-		rc = verify_area(VERIFY_WRITE, (void *) ioc.data, ioc.len);
-		if (rc) return (rc);
-		COPY_TO_USER(ioc.data, &devN->mem_start, ioc.len);
-		return (0);
-	case DGRS_SETFILTER:
-		rc = verify_area(VERIFY_READ, (void *) ioc.data, ioc.len);
-		if (rc) return (rc);
-		if (ioc.port > privN->bcomm->bc_nports)
-			return -EINVAL;
-		if (ioc.filter >= NFILTERS)
-			return -EINVAL;
-		if (ioc.len > privN->bcomm->bc_filter_area_len)
-			return -EINVAL;
-
-		/* Wait for old command to finish */
-		for (i = 0; i < 1000; ++i)
-		{
-			if ( (volatile) privN->bcomm->bc_filter_cmd <= 0 )
-				break;
-			udelay(1);
-		}
-		if (i >= 1000)
-			return -EIO;
+		case DGRS_GETMEM:
+			if (ioc.len != sizeof(ulong))
+				return -EINVAL;
+			if(COPY_TO_USER(ioc.data, &devN->mem_start, ioc.len))
+				return -EFAULT;
+			return (0);
+		case DGRS_SETFILTER:
+			if (ioc.port > privN->bcomm->bc_nports)
+				return -EINVAL;
+			if (ioc.filter >= NFILTERS)
+				return -EINVAL;
+			if (ioc.len > privN->bcomm->bc_filter_area_len)
+				return -EINVAL;
 
-		privN->bcomm->bc_filter_port = ioc.port;
-		privN->bcomm->bc_filter_num = ioc.filter;
-		privN->bcomm->bc_filter_len = ioc.len;
+			/* Wait for old command to finish */
+			for (i = 0; i < 1000; ++i)
+			{
+				if ( (volatile) privN->bcomm->bc_filter_cmd <= 0 )
+					break;
+				udelay(1);
+			}
+			if (i >= 1000)
+				return -EIO;
 
-		if (ioc.len)
-		{
-			COPY_FROM_USER(S2HN(privN->bcomm->bc_filter_area),
-					ioc.data, ioc.len);
-			privN->bcomm->bc_filter_cmd = BC_FILTER_SET;
-		}
-		else
-			privN->bcomm->bc_filter_cmd = BC_FILTER_CLR;
-		return(0);
-	default:
-		return -EOPNOTSUPP;
+			privN->bcomm->bc_filter_port = ioc.port;
+			privN->bcomm->bc_filter_num = ioc.filter;
+			privN->bcomm->bc_filter_len = ioc.len;
+	
+			if (ioc.len)
+			{
+				if(COPY_FROM_USER(S2HN(privN->bcomm->bc_filter_area),
+					ioc.data, ioc.len))
+					return -EFAULT;
+				privN->bcomm->bc_filter_cmd = BC_FILTER_SET;
+			}
+			else
+				privN->bcomm->bc_filter_cmd = BC_FILTER_CLR;
+			return(0);
+		default:
+			return -EOPNOTSUPP;
 	}
 }
 
@@ -906,8 +901,8 @@
  *
  *	dev, priv will always refer to the 0th device in Multi-NIC mode.
  */
-static void
-dgrs_intr(int irq, void *dev_id, struct pt_regs *regs)
+
+static void dgrs_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct device	*dev0 = (struct device *) dev_id;
 	DGRS_PRIV	*priv0 = (DGRS_PRIV *) dev0->priv;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/dlci.c linux/drivers/net/dlci.c
--- v2.1.24/linux/drivers/net/dlci.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/net/dlci.c	Sun Feb  2 15:18:39 1997
@@ -5,7 +5,7 @@
  *		interfaces.  Requires 'dlcicfg' program to create usable 
  *		interfaces, the initial one, 'dlci' is for IOCTL use only.
  *
- * Version:	@(#)dlci.c	0.30	12 Sep 1996
+ * Version:	@(#)dlci.c	0.35	4 Jan 1997
  *
  * Author:	Mike McLagan <mike.mclagan@linux.org>
  *
@@ -20,6 +20,7 @@
  *				 	sent back to Linux for re-transmission
  *		0.25	Mike McLagan	Converted to use SIOC IOCTL calls
  *		0.30	Jim Freeman	Fixed to allow IPX traffic
+ *		0.35	Michael Elizabeth	Fixed incorrect memcpy_fromfs
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -55,7 +56,7 @@
 #include <net/sock.h>
 
 static const char *devname = "dlci";
-static const char *version = "DLCI driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";
+static const char *version = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
 
 static struct device *open_dev[CONFIG_DLCI_COUNT];
 
@@ -66,51 +67,51 @@
 /* allow FRAD's to register their name as a valid FRAD */
 int register_frad(const char *name)
 {
-   int i;
+	int i;
 
-   if (!name)
-      return(-EINVAL);
+	if (!name)
+		return(-EINVAL);
 
-   for (i=0;i<sizeof(basename) / sizeof(char *);i++)
-   {
-      if (!basename[i])
-         break;
+	for (i=0;i<sizeof(basename) / sizeof(char *);i++)
+	{
+		if (!basename[i])
+			break;
 
-      /* take care of multiple registrations */
-      if (strcmp(basename[i], name) == 0)
-         return(0);
-   }
+		/* take care of multiple registrations */
+		if (strcmp(basename[i], name) == 0)
+			return(0);
+	}
 
-   if (i == sizeof(basename) / sizeof(char *))
-      return(-EMLINK);
+	if (i == sizeof(basename) / sizeof(char *))
+		return(-EMLINK);
 
-   basename[i] = kmalloc(strlen(name) + 1, GFP_KERNEL);
-   if (!basename[i])
-      return(-ENOMEM);
+	basename[i] = kmalloc(strlen(name) + 1, GFP_KERNEL);
+	if (!basename[i])
+		return(-ENOMEM);
 
-   strcpy(basename[i], name);
+	strcpy(basename[i], name);
 
-   return(0);
+	return(0);
 }
 
 int unregister_frad(const char *name)
 {
-   int i;
+	int i;
 
-   if (!name)
-      return(-EINVAL);
+	if (!name)
+		return(-EINVAL);
 
-   for (i=0;i<sizeof(basename) / sizeof(char *);i++)
-      if (basename[i] && (strcmp(basename[i], name) == 0))
-         break;
+	for (i=0;i<sizeof(basename) / sizeof(char *);i++)
+		if (basename[i] && (strcmp(basename[i], name) == 0))
+			break;
 
-   if (i == sizeof(basename) / sizeof(char *))
-      return(-EINVAL);
+	if (i == sizeof(basename) / sizeof(char *))
+		return(-EINVAL);
 
-   kfree(basename[i]);
-   basename[i] = NULL;
+	kfree(basename[i]);
+	basename[i] = NULL;
 
-   return(0);
+	return(0);
 }
 
 /* 
@@ -123,519 +124,501 @@
                            unsigned short type, void *daddr, void *saddr, 
                            unsigned len)
 {
-   struct frhdr      hdr;
-   struct dlci_local *dlp;
-   unsigned          hlen;
-   char              *dest;
-
-   dlp = dev->priv;
-
-   hdr.control = FRAD_I_UI;
-   switch(type)
-   {
-      case ETH_P_IP:
-         hdr.IP_NLPID = FRAD_P_IP;
-         hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
-         break;
-
-      /* feel free to add other types, if necessary */
-
-      default:
-         hdr.pad = FRAD_P_PADDING;
-         hdr.NLPID = FRAD_P_SNAP;
-         memset(hdr.OUI, 0, sizeof(hdr.OUI));
-         hdr.PID = htons(type);
-         hlen = sizeof(hdr);
-         break;
-   }
-
-   dest = skb_push(skb, hlen);
-   if (!dest)
-      return(0);
+	struct frhdr		hdr;
+	struct dlci_local	*dlp;
+	unsigned int		hlen;
+	char			*dest;
+
+	dlp = dev->priv;
+
+	hdr.control = FRAD_I_UI;
+	switch(type)
+	{
+		case ETH_P_IP:
+			hdr.IP_NLPID = FRAD_P_IP;
+			hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
+			break;
+
+		/* feel free to add other types, if necessary */
+
+		default:
+			hdr.pad = FRAD_P_PADDING;
+			hdr.NLPID = FRAD_P_SNAP;
+			memset(hdr.OUI, 0, sizeof(hdr.OUI));
+			hdr.PID = htons(type);
+			hlen = sizeof(hdr);
+			break;
+	}
+
+	dest = skb_push(skb, hlen);
+	if (!dest)
+		return(0);
 
-   memcpy(dest, &hdr, hlen);
+	memcpy(dest, &hdr, hlen);
 
-   return(hlen);
+	return(hlen);
 }
 
 static void dlci_receive(struct sk_buff *skb, struct device *dev)
 {
-   struct dlci_local *dlp;
-   struct frhdr      *hdr;
-   int               process, header;
-
-   dlp = dev->priv;
-   hdr = (struct frhdr *) skb->data;
-   process = 0;
-   header = 0;
-   skb->dev = dev;
-
-   if (hdr->control != FRAD_I_UI)
-   {
-      printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", dev->name, hdr->control);
-      dlp->stats.rx_errors++;
-   }
-   else
-      switch(hdr->IP_NLPID)
-      {
-         case FRAD_P_PADDING:
-            if (hdr->NLPID != FRAD_P_SNAP)
-            {
-               printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->NLPID);
-               dlp->stats.rx_errors++;
-               break;
-            }
-    
-            if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
-            {
-               printk(KERN_NOTICE "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.\n", dev->name, hdr->OUI[0], hdr->OUI[1], hdr->OUI[2]);
-               dlp->stats.rx_errors++;
-               break;
-            }
-
-            /* at this point, it's an EtherType frame */
-            header = sizeof(struct frhdr);
-            /* Already in network order ! */
-            skb->protocol = hdr->PID;
-            process = 1;
-            break;
-
-         case FRAD_P_IP:
-            header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
-            skb->protocol = htons(ETH_P_IP);
-            process = 1;
-            break;
-
-         case FRAD_P_SNAP:
-         case FRAD_P_Q933:
-         case FRAD_P_CLNP:
-            printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->pad);
-            dlp->stats.rx_errors++;
-            break;
-
-         default:
-            printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.\n", dev->name, hdr->pad);
-            dlp->stats.rx_errors++;
-            break;            
-      }
-
-   if (process)
-   {
-      /* we've set up the protocol, so discard the header */
-      skb->mac.raw = skb->data; 
-      skb_pull(skb, header);
-      netif_rx(skb);
-      dlp->stats.rx_packets++;
-   }
-   else
-      dev_kfree_skb(skb, FREE_WRITE);
+	struct dlci_local *dlp;
+	struct frhdr		*hdr;
+	int					process, header;
+
+	dlp = dev->priv;
+	hdr = (struct frhdr *) skb->data;
+	process = 0;
+	header = 0;
+	skb->dev = dev;
+
+	if (hdr->control != FRAD_I_UI)
+	{
+		printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", dev->name, hdr->control);
+		dlp->stats.rx_errors++;
+	}
+	else
+		switch(hdr->IP_NLPID)
+		{
+			case FRAD_P_PADDING:
+				if (hdr->NLPID != FRAD_P_SNAP)
+				{
+					printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->NLPID);
+					dlp->stats.rx_errors++;
+					break;
+				}
+	 
+				if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
+				{
+					printk(KERN_NOTICE "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.\n", dev->name, hdr->OUI[0], hdr->OUI[1], hdr->OUI[2]);
+					dlp->stats.rx_errors++;
+					break;
+				}
+
+				/* at this point, it's an EtherType frame */
+				header = sizeof(struct frhdr);
+				/* Already in network order ! */
+				skb->protocol = hdr->PID;
+				process = 1;
+				break;
+
+			case FRAD_P_IP:
+				header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
+				skb->protocol = htons(ETH_P_IP);
+				process = 1;
+				break;
+
+			case FRAD_P_SNAP:
+			case FRAD_P_Q933:
+			case FRAD_P_CLNP:
+				printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->pad);
+				dlp->stats.rx_errors++;
+				break;
+
+			default:
+				printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.\n", dev->name, hdr->pad);
+				dlp->stats.rx_errors++;
+				break;				
+		}
+
+	if (process)
+	{
+		/* we've set up the protocol, so discard the header */
+		skb->mac.raw = skb->data; 
+		skb_pull(skb, header);
+		netif_rx(skb);
+		dlp->stats.rx_packets++;
+	}
+	else
+		dev_kfree_skb(skb, FREE_WRITE);
 }
 
 static int dlci_transmit(struct sk_buff *skb, struct device *dev)
 {
-   struct dlci_local *dlp;
-   int               ret;
+	struct dlci_local *dlp;
+	int					ret;
 
-   ret = 0;
+	ret = 0;
 
-   if (!skb || !dev)
-      return(0);
+	if (!skb || !dev)
+		return(0);
 
-   if (dev->tbusy)
-      return(1);
-
-   dlp = dev->priv;
-
-   if (set_bit(0, (void*)&dev->tbusy) != 0)
-      printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
-   else
-   {
-      ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
-      switch (ret)
-      {
-         case DLCI_RET_OK:
-            dlp->stats.tx_packets++;
-            ret = 0;
-            break;
-
-         case DLCI_RET_ERR:
-            dlp->stats.tx_errors++;
-            ret = 0;
-            break;
-
-         case DLCI_RET_DROP:
-            dlp->stats.tx_dropped++;
-            ret = 1;
-            break;
-      }
-
-      /* Alan Cox recommends always returning 0, and always freeing the packet */
-      /* experience suggest a slightly more conservative approach */
+	if (dev->tbusy)
+		return(1);
+
+	dlp = dev->priv;
+
+	if (set_bit(0, (void*)&dev->tbusy) != 0)
+		printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
+	else
+	{
+		ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
+		switch (ret)
+		{
+			case DLCI_RET_OK:
+				dlp->stats.tx_packets++;
+				ret = 0;
+				break;
+
+			case DLCI_RET_ERR:
+				dlp->stats.tx_errors++;
+				ret = 0;
+				break;
+
+			case DLCI_RET_DROP:
+				dlp->stats.tx_dropped++;
+				ret = 1;
+				break;
+		}
+
+		/* Alan Cox recommends always returning 0, and always freeing the packet */
+		/* experience suggest a slightly more conservative approach */
 
-      if (!ret)
-         dev_kfree_skb(skb, FREE_WRITE);
+		if (!ret)
+			dev_kfree_skb(skb, FREE_WRITE);
 
-      dev->tbusy = 0;
-   }
+		dev->tbusy = 0;
+	}
 
-   return(ret);
+	return(ret);
 }
 
 int dlci_config(struct device *dev, struct dlci_conf *conf, int get)
 {
-   struct dlci_conf  config;
-   struct dlci_local *dlp;
-   struct frad_local *flp;
-   int               err;
-
-   dlp = dev->priv;
-
-   flp = dlp->slave->priv;
-
-   if (!get)
-   {
-      err = verify_area(VERIFY_READ, conf, sizeof(struct dlci_conf));
-      if (err)
-         return(err);
-
-      copy_from_user(&config, conf, sizeof(struct dlci_conf));
-      if (config.flags & ~DLCI_VALID_FLAGS)
-         return(-EINVAL);
-      memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
-      dlp->configured = 1;
-   }
-
-   err = (*flp->dlci_conf)(dlp->slave, dev, get);
-   if (err)
-      return(err);
-
-   if (get)
-   {
-      err = verify_area(VERIFY_WRITE, conf, sizeof(struct dlci_conf));
-      if (err)
-         return(err);
+	struct dlci_conf	config;
+	struct dlci_local	*dlp;
+	struct frad_local	*flp;
+	int			err;
+
+	dlp = dev->priv;
+
+	flp = dlp->slave->priv;
+
+	if (!get)
+	{
+		if(copy_from_user(&config, conf, sizeof(struct dlci_conf)))
+			return -FAULT;
+		if (config.flags & ~DLCI_VALID_FLAGS)
+			return(-EINVAL);
+		memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
+		dlp->configured = 1;
+	}
+
+	err = (*flp->dlci_conf)(dlp->slave, dev, get);
+	if (err)
+		return(err);
+
+	if (get)
+	{
+		if(copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)))
+			return -EFAULT;
+	}
 
-      copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf));
-   }
-
-   return(0);
+	return(0);
 }
 
 int dlci_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
 {
-   struct dlci_local *dlp;
-   int               err, len;
+	struct dlci_local *dlp;
 
-   if (!suser())
-      return(-EPERM);
+	if (!suser())
+		return(-EPERM);
 
-   dlp = dev->priv;
+	dlp = dev->priv;
 
-   switch(cmd)
-   {
-      case DLCI_GET_SLAVE:
-         if (!*(short *)(dev->dev_addr))
-            return(-EINVAL);
-
-         len = strlen(dlp->slave->name) + 1;
-         err = verify_area(VERIFY_WRITE, ifr->ifr_slave, len);
-         if (err)
-            return err;
-
-         copy_to_user(ifr->ifr_slave, dlp->slave->name, len);
-         break;
-
-      case DLCI_GET_CONF:
-      case DLCI_SET_CONF:
-         if (!*(short *)(dev->dev_addr))
-            return(-EINVAL);
-
-         return(dlci_config(dev, (struct dlci_conf *) ifr->ifr_data, cmd == DLCI_GET_CONF));
-         break;
-
-      default: 
-         return(-EOPNOTSUPP);
-   }
-   return(0);
+	switch(cmd)
+	{
+		case DLCI_GET_SLAVE:
+			if (!*(short *)(dev->dev_addr))
+				return(-EINVAL);
+
+			strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
+			break;
+
+		case DLCI_GET_CONF:
+		case DLCI_SET_CONF:
+			if (!*(short *)(dev->dev_addr))
+				return(-EINVAL);
+
+			return(dlci_config(dev, (struct dlci_conf *) ifr->ifr_data, cmd == DLCI_GET_CONF));
+			break;
+
+		default: 
+			return(-EOPNOTSUPP);
+	}
+	return(0);
 }
 
 static int dlci_change_mtu(struct device *dev, int new_mtu)
 {
-   struct dlci_local *dlp;
+	struct dlci_local *dlp;
 
-   dlp = dev->priv;
+	dlp = dev->priv;
 
-   return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
+	return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
 }
 
 static int dlci_open(struct device *dev)
 {
-   struct dlci_local *dlp;
-   struct frad_local *flp;
-   int               err;
+	struct dlci_local	*dlp;
+	struct frad_local	*flp;
+	int			err;
 
-   dlp = dev->priv;
+	dlp = dev->priv;
 
-   if (!*(short *)(dev->dev_addr))
-      return(-EINVAL);
+	if (!*(short *)(dev->dev_addr))
+		return(-EINVAL);
 
-   if (!dlp->slave->start)
-      return(-ENOTCONN);
+	if (!dlp->slave->start)
+		return(-ENOTCONN);
 
-   dev->flags = 0;
-   dev->tbusy = 0;
-   dev->interrupt = 0;
-   dev->start = 1;
+	dev->flags = 0;
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
 
-   flp = dlp->slave->priv;
-   err = (*flp->activate)(dlp->slave, dev);
-   if (err)
-      return(err);
+	flp = dlp->slave->priv;
+	err = (*flp->activate)(dlp->slave, dev);
+	if (err)
+		return(err);
 
-   return 0;
+	return 0;
 }
 
 static int dlci_close(struct device *dev)
 {
-   struct dlci_local *dlp;
-   struct frad_local *flp;
-   int               err;
+	struct dlci_local	*dlp;
+	struct frad_local	*flp;
+	int			err;
 
-   dlp = dev->priv;
+	dlp = dev->priv;
 
-   flp = dlp->slave->priv;
-   err = (*flp->deactivate)(dlp->slave, dev);
+	flp = dlp->slave->priv;
+	err = (*flp->deactivate)(dlp->slave, dev);
 
-   dev->start = 0;
-   dev->tbusy = 1;
+	dev->start = 0;
+	dev->tbusy = 1;
 
-   return 0;
+	return 0;
 }
 
-static struct enet_statistics *dlci_get_stats(struct device *dev)
+static struct net_device_stats *dlci_get_stats(struct device *dev)
 {
-   struct dlci_local *dlp;
+	struct dlci_local *dlp;
 
-   dlp = dev->priv;
+	dlp = dev->priv;
 
-   return(&dlp->stats);
+	return(&dlp->stats);
 }
 
 int dlci_add(struct dlci_add *dlci)
 {
-   struct device       *master, *slave;
-   struct dlci_local   *dlp;
-   struct frad_local   *flp;
-   int                 err, i;
-   char                buf[10];
-
-   /* validate slave device */
-   slave = dev_get(dlci->devname);
-   if (!slave)
-      return(-ENODEV);
-
-   if (slave->type != ARPHRD_FRAD)
-      return(-EINVAL);
-
-   /* check for registration */
-   for (i=0;i<sizeof(basename) / sizeof(char *); i++)
-      if ((basename[i]) && 
-          (strncmp(dlci->devname, basename[i], strlen(basename[i])) == 0) && 
-          (strlen(dlci->devname) > strlen(basename[i])))
-         break;
-
-   if (i == sizeof(basename) / sizeof(char *))
-      return(-EINVAL);
-
-   /* check for too many open devices : should this be dynamic ? */
-   for(i=0;i<CONFIG_DLCI_COUNT;i++)
-      if (!open_dev[i])
-         break;
-
-   if (i == CONFIG_DLCI_COUNT)
-      return(-ENOSPC);  /*  #### Alan: Comments on this?? */
-
-   /* create device name */
-   sprintf(buf, "%s%02i", devname, i);
-
-   master = kmalloc(sizeof(*master), GFP_KERNEL);
-   if (!master)
-      return(-ENOMEM);
-
-   memset(master, 0, sizeof(*master));
-   master->name = kmalloc(strlen(buf) + 1, GFP_KERNEL);
-
-   if (!master->name)
-   {
-      kfree(master);
-      return(-ENOMEM);
-   }
-
-   strcpy(master->name, buf);
-   master->init = dlci_init;
-   master->flags = 0;
-
-   err = register_netdev(master);
-   if (err < 0)
-   {
-      kfree(master->name);
-      kfree(master);
-      return(err);
-   }
-
-   *(short *)(master->dev_addr) = dlci->dlci;
-
-   dlp = (struct dlci_local *) master->priv;
-   dlp->slave = slave;
-
-   flp = slave->priv;
-   err = flp ? (*flp->assoc)(slave, master) : -EINVAL;
-   if (err < 0)
-   {
-      unregister_netdev(master);
-      kfree(master->priv);
-      kfree(master->name);
-      kfree(master);
-      return(err);
-   }
-
-   strcpy(dlci->devname, buf);
-   open_dev[i] = master;
-   MOD_INC_USE_COUNT;
-   return(0);
+	struct device		*master, *slave;
+	struct dlci_local	*dlp;
+	struct frad_local	*flp;
+	int			err, i;
+	char			buf[10];
+
+	/* validate slave device */
+	slave = dev_get(dlci->devname);
+	if (!slave)
+		return(-ENODEV);
+
+	if (slave->type != ARPHRD_FRAD)
+		return(-EINVAL);
+
+	/* check for registration */
+	for (i=0;i<sizeof(basename) / sizeof(char *); i++)
+		if ((basename[i]) && 
+			 (strncmp(dlci->devname, basename[i], strlen(basename[i])) == 0) && 
+			 (strlen(dlci->devname) > strlen(basename[i])))
+			break;
+
+	if (i == sizeof(basename) / sizeof(char *))
+		return(-EINVAL);
+
+	/* check for too many open devices : should this be dynamic ? */
+	for(i=0;i<CONFIG_DLCI_COUNT;i++)
+		if (!open_dev[i])
+			break;
+
+	if (i == CONFIG_DLCI_COUNT)
+		return(-ENOSPC);  /*  #### Alan: Comments on this?? */
+
+	/* create device name */
+	sprintf(buf, "%s%02i", devname, i);
+
+	master = kmalloc(sizeof(*master), GFP_KERNEL);
+	if (!master)
+		return(-ENOMEM);
+
+	memset(master, 0, sizeof(*master));
+	master->name = kmalloc(strlen(buf) + 1, GFP_KERNEL);
+
+	if (!master->name)
+	{
+		kfree(master);
+		return(-ENOMEM);
+	}
+
+	strcpy(master->name, buf);
+	master->init = dlci_init;
+	master->flags = 0;
+
+	err = register_netdev(master);
+	if (err < 0)
+	{
+		kfree(master->name);
+		kfree(master);
+		return(err);
+	}
+
+	*(short *)(master->dev_addr) = dlci->dlci;
+
+	dlp = (struct dlci_local *) master->priv;
+	dlp->slave = slave;
+
+	flp = slave->priv;
+	err = flp ? (*flp->assoc)(slave, master) : -EINVAL;
+	if (err < 0)
+	{
+		unregister_netdev(master);
+		kfree(master->priv);
+		kfree(master->name);
+		kfree(master);
+		return(err);
+	}
+
+	strcpy(dlci->devname, buf);
+	open_dev[i] = master;
+	MOD_INC_USE_COUNT;
+	return(0);
 }
 
 int dlci_del(struct dlci_add *dlci)
 {
-   struct dlci_local *dlp;
-   struct frad_local *flp;
-   struct device     *master, *slave;
-   int               i, err;
+	struct dlci_local	*dlp;
+	struct frad_local	*flp;
+	struct device		*master, *slave;
+	int			i, err;
 
-   /* validate slave device */
-   master = dev_get(dlci->devname);
-   if (!master)
-      return(-ENODEV);
+	/* validate slave device */
+	master = dev_get(dlci->devname);
+	if (!master)
+		return(-ENODEV);
 
-   if (master->start)
-      return(-EBUSY);
+	if (master->start)
+		return(-EBUSY);
 
-   dlp = master->priv;
-   slave = dlp->slave;
-   flp = slave->priv;
+	dlp = master->priv;
+	slave = dlp->slave;
+	flp = slave->priv;
 
-   err = (*flp->deassoc)(slave, master);
-   if (err)
-      return(err);
+	err = (*flp->deassoc)(slave, master);
+	if (err)
+		return(err);
 
-   unregister_netdev(master);
+	unregister_netdev(master);
 
-   for(i=0;i<CONFIG_DLCI_COUNT;i++)
-      if (master == open_dev[i])
-         break;
+	for(i=0;i<CONFIG_DLCI_COUNT;i++)
+		if (master == open_dev[i])
+			break;
 
-   if (i<CONFIG_DLCI_COUNT)
-      open_dev[i] = NULL;
+	if (i<CONFIG_DLCI_COUNT)
+		open_dev[i] = NULL;
 
-   kfree(master->priv);
-   kfree(master->name);
-   kfree(master);
+	kfree(master->priv);
+	kfree(master->name);
+	kfree(master);
 
-   MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 
-   return(0);
+	return(0);
 }
 
 int dlci_ioctl(unsigned int cmd, void *arg)
 {
-   int             err;
-   struct dlci_add add;
-
-   if (!suser())
-      return(-EPERM);
-
-   err=verify_area(VERIFY_READ, arg, sizeof(struct dlci_add));
-   if (err)
-      return(err);
-
-   copy_from_user(&add, arg, sizeof(struct dlci_add));
-
-   switch (cmd)
-   {
-      case SIOCADDDLCI:
-         err = verify_area(VERIFY_WRITE, arg, sizeof(struct dlci_add));
-         if (err)
-            return(err);
-
-         err = dlci_add(&add);
-
-         if (!err)
-            copy_to_user(arg, &add, sizeof(struct dlci_add));
-         break;
-
-      case SIOCDELDLCI:
-         err = dlci_del(&add);
-         break;
-
-      default:
-         err = -EINVAL;
-   }
+	struct dlci_add add;
+	int err;
+	
+	if (!suser())
+		return(-EPERM);
+
+	if(copy_from_user(&add, arg, sizeof(struct dlci_add)))
+		return -EFAULT;
+
+	switch (cmd)
+	{
+		case SIOCADDDLCI:
+			err = dlci_add(&add);
+
+			if (!err)
+				if(copy_to_user(arg, &add, sizeof(struct dlci_add)))
+					return -EFAULT;
+			break;
+
+		case SIOCDELDLCI:
+			err = dlci_del(&add);
+			break;
+
+		default:
+			err = -EINVAL;
+	}
 
-   return(err);
+	return(err);
 }
 
 int dlci_init(struct device *dev)
 {
-   struct dlci_local *dlp;
+	struct dlci_local *dlp;
 
-   dev->priv = kmalloc(sizeof(struct dlci_local), GFP_KERNEL);
-   if (!dev->priv)
-      return(-ENOMEM);
-
-   memset(dev->priv, 0, sizeof(struct dlci_local));
-   dlp = dev->priv;
-
-   dev->flags           = 0;
-   dev->open            = dlci_open;
-   dev->stop            = dlci_close;
-   dev->do_ioctl        = dlci_dev_ioctl;
-   dev->hard_start_xmit = dlci_transmit;
-   dev->hard_header     = dlci_header;
-   dev->get_stats       = dlci_get_stats;
-   dev->change_mtu	= dlci_change_mtu;
-
-   dlp->receive         = dlci_receive;
-
-   dev->type            = ARPHRD_DLCI;
-   dev->family          = AF_INET;
-   dev->hard_header_len = sizeof(struct frhdr);
-   dev->pa_alen         = sizeof(unsigned long);
-   dev->addr_len        = sizeof(short);
-   memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
-
-   dev->pa_addr         = 0;
-   dev->pa_dstaddr      = 0;
-   dev->pa_brdaddr      = 0;
-   dev->pa_mask         = 0;
-
-   dev_init_buffers(dev);
-   
-   return(0);
+	dev->priv = kmalloc(sizeof(struct dlci_local), GFP_KERNEL);
+	if (!dev->priv)
+		return(-ENOMEM);
+
+	memset(dev->priv, 0, sizeof(struct dlci_local));
+	dlp = dev->priv;
+
+	dev->flags		= 0;
+	dev->open		= dlci_open;
+	dev->stop		= dlci_close;
+	dev->do_ioctl		= dlci_dev_ioctl;
+	dev->hard_start_xmit	= dlci_transmit;
+	dev->hard_header	= dlci_header;
+	dev->get_stats		= dlci_get_stats;
+	dev->change_mtu		= dlci_change_mtu;
+
+	dlp->receive		= dlci_receive;
+
+	dev->type		= ARPHRD_DLCI;
+	dev->family		= AF_INET;
+	dev->hard_header_len	= sizeof(struct frhdr);
+	dev->pa_alen		= 4;
+	dev->addr_len		= sizeof(short);
+	memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
+
+	dev->pa_addr		= 0;
+	dev->pa_dstaddr		= 0;
+	dev->pa_brdaddr		= 0;
+	dev->pa_mask		= 0;
+
+	dev_init_buffers(dev);
+	
+	return(0);
 }
 
 int dlci_setup(void)
 {
-   int i;
+	int i;
 
-   printk("%s.\n", version);
-   
-   for(i=0;i<CONFIG_DLCI_COUNT;i++)
-      open_dev[i] = NULL;
+	printk("%s.\n", version);
+	
+	for(i=0;i<CONFIG_DLCI_COUNT;i++)
+		open_dev[i] = NULL;
 
-   for(i=0;i<sizeof(basename) / sizeof(char *);i++)
-      basename[i] = NULL;
+	for(i=0;i<sizeof(basename) / sizeof(char *);i++)
+		basename[i] = NULL;
 
-   return(0);
+	return(0);
 }
 
 #ifdef MODULE
@@ -644,13 +627,13 @@
 
 int init_module(void)
 {
-   dlci_ioctl_hook = dlci_ioctl;
+	dlci_ioctl_hook = dlci_ioctl;
 
-   return(dlci_setup());
+	return(dlci_setup());
 }
 
 void cleanup_module(void)
 {
-   dlci_ioctl_hook = NULL;
+	dlci_ioctl_hook = NULL;
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/dummy.c linux/drivers/net/dummy.c
--- v2.1.24/linux/drivers/net/dummy.c	Thu Dec 12 19:37:06 1996
+++ linux/drivers/net/dummy.c	Sun Feb  2 15:18:39 1997
@@ -55,7 +55,7 @@
 
 static int dummy_xmit(struct sk_buff *skb, struct device *dev);
 #ifdef DUMMY_STATS
-static struct enet_statistics *dummy_get_stats(struct device *dev);
+static struct net_device_stats *dummy_get_stats(struct device *dev);
 #endif
 
 static int dummy_open(struct device *dev)
@@ -81,10 +81,10 @@
 	dev->hard_start_xmit	= dummy_xmit;
 
 #if DUMMY_STATS
-	dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+	dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
 	if (dev->priv == NULL)
 		return -ENOMEM;
-	memset(dev->priv, 0, sizeof(struct enet_statistics));
+	memset(dev->priv, 0, sizeof(struct net_device_stats));
 	dev->get_stats		= dummy_get_stats;
 #endif
 
@@ -103,16 +103,12 @@
 dummy_xmit(struct sk_buff *skb, struct device *dev)
 {
 #if DUMMY_STATS
-	struct enet_statistics *stats;
+	struct net_device_stats *stats;
 #endif
-
-	if (skb == NULL || dev == NULL)
-		return 0;
-
 	dev_kfree_skb(skb, FREE_WRITE);
 
 #if DUMMY_STATS
-	stats = (struct enet_statistics *)dev->priv;
+	stats = (struct net_device_stats *)dev->priv;
 	stats->tx_packets++;
 #endif
 
@@ -120,10 +116,9 @@
 }
 
 #if DUMMY_STATS
-static struct enet_statistics *
-dummy_get_stats(struct device *dev)
+static struct net_device_stats *dummy_get_stats(struct device *dev)
 {
-	struct enet_statistics *stats = (struct enet_statistics*) dev->priv;
+	struct net_device_stats *stats = (struct net_device_stats *) dev->priv;
 	return stats;
 }
 #endif
diff -u --recursive --new-file v2.1.24/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.1.24/linux/drivers/net/eepro.c	Tue Dec 31 21:41:04 1996
+++ linux/drivers/net/eepro.c	Sun Feb  2 15:18:39 1997
@@ -128,7 +128,7 @@
 
 /* Information that need to be kept for each board. */
 struct eepro_local {
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	unsigned rx_start;
 	unsigned tx_start; /* start of the transmit chain */
 	int tx_last;  /* pointer to last packet in the transmit chain */
@@ -156,7 +156,7 @@
 static void 	eepro_rx(struct device *dev);
 static void 	eepro_transmit_interrupt(struct device *dev);
 static int	eepro_close(struct device *dev);
-static struct enet_statistics *eepro_get_stats(struct device *dev);
+static struct net_device_stats *eepro_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 static int read_eeprom(int ioaddr, int location);
@@ -846,7 +846,7 @@
 
 /* Get the current statistics.	This may be called with the card open or
    closed. */
-static struct enet_statistics *
+static struct net_device_stats *
 eepro_get_stats(struct device *dev)
 {
 	struct eepro_local *lp = (struct eepro_local *)dev->priv;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.1.24/linux/drivers/net/eexpress.c	Tue Dec 31 21:41:04 1996
+++ linux/drivers/net/eexpress.c	Sun Feb  2 15:18:39 1997
@@ -103,7 +103,7 @@
 
 struct net_local
 {
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	unsigned long init_time;     /* jiffies when eexp_hw_init586 called */
 	unsigned short rx_first;     /* first rx buf, same as RX_BUF_START */
 	unsigned short rx_last;      /* last rx buf */
@@ -189,7 +189,7 @@
 extern int express_probe(struct device *dev);
 static int eexp_open(struct device *dev);
 static int eexp_close(struct device *dev);
-static struct enet_statistics *eexp_stats(struct device *dev);
+static struct net_device_stats *eexp_stats(struct device *dev);
 static int eexp_xmit(struct sk_buff *buf, struct device *dev);
 
 static void eexp_irq(int irq, void *dev_addr, struct pt_regs *regs);
@@ -358,7 +358,7 @@
  * Return interface stats
  */
 
-static struct enet_statistics *eexp_stats(struct device *dev)
+static struct net_device_stats *eexp_stats(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v2.1.24/linux/drivers/net/eql.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/net/eql.c	Sun Feb  2 15:18:39 1997
@@ -155,7 +155,7 @@
 static int eql_ioctl(struct device *dev, struct ifreq *ifr, int cmd); /*  */
 static int eql_slave_xmit(struct sk_buff *skb, struct device *dev); /*  */
 
-static struct enet_statistics *eql_get_stats(struct device *dev); /*  */
+static struct net_device_stats *eql_get_stats(struct device *dev); /*  */
 
 /* ioctl() handlers
    ---------------- */
@@ -225,14 +225,14 @@
 	memset (dev->priv, 0, sizeof (equalizer_t));
 	eql = (equalizer_t *) dev->priv;
 
-	eql->stats = kmalloc (sizeof (struct enet_statistics), GFP_KERNEL);
+	eql->stats = kmalloc (sizeof (struct net_device_stats), GFP_KERNEL);
 	if (eql->stats == NULL) 
 	{
 		kfree(dev->priv);
 		dev->priv = NULL;
 		return -ENOMEM;
 	}
-	memset (eql->stats, 0, sizeof (struct enet_statistics));
+	memset (eql->stats, 0, sizeof (struct net_device_stats));
 
 	init_timer (&eql->timer);
 	eql->timer.data     	= (unsigned long) dev->priv;
@@ -398,7 +398,7 @@
 }
 
 
-static struct enet_statistics * eql_get_stats(struct device *dev)
+static struct net_device_stats * eql_get_stats(struct device *dev)
 {
 	equalizer_t *eql = (equalizer_t *) dev->priv;
 	return eql->stats;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.1.24/linux/drivers/net/eth16i.c	Tue Dec 31 21:41:04 1996
+++ linux/drivers/net/eth16i.c	Sun Feb  2 15:18:39 1997
@@ -275,21 +275,30 @@
 #define RESET                  ID_ROM_0
 
 /* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] =
-   { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 };
+static unsigned int eth16i_portlist[] = {
+	0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
+};
 
-static unsigned int eth32i_portlist[] =
-   { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
-     0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 };
+static unsigned int eth32i_portlist[] = {
+	0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
+	0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
+};
 
 /* This is the Interrupt lookup table for Eth16i card */
-static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15 };
+static unsigned int eth16i_irqmap[] = {
+	9, 10, 5, 15
+};
 
 /* This is the Interrupt lookup table for Eth32i card */
-static unsigned int eth32i_irqmap[] = { 3, 5, 7, 9, 10, 11, 12, 15 };
+static unsigned int eth32i_irqmap[] = {
+	3, 5, 7, 9, 10, 11, 12, 15
+};
+
 #define EISA_IRQ_REG	0xc89
 
-static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 };
+static unsigned int eth16i_tx_buf_map[] = {
+	2048, 2048, 4096, 8192 
+};
 unsigned int boot = 1;
 
 /* Use 0 for production, 1 for verification, >2 for debug */
@@ -299,13 +308,14 @@
 static unsigned int eth16i_debug = ETH16I_DEBUG;
 
 /* Information for each board */
-struct eth16i_local {
-  struct enet_statistics stats;
-  unsigned int tx_started:1;
-  unsigned char tx_queue;         /* Number of packets in transmit buffer */
-  unsigned short tx_queue_len;
-  unsigned int tx_buf_size;
-  unsigned long open_time;
+struct eth16i_local
+{
+	struct net_device_stats stats;
+	unsigned int tx_started:1;
+	unsigned char tx_queue;	       /* Number of packets in transmit buffer */
+	unsigned short tx_queue_len;
+	unsigned int tx_buf_size;
+	unsigned long open_time;
 };
 
 /* Function prototypes */
@@ -330,7 +340,7 @@
 static void eth16i_multicast(struct device *dev);
 static void eth16i_select_regbank(unsigned char regbank, short ioaddr);
 static void eth16i_initialize(struct device *dev);
-static struct enet_statistics *eth16i_get_stats(struct device *dev);
+static struct net_device_stats *eth16i_get_stats(struct device *dev);
 
 static char *cardname = "ICL EtherTeam 16i/32";
 
@@ -342,837 +352,845 @@
 #else  /* Not HAVE_DEVLIST */
 int eth16i_probe(struct device *dev)
 {
-  int i;
-  int ioaddr;
-  int base_addr = dev ? dev->base_addr : 0;
-
-  if(eth16i_debug > 4)
-    printk("Probing started for %s\n", cardname);
-
-  if(base_addr > 0x1ff)           /* Check only single location */
-    return eth16i_probe1(dev, base_addr);
-  else if(base_addr != 0)         /* Don't probe at all */
-    return ENXIO;
-
-  /* Seek card from the ISA io address space */
-  for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++) {
-    if(check_region(ioaddr, ETH16I_IO_EXTENT))
-      continue;
-    if(eth16i_probe1(dev, ioaddr) == 0)
-      return 0;
-  }
-
-  /* Seek card from the EISA io address space */
-  for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++) {
-    if(check_region(ioaddr, ETH16I_IO_EXTENT))
+	int i;
+	int ioaddr;
+	int base_addr = dev ? dev->base_addr : 0;
+
+	if(eth16i_debug > 4)
+		printk("Probing started for %s\n", cardname);
+
+	if(base_addr > 0x1ff)		/* Check only single location */
+		return eth16i_probe1(dev, base_addr);
+	else if(base_addr != 0)		/* Don't probe at all */
+		return ENXIO;
+
+	/* Seek card from the ISA io address space */
+	for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++) {
+		if(check_region(ioaddr, ETH16I_IO_EXTENT))
+			continue;
+		if(eth16i_probe1(dev, ioaddr) == 0)
+			return 0;
+	}
+
+	/* Seek card from the EISA io address space */
+	for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++) {
+		if(check_region(ioaddr, ETH16I_IO_EXTENT))
 	continue;
-    if(eth16i_probe1(dev, ioaddr) == 0)
+		if(eth16i_probe1(dev, ioaddr) == 0)
 	return 0;
-   }
+	 }
 
-  return ENODEV;
+	return ENODEV;
 }
-#endif  /* Not HAVE_DEVLIST */
+#endif	/* Not HAVE_DEVLIST */
 
 static int eth16i_probe1(struct device *dev, short ioaddr)
 {
-  static unsigned version_printed = 0;
-  unsigned int irq = 0;
-  boot = 1;          /* To inform initialization that we are in boot probe */
-
-  /*
-     The MB86985 chip has on register which holds information in which
-     io address the chip lies. First read this register and compare
-     it to our current io address and if match then this could
-     be our chip.
-  */
-
-  if(ioaddr < 0x1000) {
-    if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)] != ioaddr)
-      return -ENODEV;
-  }
-
-  /* Now we will go a bit deeper and try to find the chip's signature */
-
-  if(eth16i_check_signature(ioaddr) != 0) /* Can we find the signature here */
-    return -ENODEV;
-
-  /*
-     Now it seems that we have found an ethernet chip in this particular
-     ioaddr. The MB86985 chip has this feature, that when you read a
-     certain register it will increase its io base address to next
-     configurable slot. Now when we have found the chip, first thing is
-     to make sure that the chip's ioaddr will hold still here.
-  */
-
-  eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-  outb(0x00, ioaddr + TRANSCEIVER_MODE_REG);
-
-  outb(0x00, ioaddr + RESET);             /* Will reset some parts of chip */
-  BITSET(ioaddr + CONFIG_REG_0, BIT(7));  /* This will disable the data link */
-
-  if(dev == NULL)
-    dev = init_etherdev(0, sizeof(struct eth16i_local));
-
-  if( (eth16i_debug & version_printed++) == 0)
-    printk(version);
-
-  dev->base_addr = ioaddr;
-
-  irq = eth16i_get_irq(ioaddr);
-  dev->irq = irq;
-
-  /* Try to obtain interrupt vector */
-  if(request_irq(dev->irq, &eth16i_interrupt, 0, "eth16i", NULL)) {
-    printk("%s: %s at %#3x, but is unusable due
-           conflict on IRQ %d.\n", dev->name, cardname, ioaddr, irq);
-    return EAGAIN;
-  }
+	static unsigned version_printed = 0;
+	unsigned int irq = 0;
+	boot = 1;          /* To inform initialization that we are in boot probe */
+
+	/*
+		 The MB86985 chip has on register which holds information in which
+		 io address the chip lies. First read this register and compare
+		 it to our current io address and if match then this could
+		 be our chip.
+	*/
+
+	if(ioaddr < 0x1000) {
+		if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)] != ioaddr)
+			return -ENODEV;
+	}
+
+	/* Now we will go a bit deeper and try to find the chip's signature */
+
+	if(eth16i_check_signature(ioaddr) != 0) /* Can we find the signature here */
+		return -ENODEV;
+
+	/*
+		 Now it seems that we have found an ethernet chip in this particular
+		 ioaddr. The MB86985 chip has this feature, that when you read a
+		 certain register it will increase its io base address to next
+		 configurable slot. Now when we have found the chip, first thing is
+		 to make sure that the chip's ioaddr will hold still here.
+	*/
+
+	eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
+	outb(0x00, ioaddr + TRANSCEIVER_MODE_REG);
+
+	outb(0x00, ioaddr + RESET);             /* Will reset some parts of chip */
+	BITSET(ioaddr + CONFIG_REG_0, BIT(7));  /* This will disable the data link */
+
+	if(dev == NULL)
+		dev = init_etherdev(0, sizeof(struct eth16i_local));
+
+	if( (eth16i_debug & version_printed++) == 0)
+		printk(version);
+
+	dev->base_addr = ioaddr;
+
+	irq = eth16i_get_irq(ioaddr);
+	dev->irq = irq;
+
+	/* Try to obtain interrupt vector */
+	if(request_irq(dev->irq, &eth16i_interrupt, 0, "eth16i", NULL)) {
+		printk("%s: %s at %#3x, but is unusable due
+		       conflict on IRQ %d.\n", dev->name, cardname, ioaddr, irq);
+		return EAGAIN;
+	}
 
-  printk("%s: %s at %#3x, IRQ %d, ",
+	printk("%s: %s at %#3x, IRQ %d, ",
 	 dev->name, cardname, ioaddr, dev->irq);
 
-  /* Let's grab the region */
-  request_region(ioaddr, ETH16I_IO_EXTENT, "eth16i");
+	/* Let's grab the region */
+	request_region(ioaddr, ETH16I_IO_EXTENT, "eth16i");
 
-  /* Now we will have to lock the chip's io address */
-  eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-  outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
+	/* Now we will have to lock the chip's io address */
+	eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
+	outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
 
-  eth16i_initialize(dev);   /* Initialize rest of the chip's registers */
+	eth16i_initialize(dev);	 /* Initialize rest of the chip's registers */
 
-  /* Now let's same some energy by shutting down the chip ;) */
-  BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
+	/* Now let's same some energy by shutting down the chip ;) */
+	BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
 
-  /* Initialize the device structure */
-  if(dev->priv == NULL)
-    dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL);
-  memset(dev->priv, 0, sizeof(struct eth16i_local));
+	/* Initialize the device structure */
+	if(dev->priv == NULL)
+		dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct eth16i_local));
 
-  dev->open               = eth16i_open;
-  dev->stop               = eth16i_close;
-  dev->hard_start_xmit    = eth16i_tx;
-  dev->get_stats          = eth16i_get_stats;
-  dev->set_multicast_list = &eth16i_multicast;
+	dev->open               = eth16i_open;
+	dev->stop               = eth16i_close;
+	dev->hard_start_xmit    = eth16i_tx;
+	dev->get_stats          = eth16i_get_stats;
+	dev->set_multicast_list = &eth16i_multicast;
 
-  /* Fill in the fields of the device structure with ethernet values. */
-  ether_setup(dev);
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
 
-  boot = 0;
+	boot = 0;
 
-  return 0;
+	return 0;
 }
 
 
 static void eth16i_initialize(struct device *dev)
 {
-  short ioaddr = dev->base_addr;
-  int i, node_w = 0;
-  unsigned char node_byte = 0;
-
-  /* Setup station address */
-  eth16i_select_regbank(NODE_ID_RB, ioaddr);
-  for(i = 0 ; i < 3 ; i++) {
-    unsigned short node_val = eth16i_read_eeprom(ioaddr, E_NODEID_0 + i);
-    ((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
-  }
+	short ioaddr = dev->base_addr;
+	int i, node_w = 0;
+	unsigned char node_byte = 0;
+
+	/* Setup station address */
+	eth16i_select_regbank(NODE_ID_RB, ioaddr);
+	for(i = 0 ; i < 3 ; i++) {
+		unsigned short node_val = eth16i_read_eeprom(ioaddr, E_NODEID_0 + i);
+		((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
+	}
 
-  for(i = 0; i < 6; i++) {
-    outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
-    if(boot) {
-      printk("%02x", inb(ioaddr + NODE_ID_0 + i));
-      if(i != 5)
-	printk(":");
-    }
-  }
+	for(i = 0; i < 6; i++) 
+	{
+		outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
+		if(boot) 
+		{
+			printk("%02x", inb(ioaddr + NODE_ID_0 + i));
+			if(i != 5)
+				printk(":");
+		}
+	}
 
-  /* Now we will set multicast addresses to accept none */
-  eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
-  for(i = 0; i < 8; i++)
-    outb(0x00, ioaddr + HASH_TABLE_0 + i);
+	/* Now we will set multicast addresses to accept none */
+	eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
+	for(i = 0; i < 8; i++)
+		outb(0x00, ioaddr + HASH_TABLE_0 + i);
 
-  /*
-     Now let's disable the transmitter and receiver, set the buffer ram
-     cycle time, bus width and buffer data path width. Also we shall
-     set transmit buffer size and total buffer size.
-  */
+	/*
+		 Now let's disable the transmitter and receiver, set the buffer ram
+		 cycle time, bus width and buffer data path width. Also we shall
+		 set transmit buffer size and total buffer size.
+	*/
 
-  eth16i_select_regbank(2, ioaddr);
+	eth16i_select_regbank(2, ioaddr);
 
-  node_byte = 0;
-  node_w = eth16i_read_eeprom(ioaddr, E_PRODUCT_CFG);
+	node_byte = 0;
+	node_w = eth16i_read_eeprom(ioaddr, E_PRODUCT_CFG);
 
-  if( (node_w & 0xFF00) == 0x0800)
-    node_byte |= BUFFER_WIDTH_8;
+	if( (node_w & 0xFF00) == 0x0800)
+		node_byte |= BUFFER_WIDTH_8;
 
-  node_byte |= MBS1;
+	node_byte |= MBS1;
 
-  if( (node_w & 0x00FF) == 64)
-    node_byte |= MBS0;
+	if( (node_w & 0x00FF) == 64)
+		node_byte |= MBS0;
 
-  node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2);
+	node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2);
 
-  outb(node_byte, ioaddr + CONFIG_REG_0);
+	outb(node_byte, ioaddr + CONFIG_REG_0);
 
-  /* We shall halt the transmitting, if 16 collisions are detected */
-  outb(RETRANS_AND_HALT_ON_16, ioaddr + COL_16_REG);
+	/* We shall halt the transmitting, if 16 collisions are detected */
+	outb(RETRANS_AND_HALT_ON_16, ioaddr + COL_16_REG);
 
-  if(boot) /* Now set port type */
-  {
-    char *porttype[] = {"BNC", "DIX", "TP", "AUTO"};
+	if(boot) /* Now set port type */
+	{
+		char *porttype[] = {"BNC", "DIX", "TP", "AUTO"};
 
-    ushort ptype = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
-    dev->if_port = (ptype & 0x00FF);
+		ushort ptype = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
+		dev->if_port = (ptype & 0x00FF);
 
-    printk(" %s interface.\n", porttype[dev->if_port]);
+		printk(" %s interface.\n", porttype[dev->if_port]);
 
-    if(ptype == E_PORT_AUTO)
-      ptype = eth16i_probe_port(ioaddr);
+		if(ptype == E_PORT_AUTO)
+			ptype = eth16i_probe_port(ioaddr);
 
-    eth16i_set_port(ioaddr, ptype);
-  }
+		eth16i_set_port(ioaddr, ptype);
+	}
 
-  /* Set Receive Mode to normal operation */
-  outb(MODE_2, ioaddr + RECEIVE_MODE_REG);
+	/* Set Receive Mode to normal operation */
+	outb(MODE_2, ioaddr + RECEIVE_MODE_REG);
 }
 
 static int eth16i_probe_port(short ioaddr)
 {
-  int i;
-  int retcode;
-  unsigned char dummy_packet[64] = { 0 };
-
-  /* Powerup the chip */
-  outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
-
-  BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-
-  eth16i_select_regbank(NODE_ID_RB, ioaddr);
-
-  for(i = 0; i < 6; i++) {
-    dummy_packet[i] = inb(ioaddr + NODE_ID_0 + i);
-    dummy_packet[i+6] = inb(ioaddr + NODE_ID_0 + i);
-  }
-
-  dummy_packet[12] = 0x00;
-  dummy_packet[13] = 0x04;
-
-  eth16i_select_regbank(2, ioaddr);
-
-  for(i = 0; i < 3; i++) {
-    BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-    BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
-    eth16i_set_port(ioaddr, i);
-
-    if(eth16i_debug > 1)
-    	printk("Set port number %d\n", i);
-
-    retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64);
-    if(retcode == 0) {
-      retcode = eth16i_receive_probe_packet(ioaddr);
-      if(retcode != -1) {
-	if(eth16i_debug > 1)
-		printk("Eth16i interface port found at %d\n", i);
-	return i;
-      }
-    }
-    else {
-      if(eth16i_debug > 1)
-      	printk("TRANSMIT_DONE timeout\n");
-    }
-  }
+	int i;
+	int retcode;
+	unsigned char dummy_packet[64] = { 0 };
 
-  if( eth16i_debug > 1)
-  	printk("Using default port\n");
+	/* Powerup the chip */
+	outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
 
- return E_PORT_BNC;
-}
+	BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
 
-static void eth16i_set_port(short ioaddr, int porttype)
-{
-    unsigned short temp = 0;
+	eth16i_select_regbank(NODE_ID_RB, ioaddr);
+
+	for(i = 0; i < 6; i++) {
+		dummy_packet[i] = inb(ioaddr + NODE_ID_0 + i);
+		dummy_packet[i+6] = inb(ioaddr + NODE_ID_0 + i);
+	}
 
-    eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-    outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG);
+	dummy_packet[12] = 0x00;
+	dummy_packet[13] = 0x04;
 
-    temp |= DIS_AUTO_PORT_SEL;
+	eth16i_select_regbank(2, ioaddr);
 
-    switch(porttype) {
+	for(i = 0; i < 3; i++) {
+		BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+		BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+		eth16i_set_port(ioaddr, i);
+
+		if(eth16i_debug > 1)
+			printk("Set port number %d\n", i);
+
+		retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64);
+		if(retcode == 0) 
+		{
+			retcode = eth16i_receive_probe_packet(ioaddr);
+			if(retcode != -1) 
+			{
+				if(eth16i_debug > 1)
+					printk("Eth16i interface port found at %d\n", i);
+				return i;
+			}
+		}
+		else {
+			if(eth16i_debug > 1)
+				printk("TRANSMIT_DONE timeout\n");
+		}
+	}
 
-    case E_PORT_BNC :
-      temp |= AUI_SELECT;
-      break;
+	if( eth16i_debug > 1)
+		printk("Using default port\n");
 
-    case E_PORT_TP :
-      break;
+	return E_PORT_BNC;
+}
 
-    case E_PORT_DIX :
-      temp |= AUI_SELECT;
-      BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
-      break;
-    }
-    outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
+static void eth16i_set_port(short ioaddr, int porttype)
+{
+	unsigned short temp = 0;
+
+	eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
+	outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG);
+
+	temp |= DIS_AUTO_PORT_SEL;
+	switch(porttype) 
+	{
+
+		case E_PORT_BNC :
+			temp |= AUI_SELECT;
+			break;
+
+		case E_PORT_TP :
+			break;
+
+		case E_PORT_DIX :
+			temp |= AUI_SELECT;
+			BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
+			break;
+	}
+	outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
 
-    if(eth16i_debug > 1) {
-    	printk("TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
-    	printk("TRANSCEIVER_MODE_REG = %x\n", inb(ioaddr+TRANSCEIVER_MODE_REG));
-    }
+	if(eth16i_debug > 1) {
+		printk("TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
+		printk("TRANSCEIVER_MODE_REG = %x\n", inb(ioaddr+TRANSCEIVER_MODE_REG));
+	}
 }
 
 static int eth16i_send_probe_packet(short ioaddr, unsigned char *b, int l)
 {
-  int starttime;
-
-  outb(0xff, ioaddr + TX_STATUS_REG);
+	int starttime;
 
-  outw(l, ioaddr + DATAPORT);
-  outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
+	outb(0xff, ioaddr + TX_STATUS_REG);
 
-  starttime = jiffies;
-  outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
+	outw(l, ioaddr + DATAPORT);
+	outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
 
-  while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) {
-    if( (jiffies - starttime) > TIMEOUT_TICKS) {
-      break;
-    }
-  }
+	starttime = jiffies;
+	outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
 
-  return(0);
+	while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) 
+		if( (jiffies - starttime) > TIMEOUT_TICKS)
+			break;
+	return(0);
 }
 
 static int eth16i_receive_probe_packet(short ioaddr)
 {
-  int starttime;
+	int starttime;
 
-  starttime = jiffies;
+	starttime = jiffies;
 
-  while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) {
-    if( (jiffies - starttime) > TIMEOUT_TICKS) {
+	while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) 
+	{
+		if( (jiffies - starttime) > TIMEOUT_TICKS) 
+		{
+			if(eth16i_debug > 1)
+				printk("Timeout occurred waiting transmit packet received\n");
+			starttime = jiffies;
+			while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) 
+			{
+				if( (jiffies - starttime) > TIMEOUT_TICKS) 
+				{
+					if(eth16i_debug > 1)
+						printk("Timeout occurred waiting receive packet\n");
+					return -1;
+				}
+			}
+
+			if(eth16i_debug > 1)
+				printk("RECEIVE_PACKET\n");
+			return(0); /* Found receive packet */
+		}
+	}
 
-      if(eth16i_debug > 1)
-	printk("Timeout occurred waiting transmit packet received\n");
-      starttime = jiffies;
-      while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) {
-	if( (jiffies - starttime) > TIMEOUT_TICKS) {
-	if(eth16i_debug > 1)
-	  printk("Timeout occurred waiting receive packet\n");
-        return -1;
-        }
-      }
-
-      if(eth16i_debug > 1)
-      	printk("RECEIVE_PACKET\n");
-      return(0); /* Found receive packet */
-    }
-  }
-
-  if(eth16i_debug > 1) {
-  	printk("TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
-  	printk("RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
-  }
+	if(eth16i_debug > 1) {
+		printk("TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
+		printk("RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
+	}
 
-  return(0); /* Return success */
+	return(0); /* Return success */
 }
 
 static int eth16i_get_irq(short ioaddr)
 {
-  unsigned char cbyte;
+	unsigned char cbyte;
 
-  if( ioaddr < 0x1000) {
-  	cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
+	if( ioaddr < 0x1000) {
+		cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
 	return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] );
-  } else {  /* Oh..the card is EISA so method getting IRQ different */
+	} else {	/* Oh..the card is EISA so method getting IRQ different */
 	unsigned short index = 0;
 	cbyte = inb(ioaddr + EISA_IRQ_REG);
 	while( (cbyte & 0x01) == 0) {
 		cbyte = cbyte >> 1;
 		index++;
-        }
+				}
 	return( eth32i_irqmap[ index ] );
-  }
+	}
 }
 
 static int eth16i_check_signature(short ioaddr)
 {
-  int i;
-  unsigned char creg[4] = { 0 };
+	int i;
+	unsigned char creg[4] = { 0 };
 
-  for(i = 0; i < 4 ; i++) {
+	for(i = 0; i < 4 ; i++) {
 
-    creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
+		creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
 
-    if(eth16i_debug > 1)
+		if(eth16i_debug > 1)
 	printk("eth16i: read signature byte %x at %x\n", creg[i],
-	       ioaddr + TRANSMIT_MODE_REG + i);
-  }
+				 ioaddr + TRANSMIT_MODE_REG + i);
+	}
 
-  creg[0] &= 0x0F;      /* Mask collision cnr */
-  creg[2] &= 0x7F;      /* Mask DCLEN bit */
+	creg[0] &= 0x0F;      /* Mask collision cnr */
+	creg[2] &= 0x7F;      /* Mask DCLEN bit */
 
 #ifdef 0
 /*
 	This was removed because the card was sometimes left to state
   	from which it couldn't be find anymore. If there is need
-	to more strict chech still this have to be fixed.
+	to have a more strict check still this have to be fixed.
 */
-  if( !( (creg[0] == 0x06) && (creg[1] == 0x41)) ) {
-    if(creg[1] != 0x42)
-      return -1;
-  }
+	if( !( (creg[0] == 0x06) && (creg[1] == 0x41)) ) {
+		if(creg[1] != 0x42)
+			return -1;
+	}
 #endif
 
-  if( !( (creg[2] == 0x36) && (creg[3] == 0xE0)) ) {
-      creg[2] &= 0x42;
-      creg[3] &= 0x03;
-
-      if( !( (creg[2] == 0x42) && (creg[3] == 0x00)) )
-	return -1;
-  }
-
-  if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
-    return -1;
-  if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
-    return -1;
+	if( !( (creg[2] == 0x36) && (creg[3] == 0xE0)) ) 
+	{
+		creg[2] &= 0x42;
+		creg[3] &= 0x03;
+
+		if( !( (creg[2] == 0x42) && (creg[3] == 0x00)) )
+			return -1;
+	}
+
+	if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
+		return -1;
+	if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
+		return -1;
 
-  return 0;
+	return 0;
 }
 
 static int eth16i_read_eeprom(int ioaddr, int offset)
 {
-  int data = 0;
+	int data = 0;
 
-  eth16i_eeprom_cmd(ioaddr, EEPROM_READ | offset);
-  outb(CS_1, ioaddr + EEPROM_CTRL_REG);
-  data = eth16i_read_eeprom_word(ioaddr);
-  outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
+	eth16i_eeprom_cmd(ioaddr, EEPROM_READ | offset);
+	outb(CS_1, ioaddr + EEPROM_CTRL_REG);
+	data = eth16i_read_eeprom_word(ioaddr);
+	outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
 
-  return(data);
+	return(data);
 }
 
 static int eth16i_read_eeprom_word(int ioaddr)
 {
-  int i;
-  int data = 0;
+	int i;
+	int data = 0;
 
-  for(i = 16; i > 0; i--) {
-    outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-    eeprom_slow_io();
-    outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-    eeprom_slow_io();
-    data = (data << 1) | ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
-    eeprom_slow_io();
-  }
+	for(i = 16; i > 0; i--) {
+		outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
+		eeprom_slow_io();
+		outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
+		eeprom_slow_io();
+		data = (data << 1) | ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
+		eeprom_slow_io();
+	}
 
-  return(data);
+	return(data);
 }
 
 static void eth16i_eeprom_cmd(int ioaddr, unsigned char command)
 {
-  int i;
+	int i;
 
-  outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
-  outb(DI_0, ioaddr + EEPROM_DATA_REG);
-  outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-  outb(DI_1, ioaddr + EEPROM_DATA_REG);
-  outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-
-  for(i = 7; i >= 0; i--) {
-    short cmd = ( (command & (1 << i)) ? DI_1 : DI_0 );
-    outb(cmd, ioaddr + EEPROM_DATA_REG);
-    outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-    eeprom_slow_io();
-    outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-    eeprom_slow_io();
-  }
+	outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
+	outb(DI_0, ioaddr + EEPROM_DATA_REG);
+	outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
+	outb(DI_1, ioaddr + EEPROM_DATA_REG);
+	outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
+
+	for(i = 7; i >= 0; i--) {
+		short cmd = ( (command & (1 << i)) ? DI_1 : DI_0 );
+		outb(cmd, ioaddr + EEPROM_DATA_REG);
+		outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
+		eeprom_slow_io();
+		outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
+		eeprom_slow_io();
+	}
 }
 
 static int eth16i_open(struct device *dev)
 {
-  struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-  int ioaddr = dev->base_addr;
+	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	int ioaddr = dev->base_addr;
 
-  irq2dev_map[dev->irq] = dev;
+	irq2dev_map[dev->irq] = dev;
 
-  /* Powerup the chip */
-  outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
+	/* Powerup the chip */
+	outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
 
-  /* Initialize the chip */
-  eth16i_initialize(dev);
+	/* Initialize the chip */
+	eth16i_initialize(dev);
 
-  /* Set the transmit buffer size */
-  lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
+	/* Set the transmit buffer size */
+	lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
 
-  if(eth16i_debug > 3)
-    printk("%s: transmit buffer size %d\n", dev->name, lp->tx_buf_size);
+	if(eth16i_debug > 3)
+		printk("%s: transmit buffer size %d\n", dev->name, lp->tx_buf_size);
 
-  /* Now enable Transmitter and Receiver sections */
-  BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+	/* Now enable Transmitter and Receiver sections */
+	BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
 
-  /* Now switch to register bank 2, for run time operation */
-  eth16i_select_regbank(2, ioaddr);
+	/* Now switch to register bank 2, for run time operation */
+	eth16i_select_regbank(2, ioaddr);
 
-  lp->open_time = jiffies;
-  lp->tx_started = 0;
-  lp->tx_queue = 0;
-  lp->tx_queue_len = 0;
+	lp->open_time = jiffies;
+	lp->tx_started = 0;
+	lp->tx_queue = 0;
+	lp->tx_queue_len = 0;
 
-  /* Turn on interrupts*/
-  outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+	/* Turn on interrupts*/
+	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
 
-  dev->tbusy = 0;
-  dev->interrupt = 0;
-  dev->start = 1;
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
 
 #ifdef MODULE
-  MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 #endif
 
-  return 0;
+	return 0;
 }
 
 static int eth16i_close(struct device *dev)
 {
-  struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-  int ioaddr = dev->base_addr;
+	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	int ioaddr = dev->base_addr;
 
-  lp->open_time = 0;
+	lp->open_time = 0;
 
-  dev->tbusy = 1;
-  dev->start = 0;
+	dev->tbusy = 1;
+	dev->start = 0;
 
-  /* Disable transmit and receive */
-  BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+	/* Disable transmit and receive */
+	BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
 
-  /* Reset the chip */
-  outb(0xff, ioaddr + RESET);
+	/* Reset the chip */
+	outb(0xff, ioaddr + RESET);
 
-  /* Save some energy by switching off power */
-  BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
+	/* Save some energy by switching off power */
+	BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
 
 #ifdef MODULE
-  MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 #endif
 
-  return 0;
+	return 0;
 }
 
 static int eth16i_tx(struct sk_buff *skb, struct device *dev)
 {
-  struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-  int ioaddr = dev->base_addr;
+	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	int ioaddr = dev->base_addr;
 
-  if(dev->tbusy) {
-    /*
-       If we get here, some higher level has decided that we are broken.
-       There should really be a "kick me" function call instead.
-    */
-
-    int tickssofar = jiffies - dev->trans_start;
-    if(tickssofar < TIMEOUT_TICKS)  /* Let's not rush with our timeout, */
-      return 1;                     /* wait a couple of ticks first     */
-
-    printk("%s: transmit timed out with status %04x, %s ?\n", dev->name,
-	   inw(ioaddr + TX_STATUS_REG),
-	   (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
-	   "IRQ conflict" : "network cable problem");
-
-    /* Let's dump all registers */
-    if(eth16i_debug > 0) {
-      printk("%s: timeout regs: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
-	     dev->name, inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2),
-	     inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5),
-	     inb(ioaddr + 6), inb(ioaddr + 7));
-
-
-      printk("lp->tx_queue = %d\n", lp->tx_queue);
-      printk("lp->tx_queue_len = %d\n", lp->tx_queue_len);
-      printk("lp->tx_started = %d\n", lp->tx_started);
-
-    }
-
-    lp->stats.tx_errors++;
-
-    /* Now let's try to restart the adaptor */
-
-    BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-    outw(0xffff, ioaddr + RESET);
-    eth16i_initialize(dev);
-    outw(0xffff, ioaddr + TX_STATUS_REG);
-    BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
-
-    lp->tx_started = 0;
-    lp->tx_queue = 0;
-    lp->tx_queue_len = 0;
-
-    outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
-    dev->tbusy = 0;
-    dev->trans_start = jiffies;
-  }
-
-  /*
-     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 transmitter from overlapping. This could better be
-     done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-
-  /* Turn off TX interrupts */
-  outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
-  if(set_bit(0, (void *)&dev->tbusy) != 0)
-    printk("%s: Transmitter access conflict.\n", dev->name);
-  else {
-    short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-    unsigned char *buf = skb->data;
-
-    outw(length, ioaddr + DATAPORT);
-
-    if( ioaddr < 0x1000 )
-    	outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-    else {
-	unsigned char frag = length % 4;
-
-	outsl(ioaddr + DATAPORT, buf, length >> 2);
-
-	if( frag != 0 ) {
-	  outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
-	  if( frag == 3 )
-	    outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC) + 2), 1);
-	}
-    }
-
-    lp->tx_queue++;
-    lp->tx_queue_len += length + 2;
-
-    if(lp->tx_started == 0) {
-      /* If the transmitter is idle..always trigger a transmit */
-      outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
-      lp->tx_queue = 0;
-      lp->tx_queue_len = 0;
-      dev->trans_start = jiffies;
-      lp->tx_started = 1;
-      dev->tbusy = 0;
-    }
-    else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
-      /* There is still more room for one more packet in tx buffer */
-      dev->tbusy = 0;
-    }
-
-    outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
-    /* Turn TX interrupts back on */
-    /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
-  }
-  dev_kfree_skb(skb, FREE_WRITE);
+	if(dev->tbusy) {
+		/*
+			 If we get here, some higher level has decided that we are broken.
+			 There should really be a "kick me" function call instead.
+		*/
 
-  return 0;
-}
+		int tickssofar = jiffies - dev->trans_start;
+		if(tickssofar < TIMEOUT_TICKS)	/* Let's not rush with our timeout, */
+			return 1;                     /* wait a couple of ticks first     */
 
-static void eth16i_rx(struct device *dev)
-{
-  struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-  int ioaddr = dev->base_addr;
-  int boguscount = MAX_RX_LOOP;
-
-  /* Loop until all packets have been read */
-  while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) {
-
-    /* Read status byte from receive buffer */
-    ushort status = inw(ioaddr + DATAPORT);
-
-    if(eth16i_debug > 4)
-      printk("%s: Receiving packet mode %02x status %04x.\n",
-	     dev->name, inb(ioaddr + RECEIVE_MODE_REG), status);
-
-      if( !(status & PKT_GOOD) ) {
-	/* Hmm..something went wrong. Let's check what error occurred */
-	lp->stats.rx_errors++;
-	if( status & PKT_SHORT     ) lp->stats.rx_length_errors++;
-	if( status & PKT_ALIGN_ERR ) lp->stats.rx_frame_errors++;
-	if( status & PKT_CRC_ERR   ) lp->stats.rx_crc_errors++;
-	if( status & PKT_RX_BUF_OVERFLOW) lp->stats.rx_over_errors++;
-      }
-      else {   /* Ok so now we should have a good packet */
-	struct sk_buff *skb;
-
-	/* Get the size of the packet from receive buffer */
-	ushort pkt_len = inw(ioaddr + DATAPORT);
-
-	if(pkt_len > ETH_FRAME_LEN) {
-	  printk("%s: %s claimed a very large packet, size of %d bytes.\n",
-		 dev->name, cardname, pkt_len);
-	  outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
-	  lp->stats.rx_dropped++;
-	  break;
-	}
-
-	skb = dev_alloc_skb(pkt_len + 3);
-	if( skb == NULL ) {
-	  printk("%s: Couldn't allocate memory for packet (len %d)\n",
-		 dev->name, pkt_len);
-	  outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
-	  lp->stats.rx_dropped++;
-	  break;
+		printk("%s: transmit timed out with status %04x, %s ?\n", dev->name,
+		 inw(ioaddr + TX_STATUS_REG),
+		 (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
+		 "IRQ conflict" : "network cable problem");
+
+		/* Let's dump all registers */
+		if(eth16i_debug > 0) {
+			printk("%s: timeout regs: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+			 dev->name, inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2),
+			 inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5),
+			 inb(ioaddr + 6), inb(ioaddr + 7));
+
+
+			printk("lp->tx_queue = %d\n", lp->tx_queue);
+			printk("lp->tx_queue_len = %d\n", lp->tx_queue_len);
+			printk("lp->tx_started = %d\n", lp->tx_started);
+
+		}
+
+		lp->stats.tx_errors++;
+
+		/* Now let's try to restart the adaptor */
+
+		BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+		outw(0xffff, ioaddr + RESET);
+		eth16i_initialize(dev);
+		outw(0xffff, ioaddr + TX_STATUS_REG);
+		BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+
+		lp->tx_started = 0;
+		lp->tx_queue = 0;
+		lp->tx_queue_len = 0;
+
+		outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+
+		dev->tbusy = 0;
+		dev->trans_start = jiffies;
 	}
 
-	skb->dev = dev;
-	skb_reserve(skb,2);
-	/*
-	   Now let's get the packet out of buffer.
-	   size is (pkt_len + 1) >> 1, cause we are now reading words
-	   and it have to be even aligned.
-	*/
+	/* Block a timer based transmitter from overlapping. This could better be
+		 done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
 
-	if( ioaddr < 0x1000)
-	  insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), (pkt_len + 1) >> 1);
+	/* Turn off TX interrupts */
+	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+
+	if(set_bit(0, (void *)&dev->tbusy) != 0)
+		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
-	  unsigned char *buf = skb_put(skb, pkt_len);
-	  unsigned char frag = pkt_len % 4;
+		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		unsigned char *buf = skb->data;
+
+		outw(length, ioaddr + DATAPORT);
 
-	  insl(ioaddr + DATAPORT, buf, pkt_len >> 2);
+		if( ioaddr < 0x1000 )
+			outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+		else 
+		{
+			unsigned char frag = length % 4;
+
+			outsl(ioaddr + DATAPORT, buf, length >> 2);
+
+			if( frag != 0 ) 
+			{
+				outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
+				if( frag == 3 )
+					outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC) + 2), 1);
+			}
+		}
+
+		lp->tx_queue++;
+		lp->tx_queue_len += length + 2;
+
+		if(lp->tx_started == 0) {
+			/* If the transmitter is idle..always trigger a transmit */
+			outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
+			lp->tx_queue = 0;
+			lp->tx_queue_len = 0;
+			dev->trans_start = jiffies;
+			lp->tx_started = 1;
+			dev->tbusy = 0;
+		}
+		else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
+			/* There is still more room for one more packet in tx buffer */
+			dev->tbusy = 0;
+		}
 
-	  if(frag != 0) {
-	  	unsigned short rest[2];
-		rest[0] = inw( ioaddr + DATAPORT );
-		if(frag == 3)
-			rest[1] = inw( ioaddr + DATAPORT );
+		outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
 
-		memcpy(buf + (pkt_len & 0xfffc), (char *)rest, frag);
-	  }
+		/* Turn TX interrupts back on */
+		/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
 	}
+	dev_kfree_skb(skb, FREE_WRITE);
 
-        skb->protocol=eth_type_trans(skb, dev);
-	netif_rx(skb);
-	lp->stats.rx_packets++;
+	return 0;
+}
 
-	if( eth16i_debug > 5 ) {
-	  int i;
-	  printk("%s: Received packet of length %d.\n", dev->name, pkt_len);
-	  for(i = 0; i < 14; i++)
-	    printk(" %02x", skb->data[i]);
-	  printk(".\n");
-	}
+static void eth16i_rx(struct device *dev)
+{
+	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int boguscount = MAX_RX_LOOP;
+
+	/* Loop until all packets have been read */
+	while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) 
+	{
+		/* Read status byte from receive buffer */
+		ushort status = inw(ioaddr + DATAPORT);
+
+		if(eth16i_debug > 4)
+			printk("%s: Receiving packet mode %02x status %04x.\n",
+				dev->name, inb(ioaddr + RECEIVE_MODE_REG), status);
+
+		if( !(status & PKT_GOOD) ) 
+		{
+			/* Hmm..something went wrong. Let's check what error occurred */
+			lp->stats.rx_errors++;
+			if( status & PKT_SHORT)
+				lp->stats.rx_length_errors++;
+			if( status & PKT_ALIGN_ERR )
+				lp->stats.rx_frame_errors++;
+			if( status & PKT_CRC_ERR )
+				lp->stats.rx_crc_errors++;
+			if( status & PKT_RX_BUF_OVERFLOW)
+				lp->stats.rx_over_errors++;
+		}
+		else
+		{	 /* Ok so now we should have a good packet */
+			struct sk_buff *skb;
+			/* Get the size of the packet from receive buffer */
+			ushort pkt_len = inw(ioaddr + DATAPORT);
+
+			if(pkt_len > ETH_FRAME_LEN) 
+			{
+				printk("%s: %s claimed a very large packet, size of %d bytes.\n",
+				dev->name, cardname, pkt_len);
+				outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
+				lp->stats.rx_dropped++;
+				break;
+			}
+
+			skb = dev_alloc_skb(pkt_len + 3);
+			if( skb == NULL ) 
+			{
+				printk("%s: Couldn't allocate memory for packet (len %d)\n",
+				dev->name, pkt_len);
+				outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
+				lp->stats.rx_dropped++;
+				break;
+			}
+			skb->dev = dev;
+			skb_reserve(skb,2);
+			/*
+				Now let's get the packet out of buffer.
+				size is (pkt_len + 1) >> 1, cause we are now reading words
+				and it has to be even aligned.
+			*/
+
+			if( ioaddr < 0x1000)
+				insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), (pkt_len + 1) >> 1);
+			else 
+			{
+				unsigned char *buf = skb_put(skb, pkt_len);
+				unsigned char frag = pkt_len % 4;
+
+				insl(ioaddr + DATAPORT, buf, pkt_len >> 2);
+
+				if(frag != 0) 
+				{
+					unsigned short rest[2];
+					rest[0] = inw( ioaddr + DATAPORT );
+					if(frag == 3)
+						rest[1] = inw( ioaddr + DATAPORT );
+
+					memcpy(buf + (pkt_len & 0xfffc), (char *)rest, frag);
+				}
+			}
+
+			skb->protocol=eth_type_trans(skb, dev);
+			netif_rx(skb);
+			lp->stats.rx_packets++;
+
+			if( eth16i_debug > 5 ) 
+			{
+				int i;
+				printk("%s: Received packet of length %d.\n", dev->name, pkt_len);
+				for(i = 0; i < 14; i++)
+					printk(" %02x", skb->data[i]);
+				printk(".\n");
+			}
 
-      } /* else */
+		} /* else */
 
-    if(--boguscount <= 0)
-      break;
+		if(--boguscount <= 0)
+			break;
 
-  } /* while */
+	} /* while */
 
 #if 0
-  {
-    int i;
+	{
+		int i;
+
+		for(i = 0; i < 20; i++) 
+		{
+			if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == RX_BUFFER_EMPTY)
+				break;
+			inw(ioaddr + DATAPORT);
+			outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
+		}
 
-    for(i = 0; i < 20; i++) {
-      if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == RX_BUFFER_EMPTY)
-	break;
-      inw(ioaddr + DATAPORT);
-      outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
-    }
-
-    if(eth16i_debug > 1)
-      printk("%s: Flushed receive buffer.\n", dev->name);
-  }
+		if(eth16i_debug > 1)
+			printk("%s: Flushed receive buffer.\n", dev->name);
+	}
 #endif
 
-  return;
+	return;
 }
 
 static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-  struct device *dev = (struct device *)(irq2dev_map[irq]);
-  struct eth16i_local *lp;
-  int ioaddr = 0,
-      status;
-
-  if(dev == NULL) {
-    printk("eth16i_interrupt(): irq %d for unknown device. \n", irq);
-    return;
-  }
-
-  /* Turn off all interrupts from adapter */
-  outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
-  dev->interrupt = 1;
-
-  ioaddr = dev->base_addr;
-  lp = (struct eth16i_local *)dev->priv;
-  status = inw(ioaddr + TX_STATUS_REG);      /* Get the status */
-  outw(status, ioaddr + TX_STATUS_REG);      /* Clear status bits */
-
-  if(eth16i_debug > 3)
-    printk("%s: Interrupt with status %04x.\n", dev->name, status);
-
-  if( status & 0x00ff ) {          /* Let's check the transmit status reg */
-
-    if(status & TX_DONE) {         /* The transmit has been done */
-      lp->stats.tx_packets++;
-
-      if(lp->tx_queue) {           /* Is there still packets ? */
-	  /* There was packet(s) so start transmitting and write also
-	   how many packets there is to be sent */
-	outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
-	lp->tx_queue = 0;
-	lp->tx_queue_len = 0;
-	dev->trans_start = jiffies;
-	dev->tbusy = 0;
-	mark_bh(NET_BH);
-      }
-      else {
-	lp->tx_started = 0;
-	dev->tbusy = 0;
-	mark_bh(NET_BH);
-      }
-    }
-  }
-
-  if( ( status & 0xff00 ) ||
-     ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
-    eth16i_rx(dev);  /* We have packet in receive buffer */
-  }
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	struct eth16i_local *lp;
+	int ioaddr = 0,
+			status;
+
+	if(dev == NULL) {
+		printk("eth16i_interrupt(): irq %d for unknown device. \n", irq);
+		return;
+	}
+
+	/* Turn off all interrupts from adapter */
+	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+
+	dev->interrupt = 1;
 
-  dev->interrupt = 0;
+	ioaddr = dev->base_addr;
+	lp = (struct eth16i_local *)dev->priv;
+	status = inw(ioaddr + TX_STATUS_REG);			/* Get the status */
+	outw(status, ioaddr + TX_STATUS_REG);			/* Clear status bits */
+
+	if(eth16i_debug > 3)
+		printk("%s: Interrupt with status %04x.\n", dev->name, status);
+
+	if( status & 0x00ff ) {			/* Let's check the transmit status reg */
+		if(status & TX_DONE) 
+		{	/* The transmit has been done */
+			lp->stats.tx_packets++; 
+			if(lp->tx_queue) 
+			{	/* Are there still packets ? */
+				/* There was packet(s) so start transmitting and write also
+				   how many packets there is to be sent */
+				outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
+				lp->tx_queue = 0;
+				lp->tx_queue_len = 0;
+				dev->trans_start = jiffies;
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+			else 
+			{
+				lp->tx_started = 0;
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+		}
+	}
+
+	if( ( status & 0xff00 ) ||
+		 ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
+		eth16i_rx(dev);	/* We have packet in receive buffer */
+	}
 
-  /* Turn interrupts back on */
-  outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+	dev->interrupt = 0;
 
-  return;
+	/* Turn interrupts back on */
+	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+
+	return;
 }
 
 static void eth16i_multicast(struct device *dev)
 {
-  short ioaddr = dev->base_addr;
+	short ioaddr = dev->base_addr;
 
-  if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
-  {
-    dev->flags|=IFF_PROMISC;	/* Must do this */
-    outb(3, ioaddr + RECEIVE_MODE_REG);
-  } else {
-    outb(2, ioaddr + RECEIVE_MODE_REG);
-  }
+	if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
+	{
+		dev->flags|=IFF_PROMISC;	/* Must do this */
+		outb(3, ioaddr + RECEIVE_MODE_REG);
+	} else {
+		outb(2, ioaddr + RECEIVE_MODE_REG);
+	}
 }
 
-static struct enet_statistics *eth16i_get_stats(struct device *dev)
+static struct net_device_stats *eth16i_get_stats(struct device *dev)
 {
-  struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
 
-  return &lp->stats;
+	return &lp->stats;
 }
 
 static void eth16i_select_regbank(unsigned char banknbr, short ioaddr)
 {
-  unsigned char data;
+	unsigned char data;
 
-  data = inb(ioaddr + CONFIG_REG_1);
-  outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
+	data = inb(ioaddr + CONFIG_REG_1);
+	outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
 }
 
 #ifdef MODULE
@@ -1181,7 +1199,8 @@
 	devicename,
 	0, 0, 0, 0,
 	0, 0,
-	0, 0, 0, NULL, eth16i_probe };
+	0, 0, 0, NULL, eth16i_probe
+};
 
 int io = 0x2a0;
 int irq = 0;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v2.1.24/linux/drivers/net/ewrk3.c	Tue Dec 31 21:41:04 1996
+++ linux/drivers/net/ewrk3.c	Sun Feb  2 15:18:40 1997
@@ -257,7 +257,7 @@
     char adapter_name[80];              /* Name exported to /proc/ioports */
     u_long shmem_base;                  /* Shared memory start address */
     u_long shmem_length;                /* Shared memory window length */
-    struct enet_statistics stats;       /* Public stats */
+    struct net_device_stats stats;       /* Public stats */
     struct {
       u32 bins[EWRK3_PKT_STAT_SZ]; /* Private stats counters */
       u32 unicast;
@@ -291,7 +291,7 @@
 static int    ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev);
 static void   ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int    ewrk3_close(struct device *dev);
-static struct enet_statistics *ewrk3_get_stats(struct device *dev);
+static struct net_device_stats *ewrk3_get_stats(struct device *dev);
 static void   set_multicast_list(struct device *dev);
 static int    ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd);
 
@@ -1159,21 +1159,18 @@
   return 0;
 }
 
-static struct enet_statistics *
-ewrk3_get_stats(struct device *dev)
+static struct net_device_stats *ewrk3_get_stats(struct device *dev)
 {
-  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
-
-  /* Null body since there is no framing error counter */
+	struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
 
-  return &lp->stats;
+	/* Null body since there is no framing error counter */
+	return &lp->stats;
 }
 
 /*
 ** Set or clear the multicast filter for this adapter.
 */
-static void
-set_multicast_list(struct device *dev)
+static void set_multicast_list(struct device *dev)
 {
   struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
   u_long iobase = dev->base_addr;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
--- v2.1.24/linux/drivers/net/fmv18x.c	Tue Dec 31 21:41:04 1996
+++ linux/drivers/net/fmv18x.c	Sun Feb  2 15:18:40 1997
@@ -70,7 +70,7 @@
 
 /* Information that need to be kept for each board. */
 struct net_local {
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	long open_time;				/* Useless example local info. */
 	uint tx_started:1;			/* Number of packet on the Tx queue. */
 	uchar tx_queue;				/* Number of packet on the Tx queue. */
@@ -113,7 +113,7 @@
 static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void net_rx(struct device *dev);
 static int net_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 
@@ -578,8 +578,7 @@
 
 /* Get the current statistics.	This may be called with the card open or
    closed. */
-static struct enet_statistics *
-net_get_stats(struct device *dev)
+static struct net_device_stats *net_get_stats(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 
@@ -596,8 +595,8 @@
    num_addrs > 0	Multicast mode, receive normal and MC packets, and do
 			best-effort filtering.
  */
-static void
-set_multicast_list(struct device *dev)
+ 
+static void set_multicast_list(struct device *dev)
 {
 	short ioaddr = dev->base_addr;
 	if (dev->mc_count || dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
diff -u --recursive --new-file v2.1.24/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c
--- v2.1.24/linux/drivers/net/hdlcdrv.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/net/hdlcdrv.c	Sun Feb  2 15:18:40 1997
@@ -518,7 +518,7 @@
 
 /* --------------------------------------------------------------------- */
 
-static struct enet_statistics *hdlcdrv_get_stats(struct device *dev)
+static struct net_device_stats *hdlcdrv_get_stats(struct device *dev)
 {
 	struct hdlcdrv_state *sm;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- v2.1.24/linux/drivers/net/hp100.c	Tue Dec 31 21:41:05 1996
+++ linux/drivers/net/hp100.c	Sun Feb  2 15:18:40 1997
@@ -151,7 +151,7 @@
   int hub_status;		    /* login to hub was successful? */
   u_char mac1_mode;
   u_char mac2_mode;
-  struct enet_statistics stats;
+  struct net_device_stats stats;
 };
 
 /*
@@ -192,7 +192,7 @@
 static int hp100_close( struct device *dev );
 static int hp100_start_xmit( struct sk_buff *skb, struct device *dev );
 static void hp100_rx( struct device *dev );
-static struct enet_statistics *hp100_get_stats( struct device *dev );
+static struct net_device_stats *hp100_get_stats( struct device *dev );
 static void hp100_update_stats( struct device *dev );
 static void hp100_clear_stats( int ioaddr );
 static void hp100_set_multicast_list( struct device *dev);
@@ -636,14 +636,6 @@
       return -EAGAIN;
     }
 
-  if ( skb == NULL )
-    {
-      dev_tint( dev );
-      return 0;
-    }
-
-  if ( skb -> len <= 0 ) return 0;
-
   for ( i = 0; i < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_TX_CMD ); i++ )
     {
 #ifdef HP100_DEBUG_TX
@@ -798,7 +790,7 @@
  *  statistics
  */
 
-static struct enet_statistics *hp100_get_stats( struct device *dev )
+static struct net_device_stats *hp100_get_stats( struct device *dev )
 {
   int ioaddr = dev -> base_addr;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/hydra.c linux/drivers/net/hydra.c
--- v2.1.24/linux/drivers/net/hydra.c	Sun Dec 22 16:37:33 1996
+++ linux/drivers/net/hydra.c	Sun Feb  2 15:18:40 1997
@@ -47,11 +47,11 @@
 #undef HYDRA_DEBUG        /* define this for (lots of) debugging information */
 
 #if 0                         /* currently hardwired to one transmit buffer */
- #define TX_RING_SIZE	5
- #define RX_RING_SIZE	16
+	#define TX_RING_SIZE	5
+	#define RX_RING_SIZE	16
 #else
- #define TX_RING_SIZE 1
- #define RX_RING_SIZE 8
+	#define TX_RING_SIZE 1
+	#define RX_RING_SIZE 8
 #endif
 
 #define ETHER_MIN_LEN 64
@@ -65,8 +65,8 @@
  * the CIA accesses here are uses to make sure the minimum time
  * requirement between NIC chip selects is met.
  */
-#define WRITE_REG(reg, val) (ciaa.pra, ((u_char)(*(nicbase+(reg))=val)))
-#define READ_REG(reg) (ciaa.pra, ((u_char)(*(nicbase+(reg)))))
+#define WRITE_REG(reg, val) (ciaa.pra, ((u8)(*(nicbase+(reg))=val)))
+#define READ_REG(reg) (ciaa.pra, ((u8)(*(nicbase+(reg)))))
 
 /* mask value for the interrupts we use */
 #define NIC_INTS (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW | ISR_CNT)
@@ -78,23 +78,23 @@
  *   Private Device Data
  */
 struct hydra_private
-    {
-    u_char *hydra_base;
-    u_char *hydra_nic_base;
-    u_short tx_page_start;
-    u_short rx_page_start;
-    u_short rx_page_stop;
-    u_short next_pkt;
-    struct enet_statistics stats;
-    int key;
-    };
+{
+	u8 *hydra_base;
+	u8 *hydra_nic_base;
+	u16 tx_page_start;
+	u16 rx_page_start;
+	u16 rx_page_stop;
+	u16 next_pkt;
+	struct net_device_stats stats;
+	int key;
+};
 
 static int hydra_open(struct device *dev);
 static int hydra_start_xmit(struct sk_buff *skb, struct device *dev);
 static void hydra_interrupt(int irq, void *data, struct pt_regs *fp);
-static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, volatile u_char *nicbase);
+static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, volatile u8 *nicbase);
 static int hydra_close(struct device *dev);
-static struct enet_statistics *hydra_get_stats(struct device *dev);
+static struct net_device_stats *hydra_get_stats(struct device *dev);
 #ifdef HAVE_MULTICAST
 static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
 #endif
@@ -106,8 +106,8 @@
 
 #if defined (__GNUC__) && defined (__mc68000__) && defined (USE_ASM)
 
-static __inline__ void *memcpyw(u_short *dest, u_short *src, int len)
-    {
+static __inline__ void *memcpyw(u16 *dest, u16 *src, int len)
+{
     __asm__("   move.l %0,%/a1; move.l %1,%/a0; move.l %2,%/d0 \n\t"
 	    "   cmpi.l #2,%/d0 \n\t"
 	    "1: bcs.s  2f \n\t"
@@ -133,462 +133,460 @@
 /* this one here relies on the fact that _writes_ to hydra memory   */
 /* are guaranteed to be of even length. (reads can be arbitrary)    */
 
-static void memcpyw(u_short *dest, u_short *src, int len)
+/*
+ *	FIXME: Surely we should be using the OS generic stuff and do
+ *
+ *	memcpy(dest,src,(len+1)&~1);
+ *
+ *	Can a 68K guy with this card check that ? - better yet
+ *	use a copy/checksum on it.
+ */
+ 
+static void memcpyw(u16 *dest, u16 *src, int len)
 {
-  if(len & 1)
-    len++;
+	if(len & 1)
+		len++;
 
-  while (len >= 2) {
-    *(dest++) = *(src++);
-    len -= 2;
-  }
-    
+	while (len >= 2) 
+	{
+		*(dest++) = *(src++);
+		len -= 2;
+	}
 }
 
 #endif
 
 int hydra_probe(struct device *dev)
-    {
-    struct hydra_private *priv;
-    u_long board;
-    int key;
-    struct ConfigDev *cd;
-    int j;
+{
+	struct hydra_private *priv;
+	u32 board;
+	int key;
+	struct ConfigDev *cd;
+	int j;
 
 #ifdef HYDRA_DEBUG
  printk("hydra_probe(%x)\n", dev);
 #endif
 
-    if ((key = zorro_find(MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, 0, 0))) {
-	cd = zorro_get_board(key);
-	if((board = (u_long) cd->cd_BoardAddr))
-	    {
-	    for(j = 0; j < ETHER_ADDR_LEN; j++)
-                dev->dev_addr[j] = *((u_char *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j));
+	if ((key = zorro_find(MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, 0, 0))) 
+	{
+		cd = zorro_get_board(key);
+		if((board = (u32) cd->cd_BoardAddr))
+		{
+			for(j = 0; j < ETHER_ADDR_LEN; j++)
+				dev->dev_addr[j] = *((u8 *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j));
 	    
-	    printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n",
-		   dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		   dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-
-	    init_etherdev(dev, 0);
+			printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n",
+				dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+				dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+			init_etherdev(dev, 0);
 	    
-	    dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL);
-	    priv = (struct hydra_private *)dev->priv;
-	    memset(priv, 0, sizeof(struct hydra_private));
+			dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL);
+			priv = (struct hydra_private *)dev->priv;
+			memset(priv, 0, sizeof(struct hydra_private));
 	    
-	    priv->hydra_base = (u_char *) ZTWO_VADDR(board);
-	    priv->hydra_nic_base = (u_char *) ZTWO_VADDR(board) + HYDRA_NIC_BASE;
-	    priv->key = key;
+			priv->hydra_base = (u8 *) ZTWO_VADDR(board);
+			priv->hydra_nic_base = (u8 *) ZTWO_VADDR(board) + HYDRA_NIC_BASE;
+			priv->key = key;
 	    
-	    dev->open = &hydra_open;
-	    dev->stop = &hydra_close;
-	    dev->hard_start_xmit = &hydra_start_xmit;
-	    dev->get_stats = &hydra_get_stats;
-#ifdef HAVE_MULTICAST
-	    dev->set_multicast_list = &hydra_set_multicast_list;
-#endif
-	    zorro_config_board(key, 0);
-	    return(0);
-            }
-        }
-    return(ENODEV);
-    }
+			dev->open = &hydra_open;
+			dev->stop = &hydra_close;
+			dev->hard_start_xmit = &hydra_start_xmit;
+			dev->get_stats = &hydra_get_stats;
+	 		dev->set_multicast_list = &hydra_set_multicast_list;
+	 		
+	 		/*
+	 		 *	Cannot yet do multicast
+	 		 */
+	 		dev->flags&=~IFF_MULTICAST;
+			zorro_config_board(key, 0);
+			return(0);
+		}
+	}
+	return(ENODEV);
+}
 
 
 static int hydra_open(struct device *dev)
-  {
-    struct hydra_private *priv = (struct hydra_private *)dev->priv;
-    volatile u_char *nicbase = priv->hydra_nic_base;
-#ifdef HAVE_MULTICAST
-    int i;
-#endif
+{
+	struct hydra_private *priv = (struct hydra_private *)dev->priv;
+	volatile u8 *nicbase = priv->hydra_nic_base;
+	int i;
     
 #ifdef HYDRA_DEBUG
- printk("hydra_open(0x%x)\n", dev);
+	printk("hydra_open(0x%x)\n", dev);
 #endif
 
-    /* first, initialize the private structure */
-    priv->tx_page_start = 0;   /* these are 256 byte buffers for NS8390 */
-    priv->rx_page_start = 6;
-    priv->rx_page_stop  = 62;  /* these values are hard coded for now */
+	/* first, initialize the private structure */
+	priv->tx_page_start = 0;   /* these are 256 byte buffers for NS8390 */
+	priv->rx_page_start = 6;
+	priv->rx_page_stop  = 62;  /* these values are hard coded for now */
 
-    /* Reset the NS8390 NIC */
-    WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+	 /* Reset the NS8390 NIC */
+	WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
 
-    /* be sure that the NIC is in stopped state */
-    while(!(READ_REG(NIC_ISR) & ISR_RST));
+	/* be sure that the NIC is in stopped state */
+	while(!(READ_REG(NIC_ISR) & ISR_RST));
 
-    /* word transfer, big endian bytes, loopback, FIFO threshold 4 bytes */
-    WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
+	/* word transfer, big endian bytes, loopback, FIFO threshold 4 bytes */
+	WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
 
-    /* clear remote byte count registers */
-    WRITE_REG(NIC_RBCR0, 0);
-    WRITE_REG(NIC_RBCR1, 0);
+	/* clear remote byte count registers */
+	WRITE_REG(NIC_RBCR0, 0);
+	WRITE_REG(NIC_RBCR1, 0);
 
-    /* accept packets addressed to this card and also broadcast packets */
-    WRITE_REG(NIC_RCR, NIC_RCRBITS);
+	/* accept packets addressed to this card and also broadcast packets */
+	WRITE_REG(NIC_RCR, NIC_RCRBITS);
 
-    /* enable loopback mode 1 */
-    WRITE_REG(NIC_TCR, TCR_LB1);
+	/* enable loopback mode 1 */
+	WRITE_REG(NIC_TCR, TCR_LB1);
 
-    /* initialize receive buffer ring */
-    WRITE_REG(NIC_PSTART, priv->rx_page_start);
-    WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
-    WRITE_REG(NIC_BNDRY, priv->rx_page_start);
+	/* initialize receive buffer ring */
+	WRITE_REG(NIC_PSTART, priv->rx_page_start);
+	WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
+	WRITE_REG(NIC_BNDRY, priv->rx_page_start);
 
-    /* clear interrupts */
-    WRITE_REG(NIC_ISR, 0xff);
+	/* clear interrupts */
+	WRITE_REG(NIC_ISR, 0xff);
 
-    /* enable interrupts */
-    WRITE_REG(NIC_IMR, NIC_INTS);
+	/* enable interrupts */
+	WRITE_REG(NIC_IMR, NIC_INTS);
 
-    /* set the ethernet hardware address */
-    WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_STOP); /* goto page 1 */
+	/* set the ethernet hardware address */
+	WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_STOP); /* goto page 1 */
 
-    WRITE_REG(NIC_PAR0, dev->dev_addr[0]);
-    WRITE_REG(NIC_PAR1, dev->dev_addr[1]);
-    WRITE_REG(NIC_PAR2, dev->dev_addr[2]);
-    WRITE_REG(NIC_PAR3, dev->dev_addr[3]);
-    WRITE_REG(NIC_PAR4, dev->dev_addr[4]);
-    WRITE_REG(NIC_PAR5, dev->dev_addr[5]);
+	WRITE_REG(NIC_PAR0, dev->dev_addr[0]);
+	WRITE_REG(NIC_PAR1, dev->dev_addr[1]);
+	WRITE_REG(NIC_PAR2, dev->dev_addr[2]);
+	WRITE_REG(NIC_PAR3, dev->dev_addr[3]);
+	WRITE_REG(NIC_PAR4, dev->dev_addr[4]);
+	WRITE_REG(NIC_PAR5, dev->dev_addr[5]);
 
-#ifdef HAVE_MULTICAST
-    /* clear multicast hash table */
-    for(i = 0; i < 8; i++)
-      WRITE_REG(NIC_MAR0 + 2*i, 0);
-#endif
+	/* clear multicast hash table */
+	for(i = 0; i < 8; i++)
+		WRITE_REG(NIC_MAR0 + 2*i, 0);
 
-    priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
-    WRITE_REG(NIC_CURR, priv->next_pkt);    /* set the next buf for current */
+	priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
+	WRITE_REG(NIC_CURR, priv->next_pkt);    /* set the next buf for current */
 
-    /* goto page 0, start NIC */
-    WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
+	/* goto page 0, start NIC */
+	WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
 
-    /* take interface out of loopback */
-    WRITE_REG(NIC_TCR, 0);
+	/* take interface out of loopback */
+	WRITE_REG(NIC_TCR, 0);
 
-    dev->tbusy = 0;
-    dev->interrupt = 0;
-    dev->start = 1;
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
     
-    if(request_irq(IRQ_AMIGA_PORTS, hydra_interrupt, 0, "Hydra Ethernet", dev))
-      return(-EAGAIN);
+	if(request_irq(IRQ_AMIGA_PORTS, hydra_interrupt, 0, "Hydra Ethernet", dev))
+		return(-EAGAIN);
 
-    MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 
-    return(0);
-  }
+	return(0);
+}
 
 
 static int hydra_close(struct device *dev)
 {
-  struct hydra_private *priv = (struct hydra_private *)dev->priv;
-  volatile u_char *nicbase = priv->hydra_nic_base;
-  int n = 5000;
+	struct hydra_private *priv = (struct hydra_private *)dev->priv;
+	volatile u8 *nicbase = priv->hydra_nic_base;
+	int n = 5000;
 
-  dev->start = 0;
-  dev->tbusy = 1;
+	dev->start = 0;
+	dev->tbusy = 1;
 
 #ifdef HYDRA_DEBUG
-  printk("%s: Shutting down ethercard\n", dev->name);
-  printk("%s: %d packets missed\n", dev->name, priv->stats.rx_missed_errors);
+	printk("%s: Shutting down ethercard\n", dev->name);
+	printk("%s: %d packets missed\n", dev->name, priv->stats.rx_missed_errors);
 #endif
 
-  WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+	WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
 
-  /* wait for NIC to stop (what a nice timeout..) */
-  while(((READ_REG(NIC_ISR) & ISR_RST) == 0) && --n);
+	/* wait for NIC to stop (what a nice timeout..) */
+	while(((READ_REG(NIC_ISR) & ISR_RST) == 0) && --n);
     
-  free_irq(IRQ_AMIGA_PORTS, dev);
+	free_irq(IRQ_AMIGA_PORTS, dev);
 
-  MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 
-  return(0);
+	return(0);
 }
 
 
 static void hydra_interrupt(int irq, void *data, struct pt_regs *fp)
-    {
-    volatile u_char *nicbase;
+{
+	volatile u8 *nicbase;
   
-    struct device *dev = (struct device *) data;
-    struct hydra_private *priv;
-    u_short intbits;
+	struct device *dev = (struct device *) data;
+	struct hydra_private *priv;
+	u16 intbits;
 
-    if(dev == NULL)
-        {
-        printk("hydra_interrupt(): irq for unknown device\n");
-        return;
-        }
+	if(dev == NULL)
+	{
+		printk("hydra_interrupt(): irq for unknown device\n");
+		return;
+	}
 
-/* this is not likely a problem - i think */
-    if(dev->interrupt)
-        printk("%s: re-entering the interrupt handler\n", dev->name);
+	/* this is not likely a problem - i think */
+	if(dev->interrupt)
+		printk("%s: re-entering the interrupt handler\n", dev->name);
 
-    dev->interrupt = 1;
+	dev->interrupt = 1;
 
-    priv = (struct hydra_private *) dev->priv;
-    nicbase = (u_char *) priv->hydra_nic_base;
+	priv = (struct hydra_private *) dev->priv;
+	nicbase = (u8 *) priv->hydra_nic_base;
 
-    /* select page 0 */
-    WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+	/* select page 0 */
+	WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
 
-    intbits = READ_REG(NIC_ISR) & NIC_INTS;
-    if(intbits == 0)
+	intbits = READ_REG(NIC_ISR) & NIC_INTS;
+	if(intbits == 0)
         {
-        dev->interrupt = 0;
-        return;
-        }
+		dev->interrupt = 0;
+		return;
+	}
 
 	/* acknowledge all interrupts, by clearing the interrupt flag */
 	WRITE_REG(NIC_ISR, intbits);
 
 	if((intbits & ISR_PTX) && !(intbits & ISR_TXE))
-	    {
-	    dev->tbusy = 0;
-	    mark_bh(NET_BH);
-	    }
+	{
+		dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
 	
 	if((intbits & ISR_PRX) && !(intbits & ISR_RXE))/* packet received OK */
-	      hydra_rx(dev, priv, nicbase);
+		hydra_rx(dev, priv, nicbase);
 
         if(intbits & ISR_TXE)
-	    priv->stats.tx_errors++;
+		priv->stats.tx_errors++;
 
         if(intbits & ISR_RXE)
-	    priv->stats.rx_errors++;
+		priv->stats.rx_errors++;
 
-	if(intbits & ISR_CNT) {
-	  /*
-	   * read the tally counters and (currently) ignore the values
-	   * might be useful because of bugs of some versions of the 8390 NIC
-	   */
+	if(intbits & ISR_CNT) 
+	{
+		/*
+		 * read the tally counters and (currently) ignore the values
+		 * might be useful because of bugs of some versions of the 8390 NIC
+		 */
 #ifdef HYDRA_DEBUG
-	  printk("hydra_interrupt(): ISR_CNT\n");
+		printk("hydra_interrupt(): ISR_CNT\n");
 #endif
-	  (void)READ_REG(NIC_CNTR0);
-	  (void)READ_REG(NIC_CNTR1);
-	  (void)READ_REG(NIC_CNTR2);
+		(void)READ_REG(NIC_CNTR0);
+		(void)READ_REG(NIC_CNTR1);
+		(void)READ_REG(NIC_CNTR2);
 	}
 	
 	if(intbits & ISR_OVW)
-	    {
-            #ifdef HYDRA_DEBUG
-	    WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+	{
+#ifdef HYDRA_DEBUG
+		WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
 /* another one just too much for me to comprehend - basically this could  */
 /* only occur because of invalid access to hydra ram, thus invalidating  */
 /* the interrupt bits read - in average usage these do not occur at all */
-	    printk("hydra_interrupt(): overwrite warning, NIC_ISR %02x, NIC_CURR %02x\n",
-		 intbits, READ_REG(NIC_CURR));
-	    WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
-            #endif
+		printk("hydra_interrupt(): overwrite warning, NIC_ISR %02x, NIC_CURR %02x\n",
+			intbits, READ_REG(NIC_CURR));
+		WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+#endif
 	    
 
-	    /* overwrite warning occurred, stop NIC & check the BOUNDARY pointer */
-	    /* FIXME - real overwrite handling needed !! */
+		/* overwrite warning occurred, stop NIC & check the BOUNDARY pointer */
+		/* FIXME - real overwrite handling needed !! */
 
-	    printk("hydra_interrupt(): overwrite warning, resetting NIC\n");
-	    WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
-	    while(!(READ_REG(NIC_ISR) & ISR_RST));
-	    /* wait for NIC to reset */
-	    WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
-	    WRITE_REG(NIC_RBCR0, 0);
-	    WRITE_REG(NIC_RBCR1, 0);
-	    WRITE_REG(NIC_RCR, NIC_RCRBITS);
-	    WRITE_REG(NIC_TCR, TCR_LB1);
-	    WRITE_REG(NIC_PSTART, priv->rx_page_start);
-	    WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
-	    WRITE_REG(NIC_BNDRY, priv->rx_page_start);
-	    WRITE_REG(NIC_ISR, 0xff);
-	    WRITE_REG(NIC_IMR, NIC_INTS);
-/* currently this _won't_ reset my hydra, even though it is */
-/* basically the same code as in the board init - any ideas? */
+		printk("hydra_interrupt(): overwrite warning, resetting NIC\n");
+		WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+		while(!(READ_REG(NIC_ISR) & ISR_RST));
+		/* wait for NIC to reset */
+		WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
+		WRITE_REG(NIC_RBCR0, 0);
+		WRITE_REG(NIC_RBCR1, 0);
+		WRITE_REG(NIC_RCR, NIC_RCRBITS);
+		WRITE_REG(NIC_TCR, TCR_LB1);
+		WRITE_REG(NIC_PSTART, priv->rx_page_start);
+		WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
+		WRITE_REG(NIC_BNDRY, priv->rx_page_start);
+		WRITE_REG(NIC_ISR, 0xff);
+		WRITE_REG(NIC_IMR, NIC_INTS);
+		/* currently this _won't_ reset my hydra, even though it is */
+		/* basically the same code as in the board init - any ideas? */
 
-	    priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
-	    WRITE_REG(NIC_CURR, priv->next_pkt);    /* set the next buf for current */
+		priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
+		WRITE_REG(NIC_CURR, priv->next_pkt);    /* set the next buf for current */
 	    
-	    WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
-	    
-	    WRITE_REG(NIC_TCR, 0);
-	    }
+		WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
 
-    dev->interrupt = 0;
-    return;
+		WRITE_REG(NIC_TCR, 0);
+	}
+
+	dev->interrupt = 0;
+	return;
     }
 
 
 /*
  * packet transmit routine
  */
+
 static int hydra_start_xmit(struct sk_buff *skb, struct device *dev)
-    {
-    struct hydra_private *priv = (struct hydra_private *)dev->priv;
-    volatile u_char *nicbase = priv->hydra_nic_base;
-    int len, len1;
+{
+	struct hydra_private *priv = (struct hydra_private *)dev->priv;
+	volatile u8 *nicbase = priv->hydra_nic_base;
+	int len, len1;
 
 	/* Transmitter timeout, serious problems. */
 
-    if(dev->tbusy)
+	if(dev->tbusy)
 	{
-        int tickssofar = jiffies - dev->trans_start;
-	if(tickssofar < 20)
-	    return(1);
-	WRITE_REG(NIC_CR, CR_STOP);
-	printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, 0);
-	priv->stats.tx_errors++;
-
-
-	dev->tbusy = 0;
-	dev->trans_start = jiffies;
-
-	return(0);
-	}
-
-
-    if(skb == NULL)
-        {
-	dev_tint(dev);
-	return(0);
+		int tickssofar = jiffies - dev->trans_start;
+		if(tickssofar < 20)
+			return(1);
+		WRITE_REG(NIC_CR, CR_STOP);
+		printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, 0);
+		priv->stats.tx_errors++;
+		dev->tbusy = 0;
+		dev->trans_start = jiffies;
+		return(0);
 	}
 
-    if((len = skb->len) <= 0)
-	return(0);
+	len=skb->len;
 
-    /* fill in a tx ring entry */
+	/* fill in a tx ring entry */
     
 #ifdef HYDRA_DEBUG
- printk("TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]);
+	printk("TX pkt type 0x%04x from ", ((u16 *)skb->data)[6]);
 	{
 		int i;
-		u_char *ptr = &((u_char *)skb->data)[6];
+		u8 *ptr = &((u8 *)skb->data)[6];
 		for (i = 0; i < 6; i++)
 			printk("%02x", ptr[i]);
 	}
 	printk(" to ");
 	{
 		int i;
-		u_char *ptr = (u_char *)skb->data;
+		u8 *ptr = (u8 *)skb->data;
 		for (i = 0; i < 6; i++)
 			printk("%02x", ptr[i]);
 	}
 	printk(" data 0x%08x len %d\n", (int)skb->data, len);
 #endif
 
-    /*
-     * make sure that the packet size is at least the minimum
-     * allowed ethernet packet length.
-     * (possibly should also clear the unused space...)
-     * note: minimum packet length is 64, including CRC
-     */
-    len1 = len;
-    if(len < (ETHER_MIN_LEN-4))
-	len = (ETHER_MIN_LEN-1);
-
-    /* make sure we've got an even number of bytes to copy to hydra's mem */
-    if(len & 1) len++;
-
-    if((u_long)(priv->hydra_base + (priv->tx_page_start << 8)) < 0x80000000)
-      printk("weirdness: memcpyw(txbuf, skbdata, len): txbuf = 0x%x\n", (u_int)(priv->hydra_base+(priv->tx_page_start<<8)));
-
-    /* copy the packet data to the transmit buffer
-       in the ethernet card RAM */
-    memcpyw((u_short *)(priv->hydra_base + (priv->tx_page_start << 8)),
-	    (u_short *)skb->data, len);
-    /* clear the unused space */
-/*    for(; len1<len; len1++)
-      (u_short)*(priv->hydra_base + (priv->tx_page_start<<8) + len1) = 0;
-*/
-    dev_kfree_skb(skb, FREE_WRITE);
-
-    priv->stats.tx_packets++;
-
-    cli();
-    /* make sure we are on the correct page */
-    WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
-
-    /* here we configure the transmit page start register etc */
-    /* notice that this code is hardwired to one transmit buffer */
-    WRITE_REG(NIC_TPSR, priv->tx_page_start);
-    WRITE_REG(NIC_TBCR0, len & 0xff);
-    WRITE_REG(NIC_TBCR1, len >> 8);
+	/*
+	 * make sure that the packet size is at least the minimum
+	 * allowed ethernet packet length.
+	 * (FIXME: Should also clear the unused space...)
+	 * note: minimum packet length is 64, including CRC
+	 */
+	len1 = len;
+
+	if(len < (ETHER_MIN_LEN-4))
+		len = (ETHER_MIN_LEN-1);
+
+	/* make sure we've got an even number of bytes to copy to hydra's mem */
+	if(len & 1) len++;
+
+	if((u32)(priv->hydra_base + (priv->tx_page_start << 8)) < 0x80000000)
+		printk("weirdness: memcpyw(txbuf, skbdata, len): txbuf = 0x%x\n", (u_int)(priv->hydra_base+(priv->tx_page_start<<8)));
+
+	/* copy the packet data to the transmit buffer 
+	   in the ethernet card RAM */
+	memcpyw((u16 *)(priv->hydra_base + (priv->tx_page_start << 8)),
+		(u16 *)skb->data, len);
+	/* clear the unused space */
+	for(; len1<len; len1++)
+		(u16)*(priv->hydra_base + (priv->tx_page_start<<8) + len1) = 0;
+	dev_kfree_skb(skb, FREE_WRITE);
+
+	priv->stats.tx_packets++;
+
+	cli();
+	/* make sure we are on the correct page */
+	WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
+
+	/* here we configure the transmit page start register etc */
+	/* notice that this code is hardwired to one transmit buffer */
+	WRITE_REG(NIC_TPSR, priv->tx_page_start);
+	WRITE_REG(NIC_TBCR0, len & 0xff);
+	WRITE_REG(NIC_TBCR1, len >> 8);
+
+	/* commit the packet to the wire */
+	WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA | CR_TXP);
+	sti();
 
-    /* commit the packet to the wire */
-    WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA | CR_TXP);
-    sti();
+	 dev->trans_start = jiffies;
 
-    dev->trans_start = jiffies;
-
-    return(0);
-    }
+	return(0);
+}
 
 
-static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, volatile u_char *nicbase)
-    {
-    volatile u_short *board_ram_ptr;
-    struct sk_buff *skb;
-    int hdr_next_pkt, pkt_len, len1, boundary;
+static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, volatile u8 *nicbase)
+{
+	volatile u16 *board_ram_ptr;
+	struct sk_buff *skb;
+	int hdr_next_pkt, pkt_len, len1, boundary;
 
 
-    /* remove packet(s) from the ring and commit them to TCP layer */
-    WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_START); /* page 1 */
-    while(priv->next_pkt != READ_REG(NIC_CURR)) /* should read this only once? */
-      {
-	board_ram_ptr = (u_short *)(priv->hydra_base + (priv->next_pkt << 8));
+	/* remove packet(s) from the ring and commit them to TCP layer */
+	WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_START); /* page 1 */
+	while(priv->next_pkt != READ_REG(NIC_CURR)) /* should read this only once? */
+	{
+		board_ram_ptr = (u16 *)(priv->hydra_base + (priv->next_pkt << 8));
 	
 #ifdef HYDRA_DEBUG
-	printk("next_pkt = 0x%x, board_ram_ptr = 0x%x\n", priv->next_pkt, board_ram_ptr);
+		printk("next_pkt = 0x%x, board_ram_ptr = 0x%x\n", priv->next_pkt, board_ram_ptr);
 #endif
 	
-	/* the following must be done with two steps, or
-	   GCC optimizes it to a byte access to Hydra memory,
-	   which doesn't work... */
-	hdr_next_pkt = board_ram_ptr[0];
-	hdr_next_pkt >>= 8;
+		/* the following must be done with two steps, or
+		   GCC optimizes it to a byte access to Hydra memory,
+		   which doesn't work... */
+		hdr_next_pkt = board_ram_ptr[0];
+		hdr_next_pkt >>= 8;
 	
-	pkt_len = board_ram_ptr[1];
-	pkt_len = ((pkt_len >> 8) | ((pkt_len & 0xff) << 8));
+		pkt_len = board_ram_ptr[1];
+		pkt_len = ((pkt_len >> 8) | ((pkt_len & 0xff) << 8));
 	
 #ifdef HYDRA_DEBUG
-	printk("hydra_interrupt(): hdr_next_pkt = 0x%02x, len = %d\n", hdr_next_pkt, pkt_len);
+		printk("hydra_interrupt(): hdr_next_pkt = 0x%02x, len = %d\n", hdr_next_pkt, pkt_len);
 #endif
 	
-	if(pkt_len >= ETHER_MIN_LEN && pkt_len <= ETHER_MAX_LEN)
-	  {
-	    /* note that board_ram_ptr is u_short */
-	    /* CRC is not included in the packet length */
-	    
-	    pkt_len -= 4;
-	    skb = dev_alloc_skb(pkt_len+2);
-	    if(skb == NULL)
-	      {
-		printk("%s: memory squeeze, dropping packet.\n", dev->name);
-		priv->stats.rx_dropped++;
-	      }
-	    else
-	      {
-		skb->dev = dev;
-		skb_reserve(skb, 2);
+		if(pkt_len >= ETHER_MIN_LEN && pkt_len <= ETHER_MAX_LEN)
+		{
+			/* note that board_ram_ptr is u16 */
+			/* CRC is not included in the packet length */
 		
-		if(hdr_next_pkt < priv->next_pkt && hdr_next_pkt != priv->rx_page_start)
-		  {
-		    /* here, the packet is wrapped */
-		    len1 = ((priv->rx_page_stop - priv->next_pkt)<<8)-4;
-		    
-		    memcpyw((u_short *)skb_put(skb, len1), (u_short *)(board_ram_ptr+2), len1);
-		    memcpyw((u_short *)skb_put(skb, pkt_len-len1),  (u_short *)(priv->hydra_base+(priv->rx_page_start<<8)), pkt_len-len1);
-		    
+			pkt_len -= 4;
+			skb = dev_alloc_skb(pkt_len+2);
+			if(skb == NULL)
+		  	{
+				printk(KERN_INFO "%s: memory squeeze, dropping packet.\n", dev->name);
+				priv->stats.rx_dropped++;
+			}
+			else
+			{
+				skb->dev = dev;
+				skb_reserve(skb, 2);
+				if(hdr_next_pkt < priv->next_pkt && hdr_next_pkt != priv->rx_page_start)
+				{
+					/* here, the packet is wrapped */
+					len1 = ((priv->rx_page_stop - priv->next_pkt)<<8)-4;
+			
+					memcpyw((u16 *)skb_put(skb, len1), (u16 *)(board_ram_ptr+2), len1);
+					memcpyw((u16 *)skb_put(skb, pkt_len-len1),  (u16 *)(priv->hydra_base+(priv->rx_page_start<<8)), pkt_len-len1);
+			
 #ifdef HYDRA_DEBUG
-		    printk("wrapped packet: %d/%d bytes\n", len1, pkt_len-len1);
+					printk("wrapped packet: %d/%d bytes\n", len1, pkt_len-len1);
 #endif
-		  }  /* ... here, packet is not wrapped */
-		else memcpyw((u_short *) skb_put(skb, pkt_len), (u_short *)(board_ram_ptr+2), pkt_len);
-	      }
-	    /* if(skb == NULL) ... */
-	  }
-	else
-	  {
-	    WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
-	    printk("hydra_interrupt(): invalid packet len: %d, NIC_CURR = %02x\n", pkt_len, READ_REG(NIC_CURR));
+				}  /* ... here, packet is not wrapped */
+				else
+					memcpyw((u16 *) skb_put(skb, pkt_len), (u16 *)(board_ram_ptr+2), pkt_len);
+			}
+		}
+		else
+		{
+			WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+			printk("hydra_interrupt(): invalid packet len: %d, NIC_CURR = %02x\n", pkt_len, READ_REG(NIC_CURR));
 /*
 this is the error i kept getting until i switched to 0.9.10. it still doesn't
 mean that the bug would have gone away - so be alarmed. the packet is likely
@@ -596,45 +594,47 @@
    
 note-for-v2.1: not really problem anymore. hasn't been for a long time.
 */
-	    
-	    WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
-	    /* should probably reset the NIC here ?? */
-	    
-	    hydra_open(dev);  /* FIXME - i shouldn't really be doing this. */
-	    return;
-	  }
-	
-	/* now, update the next_pkt pointer */
-	if(hdr_next_pkt < priv->rx_page_stop) priv->next_pkt = hdr_next_pkt;
-	else printk("hydra_interrupt(): invalid next_pkt pointer %d\n", hdr_next_pkt);
-	
-	/* update the boundary pointer */
-	boundary = priv->next_pkt - 1;
-	if(boundary < priv->rx_page_start)
-	  boundary = priv->rx_page_stop - 1;
-	
-	/* set NIC to page 0 to update the NIC_BNDRY register */
-	WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
-	WRITE_REG(NIC_BNDRY, boundary);
-	
-	/* select page1 to access the NIC_CURR register */
-	WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
-	
-	
-	skb->protocol = eth_type_trans(skb, dev);
-	netif_rx(skb);
-	priv->stats.rx_packets++;
+		
+			WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+			/* should probably reset the NIC here ?? */
+		
+			hydra_open(dev);  /* FIXME - i shouldn't really be doing this. */
+			return;
+		}
+	
+		/* now, update the next_pkt pointer */
+		if(hdr_next_pkt < priv->rx_page_stop)
+			priv->next_pkt = hdr_next_pkt;
+		else
+			printk("hydra_interrupt(): invalid next_pkt pointer %d\n", hdr_next_pkt);
+	
+		/* update the boundary pointer */
+		boundary = priv->next_pkt - 1;
+		if(boundary < priv->rx_page_start)
+			boundary = priv->rx_page_stop - 1;
+	
+		/* set NIC to page 0 to update the NIC_BNDRY register */
+		WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+		WRITE_REG(NIC_BNDRY, boundary);
+	
+		/* select page1 to access the NIC_CURR register */
+		WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+	
+	
+		skb->protocol = eth_type_trans(skb, dev);
+		netif_rx(skb);
+		priv->stats.rx_packets++;
 	
-      }
-    return;
-    }
+	}
+	return;
+}
     
 
-static struct enet_statistics *hydra_get_stats(struct device *dev)
+static struct net_device_stats *hydra_get_stats(struct device *dev)
 {
 	struct hydra_private *priv = (struct hydra_private *)dev->priv;
 #if 0
-	u_char *board = priv->hydra_base; 
+	u8 *board = priv->hydra_base; 
 
 	short saved_addr;
 #endif
@@ -643,17 +643,15 @@
 	return(&priv->stats);
 }
 
-#ifdef HAVE_MULTICAST
 static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
-    {
-    struct hydra_private *priv = (struct hydra_private *)dev->priv;
-    u_char *board = priv->hydra_base;
+{
+	struct hydra_private *priv = (struct hydra_private *)dev->priv;
+	u8 *board = priv->hydra_base;
 
-    /* yes, this code is also waiting for someone to complete.. :) */
-    /* (personally i don't care about multicasts at all :) */
-    return;
-    }
-#endif
+	/* yes, this code is also waiting for someone to complete.. :) */
+	/* (personally i don't care about multicasts at all :) */
+	return;
+}
 
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.24/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.1.24/linux/drivers/net/ibmtr.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/net/ibmtr.c	Sun Feb  2 15:18:40 1997
@@ -174,7 +174,7 @@
 static int	tok_open(struct device *dev);
 static int	tok_close(struct device *dev);
 static int	tok_send_packet(struct sk_buff *skb, struct device *dev);
-static struct enet_statistics * tok_get_stats(struct device *dev);
+static struct net_device_stats * tok_get_stats(struct device *dev);
 void		tr_readlog(struct device *dev);
 
 /* FIXME: Should use init_timer and friends not assume the structure
@@ -1561,11 +1561,11 @@
    this device -- the tr.... structure is an ethnet look-alike
    so at least for this iteration may suffice.   */
 
-static struct enet_statistics * tok_get_stats(struct device *dev) {
+static struct net_device_stats * tok_get_stats(struct device *dev) {
 
 	struct tok_info *toki;
 	toki=(struct tok_info *) dev->priv;
-	return (struct enet_statistics *) &toki->tr_stats;
+	return (struct net_device_stats *) &toki->tr_stats;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.24/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.1.24/linux/drivers/net/lance.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/net/lance.c	Sun Feb  2 15:18:40 1997
@@ -234,7 +234,7 @@
 	int cur_rx, cur_tx;			/* The next free ring entry */
 	int dirty_rx, dirty_tx;		/* The ring entries to be free()ed. */
 	int dma;
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	unsigned char chip_version;	/* See lance_chip_type. */
 	char tx_full;
 	unsigned long lock;
@@ -294,7 +294,7 @@
 static int lance_rx(struct device *dev);
 static void lance_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int lance_close(struct device *dev);
-static struct enet_statistics *lance_get_stats(struct device *dev);
+static struct net_device_stats *lance_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 
@@ -777,8 +777,7 @@
 	outw(csr0_bits, dev->base_addr + LANCE_DATA);
 }
 
-static int
-lance_start_xmit(struct sk_buff *skb, struct device *dev)
+static int lance_start_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct lance_private *lp = (struct lance_private *)dev->priv;
 	int ioaddr = dev->base_addr;
@@ -820,14 +819,6 @@
 		return 0;
 	}
 
-	if (skb == NULL) {
-		dev_tint(dev);
-		return 0;
-	}
-
-	if (skb->len <= 0)
-		return 0;
-
 	if (lance_debug > 3) {
 		outw(0x0000, ioaddr+LANCE_ADDR);
 		printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name,
@@ -881,7 +872,8 @@
 		lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000;
 	}
 	lp->cur_tx++;
-
+	lp->stats.tx_bytes+=skb->len;
+	
 	/* Trigger an immediate send poll. */
 	outw(0x0000, ioaddr+LANCE_ADDR);
 	outw(0x0048, ioaddr+LANCE_DATA);
@@ -1088,9 +1080,10 @@
 				eth_copy_and_sum(skb,
 					(unsigned char *)bus_to_virt((lp->rx_ring[entry].base & 0x00ffffff)),
 					pkt_len,0);
+				lp->stats.rx_bytes+=skb->len;
 				skb->protocol=eth_type_trans(skb,dev);
-				netif_rx(skb);
 				lp->stats.rx_packets++;
+				netif_rx(skb);
 			}
 		}
 		/* The docs say that the buffer length isn't touched, but Andrew Boyd
@@ -1139,8 +1132,7 @@
 	return 0;
 }
 
-static struct enet_statistics *
-lance_get_stats(struct device *dev)
+static struct net_device_stats *lance_get_stats(struct device *dev)
 {
 	struct lance_private *lp = (struct lance_private *)dev->priv;
 	short ioaddr = dev->base_addr;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/lance32.c linux/drivers/net/lance32.c
--- v2.1.24/linux/drivers/net/lance32.c	Wed Oct  9 08:55:19 1996
+++ linux/drivers/net/lance32.c	Sun Feb  2 15:18:40 1997
@@ -132,7 +132,7 @@
 	int cur_rx, cur_tx;			/* The next free ring entry */
 	int dirty_rx, dirty_tx;		        /* The ring entries to be free()ed. */
 	int dma;
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	char tx_full;
 	unsigned long lock;
 };
@@ -143,7 +143,7 @@
 static int lance32_rx(struct device *dev);
 static void lance32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int lance32_close(struct device *dev);
-static struct enet_statistics *lance32_get_stats(struct device *dev);
+static struct net_device_stats *lance32_get_stats(struct device *dev);
 static void lance32_set_multicast_list(struct device *dev);
 
 
@@ -785,8 +785,7 @@
 	return 0;
 }
 
-static struct enet_statistics *
-lance32_get_stats(struct device *dev)
+static struct net_device_stats *lance32_get_stats(struct device *dev)
 {
 	struct lance32_private *lp = (struct lance32_private *)dev->priv;
 	int ioaddr = dev->base_addr;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/lapbether.c linux/drivers/net/lapbether.c
--- v2.1.24/linux/drivers/net/lapbether.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/net/lapbether.c	Sun Feb  2 15:18:40 1997
@@ -74,7 +74,7 @@
 	char   ethname[14];		/* ether device name */
 	struct device *ethdev;		/* link to ethernet device */
 	struct device axdev;		/* lapbeth device (lapb#) */
-	struct enet_statistics stats;	/* some statistics */
+	struct net_device_stats stats;	/* some statistics */
 } *lapbeth_devices = NULL;
 
 
@@ -330,7 +330,7 @@
 /*
  *	Statistics
  */
-static struct enet_statistics *lapbeth_get_stats(struct device *dev)
+static struct net_device_stats *lapbeth_get_stats(struct device *dev)
 {
 	struct lapbethdev *lapbeth;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/loopback.c linux/drivers/net/loopback.c
--- v2.1.24/linux/drivers/net/loopback.c	Thu Jan  2 15:55:18 1997
+++ linux/drivers/net/loopback.c	Sun Feb  2 15:18:40 1997
@@ -60,10 +60,14 @@
  */
 static int loopback_xmit(struct sk_buff *skb, struct device *dev)
 {
-	struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
-  
+	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
+
+	/*
+	 *	Take this out if the debug says its ok
+	 */
+	   
 	if (skb == NULL || dev == NULL) 
-		return(0);
+		printk(KERN_DEBUG "loopback fed NULL data - splat\n");
 
 	/*
 	 *	Optimise so buffers with skb->free=1 are not copied but
@@ -96,9 +100,9 @@
 	return(0);
 }
 
-static struct enet_statistics *get_stats(struct device *dev)
+static struct net_device_stats *get_stats(struct device *dev)
 {
-	return (struct enet_statistics *)dev->priv;
+	return (struct net_device_stats *)dev->priv;
 }
 
 static int loopback_open(struct device *dev)
@@ -130,10 +134,10 @@
 	dev->pa_mask		= in_aton("255.0.0.0");
 	dev->pa_alen		= 4;
 #endif  
-	dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+	dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
 	if (dev->priv == NULL)
 			return -ENOMEM;
-	memset(dev->priv, 0, sizeof(struct enet_statistics));
+	memset(dev->priv, 0, sizeof(struct net_device_stats));
 	dev->get_stats = get_stats;
 
 	/*
diff -u --recursive --new-file v2.1.24/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c
--- v2.1.24/linux/drivers/net/ltpc.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/ltpc.c	Sun Feb  2 15:18:40 1997
@@ -0,0 +1,1281 @@
+/***    ltpc.c -- a driver for the LocalTalk PC card.
+ *
+ *      Copyright (c) 1995,1996 Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *
+ *      This software may be used and distributed according to the terms
+ *      of the GNU General Public License, incorporated herein by reference.
+ *
+ *      This is ALPHA code at best.  It may not work for you.  It may
+ *      damage your equipment.  It may damage your relations with other
+ *      users of your network.  Use it at your own risk!
+ *
+ *      Based in part on:
+ *      skeleton.c      by Donald Becker
+ *      dummy.c         by Nick Holloway and Alan Cox
+ *      loopback.c      by Ross Biro, Fred van Kampen, Donald Becker
+ *      the netatalk source code (UMICH)
+ *      lots of work on the card...
+ *
+ *      I do not have access to the (proprietary) SDK that goes with the card.
+ *      If you do, I don't want to know about it, and you can probably write
+ *      a better driver yourself anyway.  This does mean that the pieces that
+ *      talk to the card are guesswork on my part, so use at your own risk!
+ *
+ *      This is my first try at writing Linux networking code, and is also
+ *      guesswork.  Again, use at your own risk!  (Although on this part, I'd
+ *      welcome suggestions)
+ *
+ *      This is a loadable kernel module which seems to work at my site
+ *      consisting of a 1.2.13 linux box running netatalk 1.3.3, and with
+ *      the kernel support from 1.3.3b2 including patches routing.patch
+ *      and ddp.disappears.from.chooser.  In order to run it, you will need
+ *      to patch ddp.c and aarp.c in the kernel, but only a little...
+ *
+ *      I'm fairly confident that while this is arguably badly written, the
+ *      problems that people experience will be "higher level", that is, with
+ *      complications in the netatalk code.  The driver itself doesn't do
+ *      anything terribly complicated -- it pretends to be an ether device
+ *      as far as netatalk is concerned, strips the DDP data out of the ether
+ *      frame and builds a LLAP packet to send out the card.  In the other
+ *      direction, it receives LLAP frames from the card and builds a fake
+ *      ether packet that it then tosses up to the networking code.  You can
+ *      argue (correctly) that this is an ugly way to do things, but it
+ *      requires a minimal amount of fooling with the code in ddp.c and aarp.c.
+ *
+ *      The card will do a lot more than is used here -- I *think* it has the
+ *      layers up through ATP.  Even if you knew how that part works (which I
+ *      don't) it would be a big job to carve up the kernel ddp code to insert
+ *      things at a higher level, and probably a bad idea...
+ *
+ *      There are a number of other cards that do LocalTalk on the PC.  If
+ *      nobody finds any insurmountable (at the netatalk level) problems
+ *      here, this driver should encourage people to put some work into the
+ *      other cards (some of which I gather are still commercially available)
+ *      and also to put hooks for LocalTalk into the official ddp code.
+ *
+ *      I welcome comments and suggestions.  This is my first try at Linux
+ *      networking stuff, and there are probably lots of things that I did
+ *      suboptimally.  
+ *
+ ***/
+
+/***
+ *
+ * $Log: ltpc.c,v $
+ * Revision 1.8  1997/01/28 05:44:54  bradford
+ * Clean up for non-module a little.
+ * Hacked about a bit to clean things up - Alan Cox 
+ * Probably broken it from the origina 1.8
+ *
+ * Revision 1.7  1996/12/12 03:42:33  bradford
+ * DMA alloc cribbed from 3c505.c.
+ *
+ * Revision 1.6  1996/12/12 03:18:58  bradford
+ * Added virt_to_bus; works in 2.1.13.
+ *
+ * Revision 1.5  1996/12/12 03:13:22  root
+ * xmitQel initialization -- think through better though.
+ *
+ * Revision 1.4  1996/06/18 14:55:55  root
+ * Change names to ltpc. Tabs. Took a shot at dma alloc,
+ * although more needs to be done eventually.
+ *
+ * Revision 1.3  1996/05/22 14:59:39  root
+ * Change dev->open, dev->close to track dummy.c in 1.99.(around 7)
+ *
+ * Revision 1.2  1996/05/22 14:58:24  root
+ * Change tabs mostly.
+ *
+ * Revision 1.1  1996/04/23 04:45:09  root
+ * Initial revision
+ *
+ * Revision 0.16  1996/03/05 15:59:56  root
+ * Change ARPHRD_LOCALTLK definition to the "real" one.
+ *
+ * Revision 0.15  1996/03/05 06:28:30  root
+ * Changes for kernel 1.3.70.  Still need a few patches to kernel, but
+ * it's getting closer.
+ *
+ * Revision 0.14  1996/02/25 17:38:32  root
+ * More cleanups.  Removed query to card on get_stats.
+ *
+ * Revision 0.13  1996/02/21  16:27:40  root
+ * Refix debug_print_skb.  Fix mac.raw gotcha that appeared in 1.3.65.
+ * Clean up receive code a little.
+ *
+ * Revision 0.12  1996/02/19  16:34:53  root
+ * Fix debug_print_skb.  Kludge outgoing snet to 0 when using startup
+ * range.  Change debug to mask: 1 for verbose, 2 for higher level stuff
+ * including packet printing, 4 for lower level (card i/o) stuff.
+ *
+ * Revision 0.11  1996/02/12  15:53:38  root
+ * Added router sends (requires new aarp.c patch)
+ *
+ * Revision 0.10  1996/02/11  00:19:35  root
+ * Change source LTALK_LOGGING debug switch to insmod ... debug=2.
+ *
+ * Revision 0.9  1996/02/10  23:59:35  root
+ * Fixed those fixes for 1.2 -- DANGER!  The at.h that comes with netatalk
+ * has a *different* definition of struct sockaddr_at than the Linux kernel
+ * does.  This is an "insidious and invidious" bug...
+ * (Actually the preceding comment is false -- it's the atalk.h in the
+ * ancient atalk-0.06 that's the problem)
+ *
+ * Revision 0.8  1996/02/10 19:09:00  root
+ * Merge 1.3 changes.  Tested OK under 1.3.60.
+ *
+ * Revision 0.7  1996/02/10 17:56:56  root
+ * Added debug=1 parameter on insmod for debugging prints.  Tried
+ * to fix timer unload on rmmod, but I don't think that's the problem.
+ *
+ * Revision 0.6  1995/12/31  19:01:09  root
+ * Clean up rmmod, irq comments per feedback from Corin Anderson (Thanks Corey!)
+ * Clean up initial probing -- sometimes the card wakes up latched in reset.
+ *
+ * Revision 0.5  1995/12/22  06:03:44  root
+ * Added comments in front and cleaned up a bit.
+ * This version sent out to people.
+ *
+ * Revision 0.4  1995/12/18  03:46:44  root
+ * Return shortDDP to longDDP fake to 0/0.  Added command structs.
+ *
+ ***/
+
+/* ltpc jumpers are:
+*
+*	Interrupts -- set at most one.  If none are set, the driver uses
+*	polled mode.  Because the card was developed in the XT era, the
+*	original documentation refers to IRQ2.  Since you'll be running
+*	this on an AT (or later) class machine, that really means IRQ9.
+*
+*	SW1	IRQ 4
+*	SW2	IRQ 3
+*	SW3	IRQ 9 (2 in original card documentation only applies to XT)
+*
+*
+*	DMA -- choose DMA 1 or 3, and set both corresponding switches.
+*
+*	SW4	DMA 3
+*	SW5	DMA 1
+*	SW6	DMA 3
+*	SW7	DMA 1
+*
+*
+*	I/O address -- choose one.  
+*
+*	SW8	220 / 240
+*/
+
+/*	To have some stuff logged, do 
+*	insmod ltpc.o debug=1
+*
+*	For a whole bunch of stuff, use higher numbers.
+*
+*	The default is 0, i.e. no messages except for the probe results.
+*/
+
+/* insmod-tweakable variables */
+static int debug=0;
+#define DEBUG_VERBOSE 1
+#define DEBUG_UPPER 2
+#define DEBUG_LOWER 4
+
+#include <linux/config.h> /* for CONFIG_MAX_16M */
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#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 <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/if_arp.h>
+#include <linux/if_ltalk.h>
+
+#include <linux/delay.h>
+#include <linux/timer.h>
+
+#include <linux/atalk.h>
+
+/* our stuff */
+#include "ltpc.h"
+
+/* function prototypes */
+static int do_read(struct device *dev, void *cbuf, int cbuflen,
+	void *dbuf, int dbuflen);
+static int sendup_buffer (struct device *dev);
+
+/* Dma Memory related stuff, cribbed directly from 3c505.c */
+
+/* Pure 2^n version of get_order */
+static inline int __get_order(unsigned long size)
+{
+        int order;
+
+        size = (size - 1) >> (PAGE_SHIFT - 1);
+        order = -1;
+        do {
+                size >>= 1;
+                order++;
+        } while (size);
+        return order;
+}
+
+static unsigned long dma_mem_alloc(int size)
+{
+        int order = __get_order(size);
+
+        return __get_dma_pages(GFP_KERNEL, order);
+}
+
+static unsigned char *ltdmabuf;
+static unsigned char *ltdmacbuf;
+
+struct xmitQel {
+	struct xmitQel *next;
+	unsigned char *cbuf;
+	short cbuflen;
+	unsigned char *dbuf;
+	short dbuflen;
+	unsigned char QWrite;	/* read or write data */
+	unsigned char mailbox;
+};
+
+static struct xmitQel *xmQhd=NULL,*xmQtl=NULL;
+
+static void enQ(struct xmitQel *qel)
+{
+	unsigned long flags;
+	qel->next = NULL;
+	save_flags(flags);
+	cli();
+	if (xmQtl) {
+		xmQtl->next = qel;
+	} else {
+		xmQhd = qel;
+	}
+	xmQtl = qel;
+	restore_flags(flags);
+
+	if (debug&DEBUG_LOWER)
+		printk("enqueued a 0x%02x command\n",qel->cbuf[0]);
+}
+
+static struct xmitQel *deQ(void)
+{
+	unsigned long flags;
+	int i;
+	struct xmitQel *qel=NULL;
+	save_flags(flags);
+	cli();
+	if (xmQhd) {
+		qel = xmQhd;
+		xmQhd = qel->next;
+		if(!xmQhd) xmQtl = NULL;
+	}
+	restore_flags(flags);
+
+	if ((debug&DEBUG_LOWER) && qel) {
+		int n;
+		printk("ltpc: dequeued command ");
+		n = qel->cbuflen;
+		if (n>100) n=100;
+		for(i=0;i<n;i++) printk("%02x ",qel->cbuf[i]);
+		printk("\n");
+	}
+
+	return qel;
+}
+
+static struct xmitQel qels[16];
+
+static unsigned char mailbox[16];
+static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+static int wait_timeout(struct device *dev, int c)
+{
+	/* returns true if it stayed c */
+	/* this uses base+6, but it's ok */
+	int i;
+	int timeout;
+
+	/* ten second or so total */
+
+	for(i=0;i<10000;i++) {
+		if ( c != inb_p(dev->base_addr+6) ) return 0;
+		for(timeout=loops_per_sec/1000; timeout > 0; timeout--) ;
+	}
+	return 1; /* timed out */
+}
+
+static int getmbox(void)
+{
+	unsigned long flags;
+	int i;
+
+	save_flags(flags);
+	cli();
+	for(i=1;i<16;i++) if(!mboxinuse[i]) {
+		mboxinuse[i]=1;
+		restore_flags(flags);
+		return i;
+	}
+	restore_flags(flags);
+	return 0;
+}
+
+static void handlefc(struct device *dev)
+{
+	/* called *only* from idle, non-reentrant */
+	int dma = dev->dma;
+	int base = dev->base_addr;
+
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_READ);
+	set_dma_addr(dma,virt_to_bus(ltdmacbuf));
+	set_dma_count(dma,50);
+	enable_dma(dma);
+
+	inb_p(base+3);
+	inb_p(base+2);
+
+	if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
+}
+
+static void handlefd(struct device *dev)
+{
+	int dma = dev->dma;
+	int base = dev->base_addr;
+
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_READ);
+	set_dma_addr(dma,virt_to_bus(ltdmabuf));
+	set_dma_count(dma,800);
+	enable_dma(dma);
+
+	inb_p(base+3);
+	inb_p(base+2);
+
+	if ( wait_timeout(dev,0xfd) ) printk("timed out in handlefd\n");
+	sendup_buffer(dev);
+} 
+
+static void handlewrite(struct device *dev)
+{
+	/* called *only* from idle, non-reentrant */
+	/* on entry, 0xfb and ltdmabuf holds data */
+	int dma = dev->dma;
+	int base = dev->base_addr;
+
+
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_WRITE);
+	set_dma_addr(dma,virt_to_bus(ltdmabuf));
+	set_dma_count(dma,800);
+	enable_dma(dma);
+
+	inb_p(base+3);
+	inb_p(base+2);
+
+	if ( wait_timeout(dev,0xfb) ) {
+		printk("timed out in handlewrite, dma res %d\n",
+			get_dma_residue(dev->dma) );
+	}
+}
+
+static void handleread(struct device *dev)
+{
+	/* on entry, 0xfb */
+	/* on exit, ltdmabuf holds data */
+	int dma = dev->dma;
+	int base = dev->base_addr;
+
+
+
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_READ);
+	set_dma_addr(dma,virt_to_bus(ltdmabuf));
+	set_dma_count(dma,800);
+	enable_dma(dma);
+
+	inb_p(base+3);
+	inb_p(base+2);
+	if ( wait_timeout(dev,0xfb) ) printk("timed out in handleread\n");
+}
+
+static void handlecommand(struct device *dev)
+{
+	/* on entry, 0xfa and ltdmacbuf holds command */
+	int dma = dev->dma;
+	int base = dev->base_addr;
+
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_WRITE);
+	set_dma_addr(dma,virt_to_bus(ltdmacbuf));
+	set_dma_count(dma,50);
+	enable_dma(dma);
+
+	inb_p(base+3);
+	inb_p(base+2);
+	if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
+} 
+
+static unsigned char rescbuf[2] = {0,0};
+static unsigned char resdbuf[2];
+
+static int QInIdle=0;
+
+/* idle expects to be called with the IRQ line high -- either because of
+ * an interrupt, or because the line is tri-stated
+ */
+
+static void idle(struct device *dev)
+{
+	unsigned long flags;
+	int state;
+	/* FIXME This is initialized to shut the warning up, but I need to
+	 * think this through again.
+	 */
+	struct xmitQel *q=0;
+	int oops;
+	int i;
+	int statusPort = dev->base_addr+6;
+
+	save_flags(flags);
+	cli();
+	if(QInIdle) {
+		restore_flags(flags);
+		return;
+	}
+	QInIdle = 1;
+
+
+	restore_flags(flags);
+
+
+	(void) inb_p(statusPort); /* this tri-states the IRQ line */
+
+	oops = 100;
+
+loop:
+	if (0>oops--) { 
+		printk("idle: looped too many times\n");
+		goto done;
+	}
+
+	state = inb_p(statusPort);
+	if (state != inb_p(statusPort)) goto loop;
+
+	switch(state) {
+		case 0xfc: 
+			if (debug&DEBUG_LOWER) printk("idle: fc\n");
+			handlefc(dev); 
+			break;
+		case 0xfd: 
+			if(debug&DEBUG_LOWER) printk("idle: fd\n");
+			handlefd(dev); 
+			break;
+		case 0xf9: 
+			if (debug&DEBUG_LOWER) printk("idle: f9\n");
+			if(!mboxinuse[0]) {
+				mboxinuse[0] = 1;
+				qels[0].cbuf = rescbuf;
+				qels[0].cbuflen = 2;
+				qels[0].dbuf = resdbuf;
+				qels[0].dbuflen = 2;
+				qels[0].QWrite = 0;
+				qels[0].mailbox = 0;
+				enQ(&qels[0]);
+			}
+			inb_p(dev->base_addr+1);
+			inb_p(dev->base_addr+0);
+			if( wait_timeout(dev,0xf9) )
+				printk("timed out idle f9\n");
+			break;
+		case 0xf8:
+			if (xmQhd) {
+				inb_p(dev->base_addr+1);
+				inb_p(dev->base_addr+0);
+				if(wait_timeout(dev,0xf8) )
+					printk("timed out idle f8\n");
+			} else {
+				goto done;
+			}
+			break;
+		case 0xfa: 
+			if(debug&DEBUG_LOWER) printk("idle: fa\n");
+			if (xmQhd) {
+				q=deQ();
+				memcpy(ltdmacbuf,q->cbuf,q->cbuflen);
+				ltdmacbuf[1] = q->mailbox;
+				if (debug>1) { 
+					int n;
+					printk("ltpc: sent command     ");
+					n = q->cbuflen;
+					if (n>100) n=100;
+					for(i=0;i<n;i++)
+						printk("%02x ",ltdmacbuf[i]);
+					printk("\n");
+				}
+				handlecommand(dev);
+					if(0xfa==inb_p(statusPort)) {
+						/* we timed out, so return */
+						goto done;
+					} 
+			} else {
+				/* we don't seem to have a command */
+				if (!mboxinuse[0]) {
+					mboxinuse[0] = 1;
+					qels[0].cbuf = rescbuf;
+					qels[0].cbuflen = 2;
+					qels[0].dbuf = resdbuf;
+					qels[0].dbuflen = 2;
+					qels[0].QWrite = 0;
+					qels[0].mailbox = 0;
+					enQ(&qels[0]);
+				} else {
+					printk("trouble: response command already queued\n");
+					goto done;
+				}
+			} 
+			break;
+		case 0xfb:
+			if(debug&DEBUG_LOWER) printk("idle: fb\n");
+			if(q->QWrite) {
+				memcpy(ltdmabuf,q->dbuf,q->dbuflen);
+				handlewrite(dev);
+			} else {
+				handleread(dev);
+				if(q->mailbox) {
+					memcpy(q->dbuf,ltdmabuf,q->dbuflen);
+				} else { 
+					/* this was a result */
+					mailbox[ 0x0f & ltdmabuf[0] ] = ltdmabuf[1];
+					mboxinuse[0]=0;
+				}
+			}
+			break;
+	}
+	goto loop;
+
+done:
+	QInIdle=0;
+
+	/* now set the interrupts back as appropriate */
+	/* the first 7 takes it out of tri-state (but still high) */
+	/* the second resets it */
+	/* note that after this point, any read of 6 will trigger an interrupt */
+
+	if (dev->irq) {
+		inb_p(dev->base_addr+7);
+		inb_p(dev->base_addr+7);
+	}
+	return;
+}
+
+
+static int do_write(struct device *dev, void *cbuf, int cbuflen,
+	void *dbuf, int dbuflen)
+{
+
+	int i = getmbox();
+	int ret;
+
+	if(i) {
+		qels[i].cbuf = (unsigned char *) cbuf;
+		qels[i].cbuflen = cbuflen;
+		qels[i].dbuf = (unsigned char *) dbuf;
+		qels[i].dbuflen = dbuflen;
+		qels[i].QWrite = 1;
+		qels[i].mailbox = i;  /* this should be initted rather */
+		enQ(&qels[i]);
+		idle(dev);
+		ret = mailbox[i];
+		mboxinuse[i]=0;
+		return ret;
+	}
+	printk("ltpc: could not allocate mbox\n");
+	return -1;
+}
+
+static int do_read(struct device *dev, void *cbuf, int cbuflen,
+	void *dbuf, int dbuflen)
+{
+
+	int i = getmbox();
+	int ret;
+
+	if(i) {
+		qels[i].cbuf = (unsigned char *) cbuf;
+		qels[i].cbuflen = cbuflen;
+		qels[i].dbuf = (unsigned char *) dbuf;
+		qels[i].dbuflen = dbuflen;
+		qels[i].QWrite = 0;
+		qels[i].mailbox = i;  /* this should be initted rather */
+		enQ(&qels[i]);
+		idle(dev);
+		ret = mailbox[i];
+		mboxinuse[i]=0;
+		return ret;
+	}
+	printk("ltpc: could not allocate mbox\n");
+	return -1;
+}
+
+/* end of idle handlers -- what should be seen is do_read, do_write */
+
+static struct timer_list ltpc_timer;
+
+static int ltpc_xmit(struct sk_buff *skb, struct device *dev);
+static struct enet_statistics *ltpc_get_stats(struct device *dev);
+
+static int ltpc_open(struct device *dev)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+	return 0;
+}
+
+static int ltpc_close(struct device *dev)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
+static int read_30 ( struct device *dev)
+{
+	lt_command c;
+	c.getflags.command = LT_GETFLAGS;
+	return do_read(dev, &c, sizeof(c.getflags),&c,0);
+}
+
+static int set_30 (struct device *dev,int x)
+{
+	lt_command c;
+	c.setflags.command = LT_SETFLAGS;
+	c.setflags.flags = x;
+	return do_write(dev, &c, sizeof(c.setflags),&c,0);
+}
+
+static int sendup_buffer (struct device *dev)
+{
+	/* on entry, command is in ltdmacbuf, data in ltdmabuf */
+	/* called from idle, non-reentrant */
+
+	int dnode, snode, llaptype, len; 
+	int sklen;
+	struct sk_buff *skb;
+	struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
+	struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf;
+
+	if (ltc->command != LT_RCVLAP) {
+		printk("unknown command 0x%02x from ltpc card\n",ltc->command);
+		return(-1);
+	}
+	dnode = ltc->dnode;
+	snode = ltc->snode;
+	llaptype = ltc->laptype;
+	len = ltc->length; 
+
+	sklen = len;
+	if (llaptype == 1) 
+		sklen += 8;  /* correct for short ddp */
+	if(sklen > 800) {
+		printk(KERN_INFO "%s: nonsense length in ltpc command 0x14: 0x%08x\n",
+			dev->name,sklen);
+		return -1;
+	}
+
+	if ( (llaptype==0) || (llaptype>2) ) {
+		printk(KERN_INFO "%s: unknown LLAP type: %d\n",dev->name,llaptype);
+		return -1;
+	}
+
+
+	skb = dev_alloc_skb(3+sklen);
+	if (skb == NULL) 
+	{
+		printk("%s: dropping packet due to memory squeeze.\n",
+			dev->name);
+		return -1;
+	}
+	skb->dev = dev;
+
+	if (sklen > len)
+		skb_reserve(skb,8);
+	skb_put(skb,len+3);
+	skb->protocol = htons(ETH_P_LOCALTALK);
+	/* add LLAP header */
+	skb->data[0] = dnode;
+	skb->data[1] = snode;
+	skb->data[2] = llaptype;
+	skb->mac.raw = skb->data;	/* save pointer to llap header */
+	skb_pull(skb,3);
+
+	/* copy ddp(s,e)hdr + contents */
+	memcpy(skb->data,(void*)ltdmabuf,len);
+
+	skb->h.raw = skb->data;
+
+	/* toss it onwards */
+	netif_rx(skb);
+	stats->rx_packets++;
+	return 0;
+}
+
+/* the handler for the board interrupt */
+ 
+static void ltpc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
+{
+	struct device *dev = (struct device *) irq2dev_map[irq];
+
+	if (dev==NULL) {
+		printk("ltpc_interrupt: unknown device.\n");
+		return;
+	}
+
+	inb_p(dev->base_addr+6);  /* disable further interrupts from board */
+
+	idle(dev); /* handle whatever is coming in */
+ 
+	/* idle re-enables interrupts from board */ 
+
+	return;
+}
+
+/***
+ *
+ *    The ioctls that the driver responds to are:
+ *
+ *    SIOCSIFADDR -- do probe using the passed node hint.
+ *    SIOCGIFADDR -- return net, node.
+ *
+ *    some of this stuff should be done elsewhere.
+ *
+ ***/
+
+static int ltpc_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+	struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr;
+	/* we'll keep the localtalk node address in dev->pa_addr */
+	struct at_addr *aa = (struct at_addr *) &dev->pa_addr;
+	struct lt_init c;
+	int ltflags;
+
+	if(debug&DEBUG_VERBOSE) printk("ltpc_ioctl called\n");
+
+	switch(cmd) {
+		case SIOCSIFADDR:
+
+			aa->s_net  = sa->sat_addr.s_net;
+      
+			/* this does the probe and returns the node addr */
+			c.command = LT_INIT;
+			c.hint = sa->sat_addr.s_node;
+
+			aa->s_node = do_read(dev,&c,sizeof(c),&c,0);
+
+			/* get all llap frames raw */
+			ltflags = read_30(dev);
+			ltflags |= LT_FLAG_ALLLAP;
+			set_30 (dev,ltflags);  
+
+			dev->broadcast[0] = 0xFF;
+			dev->dev_addr[0] = aa->s_node;
+
+			dev->addr_len=1;
+   
+			return 0;
+
+		case SIOCGIFADDR:
+
+			sa->sat_addr.s_net = aa->s_net;
+			sa->sat_addr.s_node = aa->s_node;
+
+			return 0;
+
+		default: 
+			return -EINVAL;
+	}
+}
+
+static void set_multicast_list(struct device *dev)
+{
+	/* This needs to be present to keep netatalk happy. */
+	/* Actually netatalk needs fixing! */
+}
+
+static int ltpc_init(struct device *dev)
+{
+	/* Initialize the device structure. */
+  
+	/* Fill in the fields of the device structure with ethernet-generic values. */
+	ltalk_setup(dev);
+	dev->hard_start_xmit = ltpc_xmit;
+
+	dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
+	if(!dev->priv)
+	{
+		printk(KERN_INFO "%s: could not allocate statistics buffer\n", dev->name);
+		return -ENOMEM;
+	}
+
+	memset(dev->priv, 0, sizeof(struct net_device_stats));
+	dev->get_stats = ltpc_get_stats;
+
+	dev->open = ltpc_open;
+	dev->stop = ltpc_close;
+
+	/* add the ltpc-specific things */
+	dev->do_ioctl = &ltpc_ioctl;
+
+	dev->set_multicast_list = &set_multicast_list;
+	return 0;
+}
+
+static int ltpc_poll_counter = 0;
+
+static void ltpc_poll(unsigned long l)
+{
+	struct device *dev = (struct device *) l;
+
+	del_timer(&ltpc_timer);
+
+	if(debug&DEBUG_VERBOSE) {
+		if (!ltpc_poll_counter) {
+			ltpc_poll_counter = 50;
+			printk("ltpc poll is alive\n");
+		}
+		ltpc_poll_counter--;
+	}
+  
+	if (!dev) return;  /* we've been downed */
+
+	if (dev->irq) {
+		/* we're set up for interrupts */
+		if (0xf8 != inb_p(dev->base_addr+7)) {
+			/* trigger an interrupt */
+			(void) inb_p(dev->base_addr+6);
+		}
+		ltpc_timer.expires = 100;
+	} else {
+		/* we're strictly polling mode */
+		idle(dev);
+		ltpc_timer.expires = 5;
+	}
+
+	ltpc_timer.expires += jiffies;  /* 1.2 to 1.3 change... */
+
+	add_timer(&ltpc_timer);
+}
+
+static int ltpc_xmit(struct sk_buff *skb, struct device *dev)
+{
+	/* in kernel 1.3.xx, on entry skb->data points to ddp header,
+	 * and skb->len is the length of the ddp data + ddp header
+	 */
+
+	struct net_device_stats *stats = (struct enet_statistics *)dev->priv;
+
+	int i;
+	struct lt_sendlap cbuf;
+
+	cbuf.command = LT_SENDLAP;
+	cbuf.dnode = skb->data[0];
+	cbuf.laptype = skb->data[2];
+	skb_pull(skb,3);	/* skip past LLAP header */
+	cbuf.length = skb->len;	/* this is host order */
+	skb->h.raw=skb->data;
+
+	if(debug&DEBUG_UPPER) {
+		printk("command ");
+		for(i=0;i<6;i++)
+			printk("%02x ",((unsigned char *)&cbuf)[i]);
+		printk("\n");
+	}
+
+	do_write(dev,&cbuf,sizeof(cbuf),skb->h.raw,skb->len);
+
+	if(debug&DEBUG_UPPER) {
+		printk("sent %d ddp bytes\n",skb->len);
+		for(i=0;i<skb->len;i++) printk("%02x ",skb->h.raw[i]);
+		printk("\n");
+	}
+
+	dev_kfree_skb(skb, FREE_WRITE);
+
+	stats->tx_packets++;
+
+	return 0;
+}
+
+static struct net_device_stats *ltpc_get_stats(struct device *dev)
+{
+	struct enet_statistics *stats = (struct enet_statistics*) dev->priv;
+	return stats;
+}
+
+static unsigned short irqhitmask;
+
+static void lt_probe_handler(int irq, void *dev_id, struct pt_regs *reg_ptr)
+{
+	irqhitmask |= 1<<irq;
+}
+
+int ltpc_probe(struct device *dev)
+{
+	int err;
+	unsigned char dma=0;
+	short base=0;
+	unsigned char irq=0;
+	int x=0,y=0;
+	int timeout;
+	int probe3, probe4, probe9;
+	unsigned short straymask;
+	unsigned long flags;
+
+	err = ltpc_init(dev);
+	if (err) return err;
+
+	/* occasionally the card comes up with reset latched, so we need
+	 * to "reset the reset" first of all -- check the irq first also
+	 */
+
+	save_flags(flags);
+	cli();
+
+	probe3 = request_irq( 3, &lt_probe_handler, 0, "ltpc_probe",NULL);
+	probe4 = request_irq( 4, &lt_probe_handler, 0, "ltpc_probe",NULL);
+	probe9 = request_irq( 9, &lt_probe_handler, 0, "ltpc_probe",NULL);
+
+	irqhitmask = 0;
+
+	sti();
+
+	timeout = jiffies+2;
+	while(timeout>jiffies) ;  /* wait for strays */
+
+	straymask = irqhitmask;  /* pick up any strays */
+ 
+	/* if someone already owns this address, don't probe */ 
+	if (!check_region(0x220,8)) {
+		inb_p(0x227);
+		inb_p(0x227);
+		x=inb_p(0x226);
+		timeout = jiffies+2;
+		while(timeout>jiffies) ;
+		if(straymask != irqhitmask) base = 0x220;
+	}
+	if (!check_region(0x240,8)) {
+		inb_p(0x247);
+		inb_p(0x247);
+		y=inb_p(0x246);
+		timeout = jiffies+2;
+		while(timeout>jiffies) ;
+		if(straymask != irqhitmask) base = 0x240;
+	}
+
+	/* at this point, either we have an irq and the base addr, or
+	 * there isn't any irq and we don't know the base address, but
+	 * in either event the card is no longer latched in reset and
+	 * the irq request line is tri-stated.
+	 */
+
+	cli();
+ 
+	if (!probe3) free_irq(3,NULL);
+	if (!probe4) free_irq(4,NULL);
+	if (!probe9) free_irq(9,NULL);
+
+	sti();
+ 
+	irqhitmask &= ~straymask;
+
+	irq = ffz(~irqhitmask);
+	if (irqhitmask != 1<<irq)
+		printk("ltpc card raised more than one interrupt!\n");
+
+	if (!base) {
+		if (!check_region(0x220,8)) {
+			x = inb_p(0x220+6);
+			if ( (x!=0xff) && (x>=0xf0) ) base = 0x220;
+		}
+ 
+		if (!check_region(0x240,8)) {
+			y = inb_p(0x240+6);
+			if ( (y!=0xff) && (y>=0xf0) ) base = 0x240;
+		} 
+	}
+
+	if(base) {
+		request_region(base,8,"ltpc");
+	} else {
+		printk("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",x,y);
+		restore_flags(flags);
+		return -1;
+	}
+
+	ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
+
+	if (ltdmabuf) ltdmacbuf = &ltdmabuf[800];
+
+	if (!ltdmabuf) {
+		printk("ltpc: mem alloc failed\n");
+		restore_flags(flags);
+		return(-1);
+	}
+
+	if(debug&DEBUG_VERBOSE) {
+		printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
+	}
+
+	/* reset the card */
+
+	inb_p(base+1);
+	inb_p(base+3);
+	timeout = jiffies+2;
+	while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */
+	inb_p(base+0);
+	inb_p(base+2);
+	inb_p(base+7); /* clear reset */
+	inb_p(base+4); 
+	inb_p(base+5);
+	inb_p(base+5); /* enable dma */
+	inb_p(base+6); /* tri-state interrupt line */
+
+	timeout = jiffies+100;
+	while(timeout>jiffies) {
+		/* wait for the card to complete initialization */
+	}
+ 
+	/* now, figure out which dma channel we're using */
+
+	/* set up both dma 1 and 3 for read call */
+
+	if (!request_dma(1,"ltpc")) {
+		disable_dma(1);
+		clear_dma_ff(1);
+		set_dma_mode(1,DMA_MODE_WRITE);
+		set_dma_addr(1,virt_to_bus(ltdmabuf));
+		set_dma_count(1,sizeof(struct lt_mem));
+		enable_dma(1);
+		dma|=1;
+	}
+	if (!request_dma(3,"ltpc")) {
+		disable_dma(3);
+		clear_dma_ff(3);
+		set_dma_mode(3,DMA_MODE_WRITE);
+		set_dma_addr(3,virt_to_bus(ltdmabuf));
+		set_dma_count(3,sizeof(struct lt_mem));
+		enable_dma(3);
+		dma|=2;
+	}
+
+	/* set up request */
+
+	/* FIXME -- do timings better! */
+
+	ltdmabuf[0] = 2; /* read request */
+	ltdmabuf[1] = 1;  /* mailbox */
+	ltdmabuf[2] = 0; ltdmabuf[3] = 0;  /* address */
+	ltdmabuf[4] = 0; ltdmabuf[5] = 1;  /* read 0x0100 bytes */
+	ltdmabuf[6] = 0; /* dunno if this is necessary */
+
+	inb_p(base+1);
+	inb_p(base+0);
+	timeout = jiffies+100;
+	while(timeout>jiffies) {
+		if ( 0xfa == inb_p(base+6) ) break;
+	}
+
+	inb_p(base+3);
+	inb_p(base+2);
+	while(timeout>jiffies) {
+		if ( 0xfb == inb_p(base+6) ) break;
+	}
+
+	/* release the other dma channel */
+
+	if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){
+		dma&=1;
+		free_dma(3);
+	}
+  
+	if ( (dma&0x1) && (get_dma_residue(1)==sizeof(struct lt_mem)) ){
+		dma&=0x2;
+		free_dma(1);
+	}
+ 
+	if (!dma) {  /* no dma channel */
+		printk("No DMA channel found on ltpc card.\n");
+		restore_flags(flags);
+		return -1;
+	} 
+  
+	/* fix up dma number */
+	dma|=1;
+
+	/* set up read */
+
+	if(irq)
+		printk("LocalTalk card found at %03x, IR%d, DMA%d.\n",base,irq,dma);
+	else
+		printk("LocalTalk card found at %03x, DMA%d.  Using polled mode.\n",base,dma);
+    
+	dev->base_addr = base;
+	dev->irq = irq;
+	dev->dma = dma;
+
+	if(debug&DEBUG_VERBOSE) {
+		printk("finishing up transfer\n");
+	}
+
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_READ);
+	set_dma_addr(dma,virt_to_bus(ltdmabuf));
+	set_dma_count(dma,0x100);
+	enable_dma(dma);
+
+	(void) inb_p(base+3);
+	(void) inb_p(base+2);
+	timeout = jiffies+100;
+	while(timeout>jiffies) {
+		if( 0xf9 == inb_p(base+6)) break;
+	}
+
+	if(debug&DEBUG_VERBOSE) {
+		printk("setting up timer and irq\n");
+	}
+
+	init_timer(&ltpc_timer);
+	ltpc_timer.function=ltpc_poll;
+	ltpc_timer.data = (unsigned long) dev;
+
+	if (irq) {
+		irq2dev_map[irq] = dev;
+		(void) request_irq( irq, &ltpc_interrupt, 0, "ltpc",NULL);
+		(void) inb_p(base+7);  /* enable interrupts from board */
+		(void) inb_p(base+7);  /* and reset irq line */
+		ltpc_timer.expires = 100;
+		  /* poll it once per second just in case */
+	} else {
+		ltpc_timer.expires = 5;
+		  /* polled mode -- 20 times per second */
+	}
+
+	add_timer(&ltpc_timer);
+
+	restore_flags(flags); 
+
+	return 0;
+}
+
+#ifdef MODULE
+static struct device dev_ltpc = {
+	"ltalk0\0   ", 
+		0, 0, 0, 0,
+	 	0x0, 0,
+	 	0, 0, 0, NULL, ltpc_probe };
+
+int init_module(void)
+{
+	/* Find a name for this unit */
+	int ct= 1;
+	
+	while(dev_get(dev_ltpc.name)!=NULL && ct<100)
+	{
+		sprintf(dev_ltpc.name,"ltpc%d",ct);
+		ct++;
+	}
+	if(ct==100)
+		return -ENFILE;
+	
+	if (register_netdev(&dev_ltpc) != 0) {
+		if(debug&DEBUG_VERBOSE) printk("EIO from register_netdev\n");
+		return -EIO;
+	} else {
+		if(debug&DEBUG_VERBOSE) printk("0 from register_netdev\n");
+		return 0;
+	}
+}
+
+void cleanup_module(void)
+{
+	long timeout;
+
+	ltpc_timer.data = 0;  /* signal the poll routine that we're done */
+
+	if(debug&DEBUG_VERBOSE) printk("freeing irq\n");
+
+	if(dev_ltpc.irq) {
+		free_irq(dev_ltpc.irq,NULL);
+		dev_ltpc.irq = 0;
+	}
+
+	if(del_timer(&ltpc_timer)) 
+	{
+		/* either the poll was never started, or a poll is in process */
+		if(debug&DEBUG_VERBOSE) printk("waiting\n");
+		/* if it's in process, wait a bit for it to finish */
+		timeout = jiffies+HZ; 
+		add_timer(&ltpc_timer)
+		while(del_timer(&ltpc_timer) && (timeout > jiffies))
+		{
+			add_timer(&ltpc_timer);
+			schedule();
+		}
+	}
+
+	if(debug&DEBUG_VERBOSE) printk("freeing dma\n");
+
+	if(dev_ltpc.dma) {
+		free_dma(dev_ltpc.dma);
+		dev_ltpc.dma = 0;
+	}
+
+	if(debug&DEBUG_VERBOSE) printk("freeing ioaddr\n");
+
+	if(dev_ltpc.base_addr) {
+		release_region(dev_ltpc.base_addr,8);
+		dev_ltpc.base_addr = 0;
+	}
+
+	if(debug&DEBUG_VERBOSE) printk("free_pages\n");
+
+	free_pages( (unsigned long) ltdmabuf, __get_order(1000));
+	ltdmabuf=NULL;
+	ltdmacbuf=NULL;
+
+	if(debug&DEBUG_VERBOSE) printk("unregister_netdev\n");
+
+	unregister_netdev(&dev_ltpc);
+
+	if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n");
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/ltpc.h linux/drivers/net/ltpc.h
--- v2.1.24/linux/drivers/net/ltpc.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/ltpc.h	Sun Feb  2 15:18:40 1997
@@ -0,0 +1,73 @@
+/***   ltpc.h
+ *
+ *
+ ***/
+
+#define LT_GETRESULT  0x00
+#define LT_WRITEMEM   0x01
+#define LT_READMEM    0x02
+#define LT_GETFLAGS   0x04
+#define LT_SETFLAGS   0x05
+#define LT_INIT       0x10
+#define LT_SENDLAP    0x13
+#define LT_RCVLAP     0x14
+
+/* the flag that we care about */
+#define LT_FLAG_ALLLAP 0x04
+
+struct lt_getresult {
+	unsigned char command;
+	unsigned char mailbox;
+};
+
+struct lt_mem {
+	unsigned char command;
+	unsigned char mailbox;
+	unsigned short addr;	/* host order */
+	unsigned short length;	/* host order */
+};
+
+struct lt_setflags {
+	unsigned char command;
+	unsigned char mailbox;
+	unsigned char flags;
+};
+
+struct lt_getflags {
+	unsigned char command;
+	unsigned char mailbox;
+};
+
+struct lt_init {
+	unsigned char command;
+	unsigned char mailbox;
+	unsigned char hint;
+};
+
+struct lt_sendlap {
+	unsigned char command;
+	unsigned char mailbox;
+	unsigned char dnode;
+	unsigned char laptype;
+	unsigned short length;	/* host order */
+};
+
+struct lt_rcvlap {
+	unsigned char command;
+	unsigned char dnode;
+	unsigned char snode;
+	unsigned char laptype;
+	unsigned short length;	/* host order */
+};
+
+union lt_command {
+	struct lt_getresult getresult;
+	struct lt_mem mem;
+	struct lt_setflags setflags;
+	struct lt_getflags getflags;
+	struct lt_init init;
+	struct lt_sendlap sendlap;
+	struct lt_rcvlap rcvlap;
+};
+typedef union lt_command lt_command;
+
diff -u --recursive --new-file v2.1.24/linux/drivers/net/mkiss.c linux/drivers/net/mkiss.c
--- v2.1.24/linux/drivers/net/mkiss.c	Thu Jan  2 15:55:18 1997
+++ linux/drivers/net/mkiss.c	Sun Feb  2 15:18:40 1997
@@ -643,12 +643,12 @@
 }
 
 
-static struct enet_statistics *ax_get_stats(struct device *dev)
+static struct net_device_stats *ax_get_stats(struct device *dev)
 {
-	static struct enet_statistics stats;
+	static struct net_device_stats stats;
 	struct ax_disp *ax = (struct ax_disp*)dev->priv;
 
-	memset(&stats, 0, sizeof(struct enet_statistics));
+	memset(&stats, 0, sizeof(struct net_device_stats));
 
 	stats.rx_packets     = ax->rx_packets;
 	stats.tx_packets     = ax->tx_packets;
@@ -839,7 +839,7 @@
 	ax_ldisc.read   = NULL;
 	ax_ldisc.write  = NULL;
 	ax_ldisc.ioctl  = (int (*)(struct tty_struct *, struct file *, unsigned int, unsigned long))ax25_disp_ioctl;
-	ax_ldisc.select = NULL;
+	ax_ldisc.poll   = NULL;
 
 	ax_ldisc.receive_buf  = ax25_receive_buf;
 	ax_ldisc.receive_room = ax25_receive_room;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c
--- v2.1.24/linux/drivers/net/myri_sbus.c	Sun Dec 22 16:37:34 1996
+++ linux/drivers/net/myri_sbus.c	Sun Feb  2 15:18:40 1997
@@ -819,7 +819,7 @@
 	return 0;
 }
 
-static struct enet_statistics *myri_get_stats(struct device *dev)
+static struct net_device_stats *myri_get_stats(struct device *dev)
 { return &(((struct myri_eth *)dev->priv)->enet_stats); }
 
 #define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/myri_sbus.h linux/drivers/net/myri_sbus.h
--- v2.1.24/linux/drivers/net/myri_sbus.h	Sun Dec 22 16:37:34 1996
+++ linux/drivers/net/myri_sbus.h	Sun Feb  2 15:18:40 1997
@@ -278,7 +278,7 @@
 	struct lanai_regs		*lregs;		/* Quick ptr to LANAI regs.   */
 	struct sk_buff	       *rx_skbs[RX_RING_SIZE+1];/* RX skb's                   */
 	struct sk_buff	       *tx_skbs[TX_RING_SIZE];  /* TX skb's                   */
-	struct enet_statistics		enet_stats;	/* Interface stats.           */
+	struct net_device_stats		enet_stats;	/* Interface stats.           */
 
 	/* These are less frequently accessed. */
 	struct myri_regs		*regs;          /* MyriCOM register space.    */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.1.24/linux/drivers/net/net_init.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/net/net_init.c	Sun Feb  2 15:18:40 1997
@@ -39,6 +39,7 @@
 #include <linux/if_arp.h>
 #include <linux/fddidevice.h>
 #include <linux/net_alias.h>
+#include <linux/if_ltalk.h>
 
 /* The network devices currently exist only in the socket namespace, so these
    entries are unused.  The only ones that make sense are
@@ -243,6 +244,50 @@
 	dev->pa_mask	= 0;
 	dev->pa_alen	= 4;
 	return;
+}
+
+#endif
+
+#ifdef CONFIG_ATALK
+
+static int ltalk_change_mtu(struct device *dev, int mtu)
+{
+	return -EINVAL;
+}
+
+static int ltalk_mac_addr(struct device *dev, void *addr)
+{	
+	return -EINVAL;
+}
+
+
+void ltalk_setup(struct device *dev)
+{
+	/* Fill in the fields of the device structure with localtalk-generic values. */
+
+	dev_init_buffers(dev);
+	
+	dev->change_mtu		= ltalk_change_mtu;
+	dev->hard_header	= NULL;
+	dev->rebuild_header 	= NULL;
+	dev->set_mac_address 	= ltalk_mac_addr;
+	dev->hard_header_cache	= NULL;
+	dev->header_cache_update= NULL;
+
+	dev->type		= ARPHRD_LOCALTLK;
+	dev->hard_header_len 	= LTALK_HLEN;
+	dev->mtu		= LTALK_MTU;
+	dev->addr_len		= LTALK_ALEN;
+	dev->tx_queue_len	= 10;	
+	
+	dev->broadcast[0]	= 0xFF;
+
+	dev->flags		= IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP;
+	dev->family		= AF_APPLETALK;
+	dev->pa_addr		= 0;
+	dev->pa_brdaddr 	= 0;
+	dev->pa_mask		= 0;
+	dev->pa_alen		= 1;
 }
 
 #endif
diff -u --recursive --new-file v2.1.24/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.1.24/linux/drivers/net/ni52.c	Tue Dec 31 21:41:05 1996
+++ linux/drivers/net/ni52.c	Sun Feb  2 15:18:40 1997
@@ -164,7 +164,8 @@
 #define DELAY_18(); { __delay( (loops_per_sec>>18)+1 ); }
 
 /* wait for command with timeout: */
-#define WAIT_4_SCB_CMD() { int i; \
+#define WAIT_4_SCB_CMD() 
+{ int i; \
   for(i=0;i<16384;i++) { \
     if(!p->scb->cmd_cuc) break; \
     DELAY_18(); \
@@ -195,7 +196,7 @@
 static int     ni52_open(struct device *dev);
 static int     ni52_close(struct device *dev);
 static int     ni52_send_packet(struct sk_buff *,struct device *);
-static struct  enet_statistics *ni52_get_stats(struct device *dev);
+static struct  net_device_stats *ni52_get_stats(struct device *dev);
 static void    set_multicast_list(struct device *dev);
 #if 0
 static void    ni52_dump(struct device *,void *);
@@ -213,24 +214,24 @@
 
 struct priv
 {
-  struct enet_statistics stats;
-  unsigned long base;
-  char *memtop;
-  int lock,reseted;
-  volatile struct rfd_struct  *rfd_last,*rfd_top,*rfd_first;
-  volatile struct scp_struct  *scp;  /* volatile is important */
-  volatile struct iscp_struct *iscp; /* volatile is important */
-  volatile struct scb_struct  *scb;  /* volatile is important */
-  volatile struct tbd_struct  *xmit_buffs[NUM_XMIT_BUFFS];
-  volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
+	struct net_device_stats stats;
+	unsigned long base;
+	char *memtop;
+	int lock,reseted;
+	volatile struct rfd_struct	*rfd_last,*rfd_top,*rfd_first;
+	volatile struct scp_struct	*scp;	/* volatile is important */
+	volatile struct iscp_struct	*iscp;	/* volatile is important */
+	volatile struct scb_struct	*scb;	/* volatile is important */
+	volatile struct tbd_struct	*xmit_buffs[NUM_XMIT_BUFFS];
+	volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 #if (NUM_XMIT_BUFFS == 1)
-  volatile struct nop_cmd_struct *nop_cmds[2];
+	volatile struct nop_cmd_struct *nop_cmds[2];
 #else
-  volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
+	volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
 #endif
-  volatile int    nop_point,num_recv_buffs;
-  volatile char  *xmit_cbuffs[NUM_XMIT_BUFFS];
-  volatile int    xmit_count,xmit_last;
+	volatile int		nop_point,num_recv_buffs;
+	volatile char		*xmit_cbuffs[NUM_XMIT_BUFFS];
+	volatile int		xmit_count,xmit_last;
 };
 
 /**********************************************
@@ -238,17 +239,17 @@
  */
 static int ni52_close(struct device *dev)
 {
-  free_irq(dev->irq, NULL);
-  irq2dev_map[dev->irq] = NULL;
+	free_irq(dev->irq, NULL);
+	irq2dev_map[dev->irq] = NULL;
 
-  ni_reset586(); /* the hard way to stop the receiver */
+	ni_reset586(); /* the hard way to stop the receiver */
 
-  dev->start = 0;
-  dev->tbusy = 0;
+	dev->start = 0;
+	dev->tbusy = 0;
 
-  MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 
-  return 0;
+	return 0;
 }
 
 /**********************************************
@@ -256,26 +257,26 @@
  */
 static int ni52_open(struct device *dev)
 {
-  ni_disint();
-  alloc586(dev);
-  init586(dev);
-  startrecv586(dev);
-  ni_enaint();
-
-  if(request_irq(dev->irq, &ni52_interrupt,0,"ni5210",NULL))
-  {
-    ni_reset586();
-    return -EAGAIN;
-  }
-  irq2dev_map[dev->irq] = dev;
-
-  dev->interrupt = 0;
-  dev->tbusy = 0;
-  dev->start = 1;
+	ni_disint();
+	alloc586(dev);
+	init586(dev);
+	startrecv586(dev);
+	ni_enaint();
+
+	if(request_irq(dev->irq, &ni52_interrupt,0,"ni5210",NULL))
+	{
+		ni_reset586();
+		return -EAGAIN;
+	}
+	irq2dev_map[dev->irq] = dev;
+
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
 
-  MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 
-  return 0; /* most done by init */
+	return 0; /* most done by init */
 }
 
 /**********************************************
@@ -283,41 +284,41 @@
  */
 static int check586(struct device *dev,char *where,unsigned size)
 {
-  struct priv pb;
-  struct priv *p = /* (struct priv *) dev->priv*/ &pb;
-  char *iscp_addrs[2];
-  int i;
-
-  p->base = (unsigned long) bus_to_virt((unsigned long)where) + size - 0x01000000;
-  p->memtop = bus_to_virt((unsigned long)where) + size;
-  p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
-  memset((char *)p->scp,0, sizeof(struct scp_struct));
-  for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */
-    if(((char *)p->scp)[i])
-      return 0;
-  p->scp->sysbus = SYSBUSVAL;        /* 1 = 8Bit-Bus, 0 = 16 Bit */
-  if(p->scp->sysbus != SYSBUSVAL)
-    return 0;
-
-  iscp_addrs[0] = bus_to_virt((unsigned long)where);
-  iscp_addrs[1]= (char *) p->scp - sizeof(struct iscp_struct);
-
-  for(i=0;i<2;i++)
-  {
-    p->iscp = (struct iscp_struct *) iscp_addrs[i];
-    memset((char *)p->iscp,0, sizeof(struct iscp_struct));
-
-    p->scp->iscp = make24(p->iscp);
-    p->iscp->busy = 1;
-
-    ni_reset586();
-    ni_attn586();
-    DELAY(1);	/* wait a while... */
-
-    if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
-      return 0;
-  }
-  return 1;
+	struct priv pb;
+	struct priv *p = /* (struct priv *) dev->priv*/ &pb;
+	char *iscp_addrs[2];
+	int i;
+
+	p->base = (unsigned long) bus_to_virt((unsigned long)where) + size - 0x01000000;
+	p->memtop = bus_to_virt((unsigned long)where) + size;
+	p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
+	memset((char *)p->scp,0, sizeof(struct scp_struct));
+	for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */
+		if(((char *)p->scp)[i])
+			return 0;
+	p->scp->sysbus = SYSBUSVAL;				/* 1 = 8Bit-Bus, 0 = 16 Bit */
+	if(p->scp->sysbus != SYSBUSVAL)
+		return 0;
+
+	iscp_addrs[0] = bus_to_virt((unsigned long)where);
+	iscp_addrs[1]= (char *) p->scp - sizeof(struct iscp_struct);
+
+	for(i=0;i<2;i++)
+	{
+		p->iscp = (struct iscp_struct *) iscp_addrs[i];
+		memset((char *)p->iscp,0, sizeof(struct iscp_struct));
+
+		p->scp->iscp = make24(p->iscp);
+		p->iscp->busy = 1;
+
+		ni_reset586();
+		ni_attn586();
+		DELAY(1);	/* wait a while... */
+
+		if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
+			return 0;
+	}
+	return 1;
 }
 
 /******************************************************************
@@ -325,34 +326,34 @@
  */
 void alloc586(struct device *dev)
 {
-  struct priv *p =  (struct priv *) dev->priv;
+	struct priv *p =	(struct priv *) dev->priv;
 
-  ni_reset586();
-  DELAY(1);
+	ni_reset586();
+	DELAY(1);
 
-  p->scp  = (struct scp_struct *)  (p->base + SCP_DEFAULT_ADDRESS);
-  p->scb  = (struct scb_struct *)  bus_to_virt(dev->mem_start);
-  p->iscp = (struct iscp_struct *) ((char *)p->scp - sizeof(struct iscp_struct));
+	p->scp	= (struct scp_struct *)	(p->base + SCP_DEFAULT_ADDRESS);
+	p->scb	= (struct scb_struct *)	bus_to_virt(dev->mem_start);
+	p->iscp = (struct iscp_struct *) ((char *)p->scp - sizeof(struct iscp_struct));
 
-  memset((char *) p->iscp,0,sizeof(struct iscp_struct));
-  memset((char *) p->scp ,0,sizeof(struct scp_struct));
+	memset((char *) p->iscp,0,sizeof(struct iscp_struct));
+	memset((char *) p->scp ,0,sizeof(struct scp_struct));
 
-  p->scp->iscp = make24(p->iscp);
-  p->scp->sysbus = SYSBUSVAL;
-  p->iscp->scb_offset = make16(p->scb);
+	p->scp->iscp = make24(p->iscp);
+	p->scp->sysbus = SYSBUSVAL;
+	p->iscp->scb_offset = make16(p->scb);
 
-  p->iscp->busy = 1;
-  ni_reset586();
-  ni_attn586();
+	p->iscp->busy = 1;
+	ni_reset586();
+	ni_attn586();
 
-  DELAY(1);
+	DELAY(1);
 
-  if(p->iscp->busy)
-    printk("%s: Init-Problems (alloc).\n",dev->name);
+	if(p->iscp->busy)
+		printk("%s: Init-Problems (alloc).\n",dev->name);
 
-  p->reseted = 0;
+	p->reseted = 0;
 
-  memset((char *)p->scb,0,sizeof(struct scb_struct));
+	memset((char *)p->scb,0,sizeof(struct scb_struct));
 }
 
 /**********************************************
@@ -361,172 +362,172 @@
 int ni52_probe(struct device *dev)
 {
 #ifndef MODULE
-  int *port;
-  static int ports[] = {0x300, 0x280, 0x360 , 0x320 , 0x340, 0};
+	int *port;
+	static int ports[] = {0x300, 0x280, 0x360 , 0x320 , 0x340, 0};
 #endif
-  int base_addr = dev->base_addr;
+	int base_addr = dev->base_addr;
 
-  if (base_addr > 0x1ff)		/* Check a single specified location. */
-    if( (inb(base_addr+NI52_MAGIC1) == NI52_MAGICVAL1) &&
-        (inb(base_addr+NI52_MAGIC2) == NI52_MAGICVAL2))
-      return ni52_probe1(dev, base_addr);
-  else if (base_addr > 0)		/* Don't probe at all. */
-    return ENXIO;
+	if (base_addr > 0x1ff)		/* Check a single specified location. */
+		if( (inb(base_addr+NI52_MAGIC1) == NI52_MAGICVAL1) &&
+				(inb(base_addr+NI52_MAGIC2) == NI52_MAGICVAL2))
+			return ni52_probe1(dev, base_addr);
+	else if (base_addr > 0)		/* Don't probe at all. */
+		return ENXIO;
 
 #ifdef MODULE
-  printk("%s: no autoprobing allowed for modules.\n",dev->name);
+	printk("%s: no autoprobing allowed for modules.\n",dev->name);
 #else
-  for (port = ports; *port; port++) {
-    int ioaddr = *port;
-    if (check_region(ioaddr, NI52_TOTAL_SIZE))
-      continue;
-    if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
-        !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2))
-      continue;
-
-    dev->base_addr = ioaddr;
-    if (ni52_probe1(dev, ioaddr) == 0)
-      return 0;
-  }
+	for (port = ports; *port; port++) {
+		int ioaddr = *port;
+		if (check_region(ioaddr, NI52_TOTAL_SIZE))
+			continue;
+		if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
+				!(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2))
+			continue;
+
+		dev->base_addr = ioaddr;
+		if (ni52_probe1(dev, ioaddr) == 0)
+			return 0;
+	}
 
 #ifdef FULL_IO_PROBE
-  for(dev->base_addr=0x200;dev->base_addr<0x400;dev->base_addr+=8)
-  {
-    int ioaddr = dev->base_addr;
-    if (check_region(ioaddr, NI52_TOTAL_SIZE))
-      continue;
-    if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
-        !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2))
-      continue;
-    if (ni52_probe1(dev, ioaddr) == 0)
-      return 0;
-  }
+	for(dev->base_addr=0x200;dev->base_addr<0x400;dev->base_addr+=8)
+	{
+		int ioaddr = dev->base_addr;
+		if (check_region(ioaddr, NI52_TOTAL_SIZE))
+			continue;
+		if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
+				!(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2))
+			continue;
+		if (ni52_probe1(dev, ioaddr) == 0)
+			return 0;
+	}
 #endif
 
 #endif
 
-  dev->base_addr = base_addr;
-  return ENODEV;
+	dev->base_addr = base_addr;
+	return ENODEV;
 }
 
 static int ni52_probe1(struct device *dev,int ioaddr)
 {
-  int i,size;
+	int i,size;
 
-  for(i=0;i<ETH_ALEN;i++)
-    dev->dev_addr[i] = inb(dev->base_addr+i);
+	for(i=0;i<ETH_ALEN;i++)
+		dev->dev_addr[i] = inb(dev->base_addr+i);
 
-  if(dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1
-     || dev->dev_addr[2] != NI52_ADDR2)
-    return ENODEV;
+	if(dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1
+		 || dev->dev_addr[2] != NI52_ADDR2)
+		return ENODEV;
 
-  printk("%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr);
+	printk("%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr);
 
-  request_region(ioaddr,NI52_TOTAL_SIZE,"ni5210");
+	request_region(ioaddr,NI52_TOTAL_SIZE,"ni5210");
 
-  /*
-   * check (or search) IO-Memory, 8K and 16K
-   */
+	/*
+	 * check (or search) IO-Memory, 8K and 16K
+	 */
 #ifdef MODULE
-  size = dev->mem_end - dev->mem_start;
-  if(size != 0x2000 && size != 0x4000)
-  {
-    printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n",dev->name,size);
-    return ENODEV;
-  }
-  if(!check586(dev,(char *) dev->mem_start,size))
-  {
-    printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size);
-    return ENODEV;
-  }
+	size = dev->mem_end - dev->mem_start;
+	if(size != 0x2000 && size != 0x4000)
+	{
+		printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n",dev->name,size);
+		return ENODEV;
+	}
+	if(!check586(dev,(char *) dev->mem_start,size))
+	{
+		printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size);
+		return ENODEV;
+	}
 #else
-  if(dev->mem_start != 0) /* no auto-mem-probe */
-  {
-    size = 0x4000; /* check for 16K mem */
-    if(!check586(dev,(char *) dev->mem_start,size)) {
-      size = 0x2000; /* check for 8K mem */
-      if(!check586(dev,(char *) dev->mem_start,size)) {
-        printk("?memprobe, Can't find memory at 0x%lx!\n",dev->mem_start);
-        return ENODEV;
-      }
-    }
-  }
-  else
-  {
-   static long memaddrs[] = { 0xc8000,0xca000,0xcc000,0xce000,0xd0000,0xd2000,
-                              0xd4000,0xd6000,0xd8000,0xda000,0xdc000, 0 };
-   for(i=0;;i++)
-    {
-      if(!memaddrs[i]) {
-        printk("?memprobe, Can't find io-memory!\n");
-        return ENODEV;
-      }
-      dev->mem_start = memaddrs[i];
-      size = 0x2000; /* check for 8K mem */
-      if(check586(dev,(char *)dev->mem_start,size)) /* 8K-check */
-        break;
-      size = 0x4000; /* check for 16K mem */
-      if(check586(dev,(char *)dev->mem_start,size)) /* 16K-check */
-        break;
-    }
-  }
-  dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */
+	if(dev->mem_start != 0) /* no auto-mem-probe */
+	{
+		size = 0x4000; /* check for 16K mem */
+		if(!check586(dev,(char *) dev->mem_start,size)) {
+			size = 0x2000; /* check for 8K mem */
+			if(!check586(dev,(char *) dev->mem_start,size)) {
+				printk("?memprobe, Can't find memory at 0x%lx!\n",dev->mem_start);
+				return ENODEV;
+			}
+		}
+	}
+	else
+	{
+		static long memaddrs[] = { 0xc8000,0xca000,0xcc000,0xce000,0xd0000,0xd2000,
+															0xd4000,0xd6000,0xd8000,0xda000,0xdc000, 0 };
+		for(i=0;;i++)
+		{
+			if(!memaddrs[i]) {
+				printk("?memprobe, Can't find io-memory!\n");
+				return ENODEV;
+			}
+			dev->mem_start = memaddrs[i];
+			size = 0x2000; /* check for 8K mem */
+			if(check586(dev,(char *)dev->mem_start,size)) /* 8K-check */
+				break;
+			size = 0x4000; /* check for 16K mem */
+			if(check586(dev,(char *)dev->mem_start,size)) /* 16K-check */
+				break;
+		}
+	}
+	dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */
 #endif
 
-  dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL);
-  if(dev->priv == NULL)
-  {
-    printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name);
-    return -ENOMEM;
-  }
-                                  /* warning: we don't free it on errors */
-  memset((char *) dev->priv,0,sizeof(struct priv));
-
-  ((struct priv *) (dev->priv))->memtop = bus_to_virt(dev->mem_start) + size;
-  ((struct priv *) (dev->priv))->base =  (unsigned long) bus_to_virt(dev->mem_start) + size - 0x01000000;
-  alloc586(dev);
-
-  /* set number of receive-buffs according to memsize */
-  if(size == 0x2000)
-    ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8;
-  else
-    ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16;
-
-  printk("Memaddr: 0x%lx, Memsize: %d, ",dev->mem_start,size);
-
-  if(dev->irq < 2)
-  {
-    autoirq_setup(0);
-    ni_reset586();
-    ni_attn586();
-    if(!(dev->irq = autoirq_report(2)))
-    {
-      printk("?autoirq, Failed to detect IRQ line!\n");
-      return 1;
-    }
-    printk("IRQ %d (autodetected).\n",dev->irq);
-  }
-  else  {
-    if(dev->irq == 2)
-      dev->irq = 9;
-    printk("IRQ %d (assigned and not checked!).\n",dev->irq);
-  }
-
-  dev->open            = &ni52_open;
-  dev->stop            = &ni52_close;
-  dev->get_stats       = &ni52_get_stats;
-  dev->hard_start_xmit = &ni52_send_packet;
-  dev->set_multicast_list = &set_multicast_list;
-
-  dev->if_port 	       = 0;
-
-  ether_setup(dev);
-
-  dev->tbusy = 0;
-  dev->interrupt = 0;
-  dev->start = 0;
+	dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL);
+	if(dev->priv == NULL)
+	{
+		printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name);
+		return -ENOMEM;
+	}
+																	/* warning: we don't free it on errors */
+	memset((char *) dev->priv,0,sizeof(struct priv));
+
+	((struct priv *) (dev->priv))->memtop = bus_to_virt(dev->mem_start) + size;
+	((struct priv *) (dev->priv))->base =	(unsigned long) bus_to_virt(dev->mem_start) + size - 0x01000000;
+	alloc586(dev);
+
+	/* set number of receive-buffs according to memsize */
+	if(size == 0x2000)
+		((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8;
+	else
+		((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16;
+
+	printk("Memaddr: 0x%lx, Memsize: %d, ",dev->mem_start,size);
+
+	if(dev->irq < 2)
+	{
+		autoirq_setup(0);
+		ni_reset586();
+		ni_attn586();
+		if(!(dev->irq = autoirq_report(2)))
+		{
+			printk("?autoirq, Failed to detect IRQ line!\n");
+			return 1;
+		}
+		printk("IRQ %d (autodetected).\n",dev->irq);
+	}
+	else	{
+		if(dev->irq == 2)
+			dev->irq = 9;
+		printk("IRQ %d (assigned and not checked!).\n",dev->irq);
+	}
+
+	dev->open		= &ni52_open;
+	dev->stop		= &ni52_close;
+	dev->get_stats		= &ni52_get_stats;
+	dev->hard_start_xmit 	= &ni52_send_packet;
+	dev->set_multicast_list = &set_multicast_list;
+
+	dev->if_port 		= 0;
+
+	ether_setup(dev);
+
+	dev->tbusy		= 0;
+	dev->interrupt		= 0;
+	dev->start		= 0;
 
-  return 0;
+	return 0;
 }
 
 /**********************************************
@@ -536,230 +537,232 @@
 
 static int init586(struct device *dev)
 {
-  void *ptr;
-  int i,result=0;
-  struct priv *p = (struct priv *) dev->priv;
-  volatile struct configure_cmd_struct  *cfg_cmd;
-  volatile struct iasetup_cmd_struct *ias_cmd;
-  volatile struct tdr_cmd_struct *tdr_cmd;
-  volatile struct mcsetup_cmd_struct *mc_cmd;
-  struct dev_mc_list *dmi=dev->mc_list;
-  int num_addrs=dev->mc_count;
-
-  ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
-
-  cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
-  cfg_cmd->cmd_status = 0;
-  cfg_cmd->cmd_cmd    = CMD_CONFIGURE | CMD_LAST;
-  cfg_cmd->cmd_link   = 0xffff;
-
-  cfg_cmd->byte_cnt   = 0x0a; /* number of cfg bytes */
-  cfg_cmd->fifo       = fifo; /* fifo-limit (8=tx:32/rx:64) */
-  cfg_cmd->sav_bf     = 0x40; /* hold or discard bad recv frames (bit 7) */
-  cfg_cmd->adr_len    = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
-  cfg_cmd->priority   = 0x00;
-  cfg_cmd->ifs        = 0x60;
-  cfg_cmd->time_low   = 0x00;
-  cfg_cmd->time_high  = 0xf2;
-  cfg_cmd->promisc    = 0;
-  if(dev->flags & IFF_ALLMULTI) {
-    int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
-    if(num_addrs > len)  {
-      printk("%s: switching to promisc. mode\n",dev->name);
-      dev->flags|=IFF_PROMISC;
-    }
-  }
-  if(dev->flags&IFF_PROMISC)
-  {
-       cfg_cmd->promisc=1;
-       dev->flags|=IFF_PROMISC;
-  }
-  cfg_cmd->carr_coll  = 0x00;
-
-  p->scb->cbl_offset = make16(cfg_cmd);
-  p->scb->cmd_ruc = 0;
-
-  p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
-  ni_attn586();
-
-  WAIT_4_STAT_COMPL(cfg_cmd);
-
-  if((cfg_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
-  {
-    printk("%s: configure command failed: %x\n",dev->name,cfg_cmd->cmd_status);
-    return 1;
-  }
-
-    /*
-     * individual address setup
-     */
-  ias_cmd = (struct iasetup_cmd_struct *)ptr;
-
-  ias_cmd->cmd_status = 0;
-  ias_cmd->cmd_cmd    = CMD_IASETUP | CMD_LAST;
-  ias_cmd->cmd_link   = 0xffff;
-
-  memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
-
-  p->scb->cbl_offset = make16(ias_cmd);
-
-  p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
-  ni_attn586();
-
-  WAIT_4_STAT_COMPL(ias_cmd);
-
-  if((ias_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
-    printk("%s (ni52): individual address setup command failed: %04x\n",dev->name,ias_cmd->cmd_status);
-    return 1;
-  }
-
-   /*
-    * TDR, wire check .. e.g. no resistor e.t.c
-    */
-  tdr_cmd = (struct tdr_cmd_struct *)ptr;
-
-  tdr_cmd->cmd_status  = 0;
-  tdr_cmd->cmd_cmd     = CMD_TDR | CMD_LAST;
-  tdr_cmd->cmd_link    = 0xffff;
-  tdr_cmd->status      = 0;
-
-  p->scb->cbl_offset = make16(tdr_cmd);
-  p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
-  ni_attn586();
-
-  WAIT_4_STAT_COMPL(tdr_cmd);
-
-  if(!(tdr_cmd->cmd_status & STAT_COMPL))
-  {
-    printk("%s: Problems while running the TDR.\n",dev->name);
-  }
-  else
-  {
-    DELAY_16(); /* wait for result */
-    result = tdr_cmd->status;
-
-    p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
-    ni_attn586(); /* ack the interrupts */
-
-    if(result & TDR_LNK_OK)
-      ;
-    else if(result & TDR_XCVR_PRB)
-      printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);
-    else if(result & TDR_ET_OPN)
-      printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
-    else if(result & TDR_ET_SRT)
-    {
-      if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
-        printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
-    }
-    else
-      printk("%s: TDR: Unknown status %04x\n",dev->name,result);
-  }
-
-  /*
-   * Multicast setup
-   */
-  if(num_addrs && !(dev->flags & IFF_PROMISC) )
-  {
-    mc_cmd = (struct mcsetup_cmd_struct *) ptr;
-    mc_cmd->cmd_status = 0;
-    mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST;
-    mc_cmd->cmd_link = 0xffff;
-    mc_cmd->mc_cnt = num_addrs * 6;
-
-    for(i=0;i<num_addrs;i++,dmi=dmi->next)
-      memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6);
-
-    p->scb->cbl_offset = make16(mc_cmd);
-    p->scb->cmd_cuc = CUC_START;
-    ni_attn586();
-
-    WAIT_4_STAT_COMPL(mc_cmd);
-
-    if( (mc_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
-      printk("%s: Can't apply multicast-address-list.\n",dev->name);
-  }
-
-   /*
-    * alloc nop/xmit-cmds
-    */
+	void *ptr;
+	int i,result=0;
+	struct priv *p = (struct priv *) dev->priv;
+	volatile struct configure_cmd_struct	*cfg_cmd;
+	volatile struct iasetup_cmd_struct *ias_cmd;
+	volatile struct tdr_cmd_struct *tdr_cmd;
+	volatile struct mcsetup_cmd_struct *mc_cmd;
+	struct dev_mc_list *dmi=dev->mc_list;
+	int num_addrs=dev->mc_count;
+
+	ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
+
+	cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
+	cfg_cmd->cmd_status	= 0;
+	cfg_cmd->cmd_cmd	= CMD_CONFIGURE | CMD_LAST;
+	cfg_cmd->cmd_link	= 0xffff;
+
+	cfg_cmd->byte_cnt	= 0x0a; /* number of cfg bytes */
+	cfg_cmd->fifo		= fifo; /* fifo-limit (8=tx:32/rx:64) */
+	cfg_cmd->sav_bf		= 0x40; /* hold or discard bad recv frames (bit 7) */
+	cfg_cmd->adr_len	= 0x2e; /* addr_len |!src_insert |pre-len |loopback */
+	cfg_cmd->priority	= 0x00;
+	cfg_cmd->ifs		= 0x60;
+	cfg_cmd->time_low	= 0x00;
+	cfg_cmd->time_high	= 0xf2;
+	cfg_cmd->promisc	= 0;
+	if(dev->flags & IFF_ALLMULTI) {
+		int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
+		if(num_addrs > len)	{
+			printk("%s: switching to promisc. mode\n",dev->name);
+			dev->flags|=IFF_PROMISC;
+		}
+	}
+	if(dev->flags&IFF_PROMISC)
+	{
+			 cfg_cmd->promisc=1;
+			 dev->flags|=IFF_PROMISC;
+	}
+	cfg_cmd->carr_coll	= 0x00;
+
+	p->scb->cbl_offset	= make16(cfg_cmd);
+	p->scb->cmd_ruc		= 0;
+
+	p->scb->cmd_cuc		= CUC_START; /* cmd.-unit start */
+	ni_attn586();
+
+	WAIT_4_STAT_COMPL(cfg_cmd);
+
+	if((cfg_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
+	{
+		printk("%s: configure command failed: %x\n",dev->name,cfg_cmd->cmd_status);
+		return 1;
+	}
+
+	/*
+	 * individual address setup
+	 */
+
+	ias_cmd = (struct iasetup_cmd_struct *)ptr;
+
+	ias_cmd->cmd_status	= 0;
+	ias_cmd->cmd_cmd	= CMD_IASETUP | CMD_LAST;
+	ias_cmd->cmd_link	= 0xffff;
+
+	memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
+
+	p->scb->cbl_offset = make16(ias_cmd);
+
+	p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+	ni_attn586();
+
+	WAIT_4_STAT_COMPL(ias_cmd);
+
+	if((ias_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
+		printk("%s (ni52): individual address setup command failed: %04x\n",dev->name,ias_cmd->cmd_status);
+		return 1;
+	}
+
+	/*
+	 * TDR, wire check .. e.g. no resistor e.t.c
+	 */
+	 
+	tdr_cmd = (struct tdr_cmd_struct *)ptr;
+
+	tdr_cmd->cmd_status	= 0;
+	tdr_cmd->cmd_cmd	= CMD_TDR | CMD_LAST;
+	tdr_cmd->cmd_link	= 0xffff;
+	tdr_cmd->status		= 0;
+
+	p->scb->cbl_offset = make16(tdr_cmd);
+	p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+	ni_attn586();
+
+	WAIT_4_STAT_COMPL(tdr_cmd);
+
+	if(!(tdr_cmd->cmd_status & STAT_COMPL))
+	{
+		printk("%s: Problems while running the TDR.\n",dev->name);
+	}
+	else
+	{
+		DELAY_16(); /* wait for result */
+		result = tdr_cmd->status;
+
+		p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+		ni_attn586(); /* ack the interrupts */
+
+		if(result & TDR_LNK_OK)
+			;
+		else if(result & TDR_XCVR_PRB)
+			printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);
+		else if(result & TDR_ET_OPN)
+			printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+		else if(result & TDR_ET_SRT)
+		{
+			if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
+				printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+		}
+		else
+			printk("%s: TDR: Unknown status %04x\n",dev->name,result);
+	}
+
+	/*
+	 * Multicast setup
+	 */
+	if(num_addrs && !(dev->flags & IFF_PROMISC) )
+	{
+		mc_cmd = (struct mcsetup_cmd_struct *) ptr;
+		mc_cmd->cmd_status = 0;
+		mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST;
+		mc_cmd->cmd_link = 0xffff;
+		mc_cmd->mc_cnt = num_addrs * 6;
+
+		for(i=0;i<num_addrs;i++,dmi=dmi->next)
+			memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6);
+
+		p->scb->cbl_offset = make16(mc_cmd);
+		p->scb->cmd_cuc = CUC_START;
+		ni_attn586();
+
+		WAIT_4_STAT_COMPL(mc_cmd);
+
+		if( (mc_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+			printk("%s: Can't apply multicast-address-list.\n",dev->name);
+	}
+
+	/*
+	 * alloc nop/xmit-cmds
+	 */
 #if (NUM_XMIT_BUFFS == 1)
-  for(i=0;i<2;i++)
-  {
-    p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
-    p->nop_cmds[i]->cmd_cmd    = CMD_NOP;
-    p->nop_cmds[i]->cmd_status = 0;
-    p->nop_cmds[i]->cmd_link   = make16((p->nop_cmds[i]));
-    ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
-  }
+	for(i=0;i<2;i++)
+	{
+		p->nop_cmds[i] 			= (struct nop_cmd_struct *)ptr;
+		p->nop_cmds[i]->cmd_cmd		= CMD_NOP;
+		p->nop_cmds[i]->cmd_status 	= 0;
+		p->nop_cmds[i]->cmd_link	= make16((p->nop_cmds[i]));
+		ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+	}
 #else
-  for(i=0;i<NUM_XMIT_BUFFS;i++)
-  {
-    p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
-    p->nop_cmds[i]->cmd_cmd    = CMD_NOP;
-    p->nop_cmds[i]->cmd_status = 0;
-    p->nop_cmds[i]->cmd_link   = make16((p->nop_cmds[i]));
-    ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
-  }
+	for(i=0;i<NUM_XMIT_BUFFS;i++)
+	{
+		p->nop_cmds[i]			= (struct nop_cmd_struct *)ptr;
+		p->nop_cmds[i]->cmd_cmd		= CMD_NOP;
+		p->nop_cmds[i]->cmd_status	= 0;
+		p->nop_cmds[i]->cmd_link	= make16((p->nop_cmds[i]));
+		ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+	}
 #endif
 
-  ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
+	ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
 
-  /*
-   * alloc xmit-buffs / init xmit_cmds
-   */
-  for(i=0;i<NUM_XMIT_BUFFS;i++)
-  {
-    p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
-    ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
-    p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
-    ptr = (char *) ptr + XMIT_BUFF_SIZE;
-    p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
-    ptr = (char *) ptr + sizeof(struct tbd_struct);
-    if((void *)ptr > (void *)p->iscp)
-    {
-      printk("%s: not enough shared-mem for your configuration!\n",dev->name);
-      return 1;
-    }
-    memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
-    memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
-    p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
-    p->xmit_cmds[i]->cmd_status = STAT_COMPL;
-    p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT;
-    p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
-    p->xmit_buffs[i]->next = 0xffff;
-    p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
-  }
+	/*
+	 * alloc xmit-buffs / init xmit_cmds
+	 */
+	for(i=0;i<NUM_XMIT_BUFFS;i++)
+	{
+		p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
+		ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
+		p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
+		ptr = (char *) ptr + XMIT_BUFF_SIZE;
+		p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
+		ptr = (char *) ptr + sizeof(struct tbd_struct);
+		if((void *)ptr > (void *)p->iscp)
+		{
+			printk("%s: not enough shared-mem for your configuration!\n",dev->name);
+			return 1;
+		}
+		memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
+		memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
+		p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
+		p->xmit_cmds[i]->cmd_status = STAT_COMPL;
+		p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT;
+		p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
+		p->xmit_buffs[i]->next = 0xffff;
+		p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
+	}
 
-  p->xmit_count = 0;
-  p->xmit_last  = 0;
+	p->xmit_count = 0;
+	p->xmit_last	= 0;
 #ifndef NO_NOPCOMMANDS
-  p->nop_point  = 0;
+	p->nop_point	= 0;
 #endif
 
-   /*
-    * 'start transmitter'
-    */
+	 /*
+		* 'start transmitter'
+		*/
 #ifndef NO_NOPCOMMANDS
-  p->scb->cbl_offset = make16(p->nop_cmds[0]);
-  p->scb->cmd_cuc = CUC_START;
-  ni_attn586();
-  WAIT_4_SCB_CMD();
+	p->scb->cbl_offset = make16(p->nop_cmds[0]);
+	p->scb->cmd_cuc = CUC_START;
+	ni_attn586();
+	WAIT_4_SCB_CMD();
 #else
-  p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);
-  p->xmit_cmds[0]->cmd_cmd  = CMD_XMIT | CMD_SUSPEND | CMD_INT;
+	p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);
+	p->xmit_cmds[0]->cmd_cmd	= CMD_XMIT | CMD_SUSPEND | CMD_INT;
 #endif
 
-  /*
-   * ack. interrupts
-   */
-  p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
-  ni_attn586();
-  DELAY_16();
+	/*
+	 * ack. interrupts
+	 */
+	p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+	ni_attn586();
+	DELAY_16();
 
-  ni_enaint();
+	ni_enaint();
 
-  return 0;
+	return 0;
 }
 
 /******************************************************
@@ -769,43 +772,43 @@
 
 static void *alloc_rfa(struct device *dev,void *ptr)
 {
-  volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
-  volatile struct rbd_struct *rbd;
-  int i;
-  struct priv *p = (struct priv *) dev->priv;
-
-  memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
-  p->rfd_first = rfd;
-
-  for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {
-    rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );
-    rfd[i].rbd_offset = 0xffff;
-  }
-  rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP;   /* RU suspend */
-
-  ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );
-
-  rbd = (struct rbd_struct *) ptr;
-  ptr = (void *) (rbd + p->num_recv_buffs);
-
-   /* clr descriptors */
-  memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));
-
-  for(i=0;i<p->num_recv_buffs;i++)
-  {
-    rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
-    rbd[i].size = RECV_BUFF_SIZE;
-    rbd[i].buffer = make24(ptr);
-    ptr = (char *) ptr + RECV_BUFF_SIZE;
-  }
+	volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
+	volatile struct rbd_struct *rbd;
+	int i;
+	struct priv *p = (struct priv *) dev->priv;
+
+	memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
+	p->rfd_first = rfd;
+
+	for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {
+		rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );
+		rfd[i].rbd_offset = 0xffff;
+	}
+	rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP;	 /* RU suspend */
+
+	ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );
+
+	rbd = (struct rbd_struct *) ptr;
+	ptr = (void *) (rbd + p->num_recv_buffs);
+
+	 /* clr descriptors */
+	memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));
+
+	for(i=0;i<p->num_recv_buffs;i++)
+	{
+		rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
+		rbd[i].size = RECV_BUFF_SIZE;
+		rbd[i].buffer = make24(ptr);
+		ptr = (char *) ptr + RECV_BUFF_SIZE;
+	}
 
-  p->rfd_top  = p->rfd_first;
-  p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
+	p->rfd_top	= p->rfd_first;
+	p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
 
-  p->scb->rfa_offset		= make16(p->rfd_first);
-  p->rfd_first->rbd_offset	= make16(rbd);
+	p->scb->rfa_offset		= make16(p->rfd_first);
+	p->rfd_first->rbd_offset	= make16(rbd);
 
-  return ptr;
+	return ptr;
 }
 
 
@@ -815,76 +818,76 @@
 
 static void ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
 {
-  struct device *dev = (struct device *) irq2dev_map[irq];
-  unsigned short stat;
-  int cnt=0;
-  struct priv *p;
-
-  if (!dev) {
-    printk ("ni5210-interrupt: irq %d for unknown device.\n",irq);
-    return;
-  }
-  p = (struct priv *) dev->priv;
-
-  if(debuglevel > 1)
-    printk("I");
-
-  dev->interrupt = 1;
-
-  WAIT_4_SCB_CMD(); /* wait for last command  */
-
-  while((stat=p->scb->cus & STAT_MASK))
-  {
-    p->scb->cmd_cuc = stat;
-    ni_attn586();
-
-    if(stat & STAT_FR)   /* received a frame */
-      ni52_rcv_int(dev);
-
-    if(stat & STAT_RNR) /* RU went 'not ready' */
-    {
-      printk("(R)");
-      if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */
-      {
-        WAIT_4_SCB_CMD();
-        p->scb->cmd_ruc = RUC_RESUME;
-        ni_attn586();
-        WAIT_4_SCB_CMD_RUC();
-      }
-      else
-      {
-        printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);
-        ni52_rnr_int(dev);
-      }
-    }
+	struct device *dev = (struct device *) irq2dev_map[irq];
+	unsigned short stat;
+	int cnt=0;
+	struct priv *p;
+
+	if (!dev) {
+		printk ("ni5210-interrupt: irq %d for unknown device.\n",irq);
+		return;
+	}
+	p = (struct priv *) dev->priv;
+
+	if(debuglevel > 1)
+		printk("I");
+
+	dev->interrupt = 1;
+
+	WAIT_4_SCB_CMD(); /* wait for last command	*/
+
+	while((stat=p->scb->cus & STAT_MASK))
+	{
+		p->scb->cmd_cuc = stat;
+		ni_attn586();
+
+		if(stat & STAT_FR)	 /* received a frame */
+			ni52_rcv_int(dev);
+
+		if(stat & STAT_RNR) /* RU went 'not ready' */
+		{
+			printk("(R)");
+			if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */
+			{
+				WAIT_4_SCB_CMD();
+				p->scb->cmd_ruc = RUC_RESUME;
+				ni_attn586();
+				WAIT_4_SCB_CMD_RUC();
+			}
+			else
+			{
+				printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);
+				ni52_rnr_int(dev);
+			}
+		}
 
-    if(stat & STAT_CX)    /* command with I-bit set complete */
-       ni52_xmt_int(dev);
+		if(stat & STAT_CX)		/* command with I-bit set complete */
+			 ni52_xmt_int(dev);
 
 #ifndef NO_NOPCOMMANDS
-    if(stat & STAT_CNA)  /* CU went 'not ready' */
-    {
-      if(dev->start)
-        printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
-    }
+		if(stat & STAT_CNA)	/* CU went 'not ready' */
+		{
+			if(dev->start)
+				printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
+		}
 #endif
 
-    if(debuglevel > 1)
-      printk("%d",cnt++);
+		if(debuglevel > 1)
+			printk("%d",cnt++);
 
-    WAIT_4_SCB_CMD(); /* wait for ack. (ni52_xmt_int can be faster than ack!!) */
-    if(p->scb->cmd_cuc)   /* timed out? */
-    {
-      printk("%s: Acknowledge timed out.\n",dev->name);
-      ni_disint();
-      break;
-    }
-  }
+		WAIT_4_SCB_CMD(); /* wait for ack. (ni52_xmt_int can be faster than ack!!) */
+		if(p->scb->cmd_cuc)	 /* timed out? */
+		{
+			printk("%s: Acknowledge timed out.\n",dev->name);
+			ni_disint();
+			break;
+		}
+	}
 
-  if(debuglevel > 1)
-    printk("i");
+	if(debuglevel > 1)
+		printk("i");
 
-  dev->interrupt = 0;
+	dev->interrupt = 0;
 }
 
 /*******************************************************
@@ -893,121 +896,121 @@
 
 static void ni52_rcv_int(struct device *dev)
 {
-  int status,cnt=0;
-  unsigned short totlen;
-  struct sk_buff *skb;
-  struct rbd_struct *rbd;
-  struct priv *p = (struct priv *) dev->priv;
-
-  if(debuglevel > 0)
-    printk("R");
-
-  for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)
-  {
-      rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
-
-      if(status & RFD_OK) /* frame received without error? */
-      {
-        if( (totlen = rbd->status) & RBD_LAST) /* the first and the last buffer? */
-        {
-          totlen &= RBD_MASK; /* length of this frame */
-          rbd->status = 0;
-          skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
-          if(skb != NULL)
-          {
-            skb->dev = dev;
-            skb_reserve(skb,2);
-            skb_put(skb,totlen);
-            eth_copy_and_sum(skb,(char *) p->base+(unsigned long) rbd->buffer,totlen,0);
-            skb->protocol=eth_type_trans(skb,dev);
-            netif_rx(skb);
-            p->stats.rx_packets++;
-          }
-          else
-            p->stats.rx_dropped++;
-        }
-        else
-        {
-          int rstat;
-             /* free all RBD's until RBD_LAST is set */
-          totlen = 0;
-          while(!((rstat=rbd->status) & RBD_LAST))
-          {
-            totlen += rstat & RBD_MASK;
-            if(!rstat)
-            {
-              printk("%s: Whoops .. no end mark in RBD list\n",dev->name);
-              break;
-            }
-            rbd->status = 0;
-            rbd = (struct rbd_struct *) make32(rbd->next);
-          }
-          totlen += rstat & RBD_MASK;
-          rbd->status = 0;
-          printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
-          p->stats.rx_dropped++;
-       }
-      }
-      else /* frame !(ok), only with 'save-bad-frames' */
-      {
-        printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
-        p->stats.rx_errors++;
-      }
-      p->rfd_top->stat_high = 0;
-      p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
-      p->rfd_top->rbd_offset = 0xffff;
-      p->rfd_last->last = 0;        /* delete RFD_SUSP  */
-      p->rfd_last = p->rfd_top;
-      p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
-      p->scb->rfa_offset = make16(p->rfd_top);
-
-      if(debuglevel > 0)
-        printk("%d",cnt++);
-  }
-
-  if(automatic_resume)
-  {
-    WAIT_4_SCB_CMD();
-    p->scb->cmd_ruc = RUC_RESUME;
-    ni_attn586();
-    WAIT_4_SCB_CMD_RUC();
-  }
+	int status,cnt=0;
+	unsigned short totlen;
+	struct sk_buff *skb;
+	struct rbd_struct *rbd;
+	struct priv *p = (struct priv *) dev->priv;
+
+	if(debuglevel > 0)
+		printk("R");
+
+	for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)
+	{
+			rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
+
+			if(status & RFD_OK) /* frame received without error? */
+			{
+				if( (totlen = rbd->status) & RBD_LAST) /* the first and the last buffer? */
+				{
+					totlen &= RBD_MASK; /* length of this frame */
+					rbd->status = 0;
+					skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
+					if(skb != NULL)
+					{
+						skb->dev = dev;
+						skb_reserve(skb,2);
+						skb_put(skb,totlen);
+						eth_copy_and_sum(skb,(char *) p->base+(unsigned long) rbd->buffer,totlen,0);
+						skb->protocol=eth_type_trans(skb,dev);
+						netif_rx(skb);
+						p->stats.rx_packets++;
+					}
+					else
+						p->stats.rx_dropped++;
+				}
+				else
+				{
+					int rstat;
+						 /* free all RBD's until RBD_LAST is set */
+					totlen = 0;
+					while(!((rstat=rbd->status) & RBD_LAST))
+					{
+						totlen += rstat & RBD_MASK;
+						if(!rstat)
+						{
+							printk("%s: Whoops .. no end mark in RBD list\n",dev->name);
+							break;
+						}
+						rbd->status = 0;
+						rbd = (struct rbd_struct *) make32(rbd->next);
+					}
+					totlen += rstat & RBD_MASK;
+					rbd->status = 0;
+					printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
+					p->stats.rx_dropped++;
+			 }
+		}
+		else /* frame !(ok), only with 'save-bad-frames' */
+		{
+			printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
+			p->stats.rx_errors++;
+		}
+		p->rfd_top->stat_high = 0;
+		p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
+		p->rfd_top->rbd_offset = 0xffff;
+		p->rfd_last->last = 0;				/* delete RFD_SUSP	*/
+		p->rfd_last = p->rfd_top;
+		p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
+		p->scb->rfa_offset = make16(p->rfd_top);
+
+		if(debuglevel > 0)
+			printk("%d",cnt++);
+	}
+
+	if(automatic_resume)
+	{
+		WAIT_4_SCB_CMD();
+		p->scb->cmd_ruc = RUC_RESUME;
+		ni_attn586();
+		WAIT_4_SCB_CMD_RUC();
+	}
 
 #ifdef WAIT_4_BUSY
-  {
-    int i;
-    for(i=0;i<1024;i++)
-    {
-      if(p->rfd_top->status)
-        break;
-      DELAY_16();
-      if(i == 1023)
-        printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name);
-    }
-  }
+	{
+		int i;
+		for(i=0;i<1024;i++)
+		{
+			if(p->rfd_top->status)
+				break;
+			DELAY_16();
+			if(i == 1023)
+				printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name);
+		}
+	}
 #endif
 
 #ifdef 0
-  if(!at_least_one)
-  {
-    int i;
-    volatile struct rfd_struct *rfds=p->rfd_top;
-    volatile struct rbd_struct *rbds;
-    printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least);
-    for(i=0;i< (p->num_recv_buffs+4);i++)
-    {
-      rbds = (struct rbd_struct *) make32(rfds->rbd_offset);
-      printk("%04x:%04x ",rfds->status,rbds->status);
-      rfds = (struct rfd_struct *) make32(rfds->next);
-    }
-    printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status);
-    printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus);
-  }
-  old_at_least = at_least_one;
+	if(!at_least_one)
+	{
+		int i;
+		volatile struct rfd_struct *rfds=p->rfd_top;
+		volatile struct rbd_struct *rbds;
+		printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least);
+		for(i=0;i< (p->num_recv_buffs+4);i++)
+		{
+			rbds = (struct rbd_struct *) make32(rfds->rbd_offset);
+			printk("%04x:%04x ",rfds->status,rbds->status);
+			rfds = (struct rfd_struct *) make32(rfds->next);
+		}
+		printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status);
+		printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus);
+	}
+	old_at_least = at_least_one;
 #endif
 
-  if(debuglevel > 0)
-    printk("r");
+	if(debuglevel > 0)
+		printk("r");
 }
 
 /**********************************************************
@@ -1016,20 +1019,20 @@
 
 static void ni52_rnr_int(struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = (struct priv *) dev->priv;
 
-  p->stats.rx_errors++;
+	p->stats.rx_errors++;
 
-  WAIT_4_SCB_CMD();    /* wait for the last cmd, WAIT_4_FULLSTAT?? */
-  p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
-  ni_attn586();
-  WAIT_4_SCB_CMD_RUC();    /* wait for accept cmd. */
+	WAIT_4_SCB_CMD();		/* wait for the last cmd, WAIT_4_FULLSTAT?? */
+	p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
+	ni_attn586();
+	WAIT_4_SCB_CMD_RUC();		/* wait for accept cmd. */
 
-  alloc_rfa(dev,(char *)p->rfd_first);
+	alloc_rfa(dev,(char *)p->rfd_first);
 /* maybe add a check here, before restarting the RU */
-  startrecv586(dev); /* restart RU */
+	startrecv586(dev); /* restart RU */
 
-  printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus);
+	printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus);
 
 }
 
@@ -1039,51 +1042,51 @@
 
 static void ni52_xmt_int(struct device *dev)
 {
-  int status;
-  struct priv *p = (struct priv *) dev->priv;
+	int status;
+	struct priv *p = (struct priv *) dev->priv;
 
-  if(debuglevel > 0)
-    printk("X");
+	if(debuglevel > 0)
+		printk("X");
 
-  status = p->xmit_cmds[p->xmit_last]->cmd_status;
-  if(!(status & STAT_COMPL))
-    printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
-
-  if(status & STAT_OK)
-  {
-    p->stats.tx_packets++;
-    p->stats.collisions += (status & TCMD_MAXCOLLMASK);
-  }
-  else
-  {
-    p->stats.tx_errors++;
-    if(status & TCMD_LATECOLL) {
-      printk("%s: late collision detected.\n",dev->name);
-      p->stats.collisions++;
-    }
-    else if(status & TCMD_NOCARRIER) {
-      p->stats.tx_carrier_errors++;
-      printk("%s: no carrier detected.\n",dev->name);
-    }
-    else if(status & TCMD_LOSTCTS)
-      printk("%s: loss of CTS detected.\n",dev->name);
-    else if(status & TCMD_UNDERRUN) {
-      p->stats.tx_fifo_errors++;
-      printk("%s: DMA underrun detected.\n",dev->name);
-    }
-    else if(status & TCMD_MAXCOLL) {
-      printk("%s: Max. collisions exceeded.\n",dev->name);
-      p->stats.collisions += 16;
-    }
-  }
+	status = p->xmit_cmds[p->xmit_last]->cmd_status;
+	if(!(status & STAT_COMPL))
+		printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
+
+	if(status & STAT_OK)
+	{
+		p->stats.tx_packets++;
+		p->stats.collisions += (status & TCMD_MAXCOLLMASK);
+	}
+	else
+	{
+		p->stats.tx_errors++;
+		if(status & TCMD_LATECOLL) {
+			printk("%s: late collision detected.\n",dev->name);
+			p->stats.collisions++;
+		}
+		else if(status & TCMD_NOCARRIER) {
+			p->stats.tx_carrier_errors++;
+			printk("%s: no carrier detected.\n",dev->name);
+		}
+		else if(status & TCMD_LOSTCTS)
+			printk("%s: loss of CTS detected.\n",dev->name);
+		else if(status & TCMD_UNDERRUN) {
+			p->stats.tx_fifo_errors++;
+			printk("%s: DMA underrun detected.\n",dev->name);
+		}
+		else if(status & TCMD_MAXCOLL) {
+			printk("%s: Max. collisions exceeded.\n",dev->name);
+			p->stats.collisions += 16;
+		}
+	}
 
 #if (NUM_XMIT_BUFFS > 1)
-  if( (++p->xmit_last) == NUM_XMIT_BUFFS)
-    p->xmit_last = 0;
+	if( (++p->xmit_last) == NUM_XMIT_BUFFS)
+		p->xmit_last = 0;
 #endif
 
-  dev->tbusy = 0;
-  mark_bh(NET_BH);
+	dev->tbusy = 0;
+	mark_bh(NET_BH);
 }
 
 /***********************************************************
@@ -1092,14 +1095,14 @@
 
 static void startrecv586(struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = (struct priv *) dev->priv;
 
-  WAIT_4_SCB_CMD();
-  WAIT_4_SCB_CMD_RUC();
-  p->scb->rfa_offset = make16(p->rfd_first);
-  p->scb->cmd_ruc = RUC_START;
-  ni_attn586();		/* start cmd. */
-  WAIT_4_SCB_CMD_RUC();	/* wait for accept cmd. (no timeout!!) */
+	WAIT_4_SCB_CMD();
+	WAIT_4_SCB_CMD_RUC();
+	p->scb->rfa_offset = make16(p->rfd_first);
+	p->scb->cmd_ruc = RUC_START;
+	ni_attn586();		/* start cmd. */
+	WAIT_4_SCB_CMD_RUC();	/* wait for accept cmd. (no timeout!!) */
 }
 
 /******************************************************
@@ -1108,182 +1111,182 @@
 
 static int ni52_send_packet(struct sk_buff *skb, struct device *dev)
 {
-  int len,i;
+	int len,i;
 #ifndef NO_NOPCOMMANDS
-  int next_nop;
+	int next_nop;
 #endif
-  struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = (struct priv *) dev->priv;
 
-  if(dev->tbusy)
-  {
-    int tickssofar = jiffies - dev->trans_start;
-    if (tickssofar < 5)
-      return 1;
+	if(dev->tbusy)
+	{
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 5)
+			return 1;
 
 #ifndef NO_NOPCOMMANDS
-    if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
-    {
-      dev->tbusy = 0;
+		if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
+		{
+			dev->tbusy = 0;
 #ifdef DEBUG
-      printk("%s: strange ... timeout with CU active?!?\n",dev->name);
-      printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)p->xmit_cmds[0]->cmd_status,(int)p->nop_cmds[0]->cmd_status,(int)p->nop_cmds[1]->cmd_status,(int)p->nop_point);
+			printk("%s: strange ... timeout with CU active?!?\n",dev->name);
+			printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)p->xmit_cmds[0]->cmd_status,(int)p->nop_cmds[0]->cmd_status,(int)p->nop_cmds[1]->cmd_status,(int)p->nop_point);
 #endif
-      p->scb->cmd_cuc = CUC_ABORT;
-      ni_attn586();
-      WAIT_4_SCB_CMD();
-      p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
-      p->scb->cmd_cuc = CUC_START;
-      ni_attn586();
-      WAIT_4_SCB_CMD();
-      dev->trans_start = jiffies;
-      return 0;
-    }
-    else
+			p->scb->cmd_cuc = CUC_ABORT;
+			ni_attn586();
+			WAIT_4_SCB_CMD();
+			p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
+			p->scb->cmd_cuc = CUC_START;
+			ni_attn586();
+			WAIT_4_SCB_CMD();
+			dev->trans_start = jiffies;
+			return 0;
+		}
+		else
 #endif
-    {
+		{
 #ifdef DEBUG
-      printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
-      printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status);
-      printk("%s: check, whether you set the right interrupt number!\n",dev->name);
+			printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
+			printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status);
+			printk("%s: check, whether you set the right interrupt number!\n",dev->name);
 #endif
-      ni52_close(dev);
-      ni52_open(dev);
-    }
-    dev->trans_start = jiffies;
-    return 0;
-  }
-
-  if(skb == NULL)
-  {
-    dev_tint(dev);
-    return 0;
-  }
-
-  if (skb->len <= 0)
-    return 0;
-  if(skb->len > XMIT_BUFF_SIZE)
-  {
-    printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
-    return 0;
-  }
-
-  if (set_bit(0, (void*)&dev->tbusy)) {
-    printk("%s: Transmitter access conflict.\n", dev->name);
-    return 1;
-  }
+			ni52_close(dev);
+			ni52_open(dev);
+		}
+		dev->trans_start = jiffies;
+		return 0;
+	}
+
+	if(skb == NULL)
+	{
+		dev_tint(dev);
+		return 0;
+	}
+
+	if (skb->len <= 0)
+		return 0;
+	if(skb->len > XMIT_BUFF_SIZE)
+	{
+		printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
+		return 0;
+	}
+
+	if (set_bit(0, (void*)&dev->tbusy)) {
+		printk("%s: Transmitter access conflict.\n", dev->name);
+		return 1;
+	}
 #if(NUM_XMIT_BUFFS > 1)
-  else if(set_bit(0,(void *) &p->lock)) {
-    printk("%s: Queue was locked\n",dev->name);
-    return 1;
-  }
+	else if(set_bit(0,(void *) &p->lock)) {
+		printk("%s: Queue was locked\n",dev->name);
+		return 1;
+	}
 #endif
-  else
-  {
-    memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
-    len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+	else
+	{
+		memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
+		len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
 
 #if (NUM_XMIT_BUFFS == 1)
-#  ifdef NO_NOPCOMMANDS
+#	ifdef NO_NOPCOMMANDS
 
 #ifdef DEBUG
-    if(p->scb->cus & CU_ACTIVE)
-    {
-      printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name);
-      printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,p->xmit_cmds[0]->cmd_status);
-    }
+		if(p->scb->cus & CU_ACTIVE)
+		{
+			printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name);
+			printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,p->xmit_cmds[0]->cmd_status);
+		}
 #endif
 
-    p->xmit_buffs[0]->size = TBD_LAST | len;
-    for(i=0;i<16;i++)
-    {
-      p->xmit_cmds[0]->cmd_status = 0;
-      WAIT_4_SCB_CMD();
-      if( (p->scb->cus & CU_STATUS) == CU_SUSPEND)
-        p->scb->cmd_cuc = CUC_RESUME;
-      else
-      {
-        p->scb->cbl_offset = make16(p->xmit_cmds[0]);
-        p->scb->cmd_cuc = CUC_START;
-      }
-
-      ni_attn586();
-      dev->trans_start = jiffies;
-      if(!i)
-        dev_kfree_skb(skb,FREE_WRITE);
-      WAIT_4_SCB_CMD();
-      if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
-        break;
-      if(p->xmit_cmds[0]->cmd_status)
-        break;
-      if(i==15)
-        printk("%s: Can't start transmit-command.\n",dev->name);
-    }
-#  else
-    next_nop = (p->nop_point + 1) & 0x1;
-    p->xmit_buffs[0]->size = TBD_LAST | len;
-
-    p->xmit_cmds[0]->cmd_link   = p->nop_cmds[next_nop]->cmd_link
-                                = make16((p->nop_cmds[next_nop]));
-    p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
-
-    p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
-    dev->trans_start = jiffies;
-    p->nop_point = next_nop;
-    dev_kfree_skb(skb,FREE_WRITE);
-#  endif
+		p->xmit_buffs[0]->size = TBD_LAST | len;
+		for(i=0;i<16;i++)
+		{
+			p->xmit_cmds[0]->cmd_status = 0;
+			WAIT_4_SCB_CMD();
+			if( (p->scb->cus & CU_STATUS) == CU_SUSPEND)
+				p->scb->cmd_cuc = CUC_RESUME;
+			else
+			{
+				p->scb->cbl_offset = make16(p->xmit_cmds[0]);
+				p->scb->cmd_cuc = CUC_START;
+			}
+
+			ni_attn586();
+			dev->trans_start = jiffies;
+			if(!i)
+				dev_kfree_skb(skb,FREE_WRITE);
+			WAIT_4_SCB_CMD();
+			if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
+				break;
+			if(p->xmit_cmds[0]->cmd_status)
+				break;
+			if(i==15)
+				printk("%s: Can't start transmit-command.\n",dev->name);
+		}
+#	else
+		next_nop = (p->nop_point + 1) & 0x1;
+		p->xmit_buffs[0]->size = TBD_LAST | len;
+
+		p->xmit_cmds[0]->cmd_link	 = p->nop_cmds[next_nop]->cmd_link
+																= make16((p->nop_cmds[next_nop]));
+		p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
+
+		p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
+		dev->trans_start = jiffies;
+		p->nop_point = next_nop;
+		dev_kfree_skb(skb,FREE_WRITE);
+#	endif
 #else
-    p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
-    if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
-      next_nop = 0;
+		p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
+		if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
+			next_nop = 0;
 
-    p->xmit_cmds[p->xmit_count]->cmd_status  = 0;
+		p->xmit_cmds[p->xmit_count]->cmd_status	= 0;
 	/* linkpointer of xmit-command already points to next nop cmd */
-    p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
-    p->nop_cmds[next_nop]->cmd_status = 0;
+		p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
+		p->nop_cmds[next_nop]->cmd_status = 0;
 
-    p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
-    dev->trans_start = jiffies;
-    p->xmit_count = next_nop;
-
-    {
-      long flags;
-      save_flags(flags);
-      cli();
-      if(p->xmit_count != p->xmit_last)
-        dev->tbusy = 0;
-      p->lock = 0;
-      restore_flags(flags);
-    }
-    dev_kfree_skb(skb,FREE_WRITE);
+		p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
+		dev->trans_start = jiffies;
+		p->xmit_count = next_nop;
+
+		{
+			long flags;
+			save_flags(flags);
+			cli();
+			if(p->xmit_count != p->xmit_last)
+				dev->tbusy = 0;
+			p->lock = 0;
+			restore_flags(flags);
+		}
+		dev_kfree_skb(skb,FREE_WRITE);
 #endif
-  }
-  return 0;
+	}
+	return 0;
 }
 
 /*******************************************
  * Someone wanna have the statistics
  */
 
-static struct enet_statistics *ni52_get_stats(struct device *dev)
+static struct net_device_stats *ni52_get_stats(struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
-  unsigned short crc,aln,rsc,ovrn;
+	struct priv *p = (struct priv *) dev->priv;
+	unsigned short crc,aln,rsc,ovrn;
 
-  crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */
-  p->scb->crc_errs = 0;
-  aln = p->scb->aln_errs;
-  p->scb->aln_errs = 0;
-  rsc = p->scb->rsc_errs;
-  p->scb->rsc_errs = 0;
-  ovrn = p->scb->ovrn_errs;
-  p->scb->ovrn_errs = 0;
-
-  p->stats.rx_crc_errors += crc;
-  p->stats.rx_fifo_errors += ovrn;
-  p->stats.rx_frame_errors += aln;
-  p->stats.rx_dropped += rsc;
+	crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */
+	p->scb->crc_errs = 0;
+	aln = p->scb->aln_errs;
+	p->scb->aln_errs = 0;
+	rsc = p->scb->rsc_errs;
+	p->scb->rsc_errs = 0;
+	ovrn = p->scb->ovrn_errs;
+	p->scb->ovrn_errs = 0;
+
+	p->stats.rx_crc_errors += crc;
+	p->stats.rx_fifo_errors += ovrn;
+	p->stats.rx_frame_errors += aln;
+	p->stats.rx_dropped += rsc;
 
-  return &p->stats;
+	return &p->stats;
 }
 
 /********************************************************
@@ -1291,35 +1294,35 @@
  */
 static void set_multicast_list(struct device *dev)
 {
-  if(!dev->start)
-  {
-    printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name);
-    return;
-  }
-
-  dev->start = 0;
-
-  ni_disint();
-  alloc586(dev);
-  init586(dev);
-  startrecv586(dev);
-  ni_enaint();
+	if(!dev->start)
+	{
+		printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name);
+		return;
+	}
+
+	dev->start = 0;
+
+	ni_disint();
+	alloc586(dev);
+	init586(dev);
+	startrecv586(dev);
+	ni_enaint();
 
-  dev->start = 1;
+	dev->start = 1;
 }
 
 #ifdef MODULE
 static struct device dev_ni52 = {
-  "        ",  /* "ni5210": device name inserted by net_init.c */
-  0, 0, 0, 0,
-  0x300, 9,   /* I/O address, IRQ */
-  0, 0, 0, NULL, ni52_probe };
+	"				",	/* "ni5210": device name inserted by net_init.c */
+	0, 0, 0, 0,
+	0x300, 9,	 /* I/O address, IRQ */
+	0, 0, 0, NULL, ni52_probe };
 
 /* set: io,irq,memstart,memend or set it when calling insmod */
 int irq=9;
 int io=0x300;
 long memstart=0; /* e.g 0xd0000 */
-long memend=0;   /* e.g 0xd4000 */
+long memend=0;	 /* e.g 0xd4000 */
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
@@ -1328,25 +1331,25 @@
 
 int init_module(void)
 {
-  if(io <= 0x0 || !memend || !memstart || irq < 2) {
-    printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
-    return -ENODEV;
-  }
-  dev_ni52.irq = irq;
-  dev_ni52.base_addr = io;
-  dev_ni52.mem_end = memend;
-  dev_ni52.mem_start = memstart;
-  if (register_netdev(&dev_ni52) != 0)
-    return -EIO;
-  return 0;
+	if(io <= 0x0 || !memend || !memstart || irq < 2) {
+		printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
+		return -ENODEV;
+	}
+	dev_ni52.irq = irq;
+	dev_ni52.base_addr = io;
+	dev_ni52.mem_end = memend;
+	dev_ni52.mem_start = memstart;
+	if (register_netdev(&dev_ni52) != 0)
+		return -EIO;
+	return 0;
 }
 
 void cleanup_module(void)
 {
-  release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE);
-  kfree(dev_ni52.priv);
-  dev_ni52.priv = NULL;
-  unregister_netdev(&dev_ni52);
+	release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE);
+	kfree(dev_ni52.priv);
+	dev_ni52.priv = NULL;
+	unregister_netdev(&dev_ni52);
 }
 #endif /* MODULE */
 
@@ -1356,34 +1359,34 @@
  */
 void ni52_dump(struct device *dev,void *ptr)
 {
-  struct priv *p = (struct priv *) dev->priv;
-  struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
-  int i;
-
-  p->scb->cmd_cuc = CUC_ABORT;
-  ni_attn586();
-  WAIT_4_SCB_CMD();
-  WAIT_4_SCB_CMD_RUC();
-
-  dump_cmd->cmd_status = 0;
-  dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST;
-  dump_cmd->dump_offset = make16((dump_cmd + 1));
-  dump_cmd->cmd_link = 0xffff;
-
-  p->scb->cbl_offset = make16(dump_cmd);
-  p->scb->cmd_cuc = CUC_START;
-  ni_attn586();
-  WAIT_4_STAT_COMPL(dump_cmd);
-
-  if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
-        printk("%s: Can't get dump information.\n",dev->name);
-
-  for(i=0;i<170;i++) {
-    printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]);
-    if(i % 24 == 23)
-      printk("\n");
-  }
-  printk("\n");
+	struct priv *p = (struct priv *) dev->priv;
+	struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
+	int i;
+
+	p->scb->cmd_cuc = CUC_ABORT;
+	ni_attn586();
+	WAIT_4_SCB_CMD();
+	WAIT_4_SCB_CMD_RUC();
+
+	dump_cmd->cmd_status = 0;
+	dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST;
+	dump_cmd->dump_offset = make16((dump_cmd + 1));
+	dump_cmd->cmd_link = 0xffff;
+
+	p->scb->cbl_offset = make16(dump_cmd);
+	p->scb->cmd_cuc = CUC_START;
+	ni_attn586();
+	WAIT_4_STAT_COMPL(dump_cmd);
+
+	if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+				printk("%s: Can't get dump information.\n",dev->name);
+
+	for(i=0;i<170;i++) {
+		printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]);
+		if(i % 24 == 23)
+			printk("\n");
+	}
+	printk("\n");
 }
 #endif
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v2.1.24/linux/drivers/net/ni65.c	Tue Dec 31 21:41:05 1996
+++ linux/drivers/net/ni65.c	Sun Feb  2 15:18:40 1997
@@ -195,27 +195,27 @@
 
 struct priv
 {
-  struct rmd rmdhead[RMDNUM];
-  struct tmd tmdhead[TMDNUM];
-  struct init_block ib;
-  int rmdnum;
-  int tmdnum,tmdlast;
+	struct rmd rmdhead[RMDNUM];
+	struct tmd tmdhead[TMDNUM];
+	struct init_block ib;
+	int rmdnum;
+	int tmdnum,tmdlast;
 #ifdef RCV_VIA_SKB
-  struct sk_buff *recv_skb[RMDNUM];
+	struct sk_buff *recv_skb[RMDNUM];
 #else
-  void *recvbounce[RMDNUM];
+	void *recvbounce[RMDNUM];
 #endif
 #ifdef XMT_VIA_SKB
-  struct sk_buff *tmd_skb[TMDNUM];
+	struct sk_buff *tmd_skb[TMDNUM];
 #endif
-  void *tmdbounce[TMDNUM];
-  int tmdbouncenum;
-  int lock,xmit_queued;
-  struct enet_statistics stats;
-  void *self;
-  int cmdr_addr;
-  int cardno;
-  int features;
+	void *tmdbounce[TMDNUM];
+	int tmdbouncenum;
+	int lock,xmit_queued;
+	struct net_device_stats stats;
+	void *self;
+	int cmdr_addr;
+	int cardno;
+	int features;
 };
 
 static int  ni65_probe1(struct device *dev,int);
@@ -229,7 +229,7 @@
 static int  ni65_close(struct device *dev);
 static int  ni65_alloc_buffer(struct device *dev);
 static void ni65_free_buffer(struct priv *p);
-static struct enet_statistics *ni65_get_stats(struct device *);
+static struct net_device_stats *ni65_get_stats(struct device *);
 static void set_multicast_list(struct device *dev);
 
 static int irqtab[] = { 9,12,15,5 }; /* irq config-translate */
@@ -242,22 +242,22 @@
  */
 static void ni65_set_performance(struct priv *p)
 {
-  writereg(CSR0_STOP | CSR0_CLRALL,CSR0); /* STOP */
+	writereg(CSR0_STOP | CSR0_CLRALL,CSR0); /* STOP */
 
-  if( !(cards[p->cardno].config & 0x02) )
-    return;
+	if( !(cards[p->cardno].config & 0x02) )
+		return;
 
-  outw(80,PORT+L_ADDRREG);
-  if(inw(PORT+L_ADDRREG) != 80)
-    return;
-
-  writereg( (csr80 & 0x3fff) ,80); /* FIFO watermarks */
-  outw(0,PORT+L_ADDRREG);
-  outw((short)isa0,PORT+L_BUSIF); /* write ISA 0: DMA_R : isa0 * 50ns */
-  outw(1,PORT+L_ADDRREG);
-  outw((short)isa1,PORT+L_BUSIF); /* write ISA 1: DMA_W : isa1 * 50ns  */
+	outw(80,PORT+L_ADDRREG);
+	if(inw(PORT+L_ADDRREG) != 80)
+		return;
+
+	writereg( (csr80 & 0x3fff) ,80); /* FIFO watermarks */
+	outw(0,PORT+L_ADDRREG);
+	outw((short)isa0,PORT+L_BUSIF); /* write ISA 0: DMA_R : isa0 * 50ns */
+	outw(1,PORT+L_ADDRREG);
+	outw((short)isa1,PORT+L_BUSIF); /* write ISA 1: DMA_W : isa1 * 50ns	*/
 
-  outw(CSR0,PORT+L_ADDRREG);	/* switch back to CSR0 */
+	outw(CSR0,PORT+L_ADDRREG);	/* switch back to CSR0 */
 }
 
 /*
@@ -265,31 +265,31 @@
  */
 static int ni65_open(struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
-  int irqval = request_irq(dev->irq, &ni65_interrupt,0,
+	struct priv *p = (struct priv *) dev->priv;
+	int irqval = request_irq(dev->irq, &ni65_interrupt,0,
                         cards[p->cardno].cardname,NULL);
-  if (irqval) {
-    printk ("%s: unable to get IRQ %d (irqval=%d).\n",
-              dev->name,dev->irq, irqval);
-    return -EAGAIN;
-  }
-  irq2dev_map[dev->irq] = dev;
-
-  if(ni65_lance_reinit(dev))
-  {
-    dev->tbusy     = 0;
-    dev->interrupt = 0;
-    dev->start     = 1;
-    MOD_INC_USE_COUNT;
-    return 0;
-  }
-  else
-  {
-    irq2dev_map[dev->irq] = NULL;
-    free_irq(dev->irq,NULL);
-    dev->start = 0;
-    return -EAGAIN;
-  }
+	if (irqval) {
+		printk ("%s: unable to get IRQ %d (irqval=%d).\n",
+		          dev->name,dev->irq, irqval);
+		return -EAGAIN;
+	}
+	irq2dev_map[dev->irq] = dev;
+
+	if(ni65_lance_reinit(dev))
+	{
+		dev->tbusy     = 0;
+		dev->interrupt = 0;
+		dev->start     = 1;
+		MOD_INC_USE_COUNT;
+		return 0;
+	}
+	else
+	{
+		irq2dev_map[dev->irq] = NULL;
+		free_irq(dev->irq,NULL);
+		dev->start = 0;
+		return -EAGAIN;
+	}
 }
 
 /*
@@ -297,28 +297,28 @@
  */
 static int ni65_close(struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = (struct priv *) dev->priv;
 
-  outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */
+	outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */
 
 #ifdef XMT_VIA_SKB
-  {
-    int i;
-    for(i=0;i<TMDNUM;i++)
-    {
-      if(p->tmd_skb[i]) {
-        dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
-        p->tmd_skb[i] = NULL;
-      }
-    }
-  }
-#endif
-  irq2dev_map[dev->irq] = NULL;
-  free_irq(dev->irq,NULL);
-  dev->tbusy = 1;
-  dev->start = 0;
-  MOD_DEC_USE_COUNT;
-  return 0;
+	{
+		int i;
+		for(i=0;i<TMDNUM;i++)
+		{
+			if(p->tmd_skb[i]) {
+				dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
+				p->tmd_skb[i] = NULL;
+			}
+		}
+	}
+#endif
+	irq2dev_map[dev->irq] = NULL;
+	free_irq(dev->irq,NULL);
+	dev->tbusy = 1;
+	dev->start = 0;
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 /*
@@ -329,21 +329,21 @@
 #endif
 int ni65_probe(struct device *dev)
 {
-  int *port;
-  static int ports[] = {0x360,0x300,0x320,0x340, 0};
+	int *port;
+	static int ports[] = {0x360,0x300,0x320,0x340, 0};
 
-  if (dev->base_addr > 0x1ff)          /* Check a single specified location. */
-     return ni65_probe1(dev, dev->base_addr);
-  else if (dev->base_addr > 0)         /* Don't probe at all. */
-     return -ENXIO;
-
-  for (port = ports; *port; port++)
-  {
-    if (ni65_probe1(dev, *port) == 0)
-       return 0;
-  }
+	if (dev->base_addr > 0x1ff)          /* Check a single specified location. */
+		 return ni65_probe1(dev, dev->base_addr);
+	else if (dev->base_addr > 0)         /* Don't probe at all. */
+		 return -ENXIO;
+
+	for (port = ports; *port; port++)
+	{
+		if (ni65_probe1(dev, *port) == 0)
+			 return 0;
+	}
 
-  return -ENODEV;
+	return -ENODEV;
 }
 
 /*
@@ -351,139 +351,139 @@
  */
 static int ni65_probe1(struct device *dev,int ioaddr)
 {
-  int i,j;
-  struct priv *p;
+	int i,j;
+	struct priv *p;
 
-  for(i=0;i<NUM_CARDS;i++) {
-    if(check_region(ioaddr, cards[i].total_size))
-      continue;
-    if(cards[i].id_offset >= 0) {
-      if(inb(ioaddr+cards[i].id_offset+0) != cards[i].id0 ||
-         inb(ioaddr+cards[i].id_offset+1) != cards[i].id1) {
-         continue;
-      }
-    }
-    if(cards[i].vendor_id) {
-      for(j=0;j<3;j++)
-        if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j])
-          continue;
-    }
-    break;
-  }
-  if(i == NUM_CARDS)
-    return -ENODEV;
-
-  for(j=0;j<6;j++)
-    dev->dev_addr[j] = inb(ioaddr+cards[i].addr_offset+j);
-
-  if( (j=ni65_alloc_buffer(dev)) < 0)
-    return j;
-  p = (struct priv *) dev->priv;
-  p->cmdr_addr = ioaddr + cards[i].cmd_offset;
-  p->cardno = i;
-
-  printk("%s: %s found at %#3x, ", dev->name, cards[p->cardno].cardname , ioaddr);
-
-  outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
-  if( (j=readreg(CSR0)) != 0x4) {
-     printk(KERN_ERR "can't RESET card: %04x\n",j);
-     ni65_free_buffer(p);
-     return -EAGAIN;
-  }
-
-  outw(88,PORT+L_ADDRREG);
-  if(inw(PORT+L_ADDRREG) == 88) {
-    unsigned long v;
-    v = inw(PORT+L_DATAREG);
-    v <<= 16;
-    outw(89,PORT+L_ADDRREG);
-    v |= inw(PORT+L_DATAREG);
-    printk("Version %#08lx, ",v);
-    p->features = INIT_RING_BEFORE_START;
-  }
-  else {
-    printk("ancient LANCE, ");
-    p->features = 0x0;
-  }
-
-  if(test_bit(0,&cards[i].config)) {
-    dev->irq = irqtab[(inw(ioaddr+L_CONFIG)>>2)&3];
-    dev->dma = dmatab[inw(ioaddr+L_CONFIG)&3];
-    printk("IRQ %d (from card), DMA %d (from card).\n",dev->irq,dev->dma);
-  }
-  else {
-    if(dev->dma == 0) {
+	for(i=0;i<NUM_CARDS;i++) {
+		if(check_region(ioaddr, cards[i].total_size))
+			continue;
+		if(cards[i].id_offset >= 0) {
+			if(inb(ioaddr+cards[i].id_offset+0) != cards[i].id0 ||
+				 inb(ioaddr+cards[i].id_offset+1) != cards[i].id1) {
+				 continue;
+			}
+		}
+		if(cards[i].vendor_id) {
+			for(j=0;j<3;j++)
+				if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j])
+					continue;
+		}
+		break;
+	}
+	if(i == NUM_CARDS)
+		return -ENODEV;
+
+	for(j=0;j<6;j++)
+		dev->dev_addr[j] = inb(ioaddr+cards[i].addr_offset+j);
+
+	if( (j=ni65_alloc_buffer(dev)) < 0)
+		return j;
+	p = (struct priv *) dev->priv;
+	p->cmdr_addr = ioaddr + cards[i].cmd_offset;
+	p->cardno = i;
+
+	printk("%s: %s found at %#3x, ", dev->name, cards[p->cardno].cardname , ioaddr);
+
+	outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
+	if( (j=readreg(CSR0)) != 0x4) {
+		 printk(KERN_ERR "can't RESET card: %04x\n",j);
+		 ni65_free_buffer(p);
+		 return -EAGAIN;
+	}
+
+	outw(88,PORT+L_ADDRREG);
+	if(inw(PORT+L_ADDRREG) == 88) {
+		unsigned long v;
+		v = inw(PORT+L_DATAREG);
+		v <<= 16;
+		outw(89,PORT+L_ADDRREG);
+		v |= inw(PORT+L_DATAREG);
+		printk("Version %#08lx, ",v);
+		p->features = INIT_RING_BEFORE_START;
+	}
+	else {
+		printk("ancient LANCE, ");
+		p->features = 0x0;
+	}
+
+	if(test_bit(0,&cards[i].config)) {
+		dev->irq = irqtab[(inw(ioaddr+L_CONFIG)>>2)&3];
+		dev->dma = dmatab[inw(ioaddr+L_CONFIG)&3];
+		printk("IRQ %d (from card), DMA %d (from card).\n",dev->irq,dev->dma);
+	}
+	else {
+		if(dev->dma == 0) {
 		/* 'stuck test' from lance.c */
-      int dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | (inb(DMA2_STAT_REG) & 0xf0);
-      for(i=1;i<5;i++) {
-        int dma = dmatab[i];
-        if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510"))
-          continue;
-        disable_dma(dma);
-        set_dma_mode(dma,DMA_MODE_CASCADE);
-        enable_dma(dma);
-        ni65_init_lance(p,dev->dev_addr,0,0); /* trigger memory access */
-        disable_dma(dma);
-        free_dma(dma);
-        if(readreg(CSR0) & CSR0_IDON)
-          break;
-      }
-      if(i == 5) {
-        printk("Can't detect DMA channel!\n");
-        ni65_free_buffer(p);
-        return -EAGAIN;
-      }
-      dev->dma = dmatab[i];
-      printk("DMA %d (autodetected), ",dev->dma);
-    }
-    else
-      printk("DMA %d (assigned), ",dev->dma);
-
-    if(dev->irq < 2)
-    {
-      ni65_init_lance(p,dev->dev_addr,0,0);
-      autoirq_setup(0);
-      writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */
-
-      if(!(dev->irq = autoirq_report(2)))
-      {
-        printk("Failed to detect IRQ line!\n");
-        ni65_free_buffer(p);
-        return -EAGAIN;
-      }
-      printk("IRQ %d (autodetected).\n",dev->irq);
-    }
-    else
-      printk("IRQ %d (assigned).\n",dev->irq);
-  }
-
-  if(request_dma(dev->dma, cards[p->cardno].cardname ) != 0)
-  {
-    printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma);
-    ni65_free_buffer(p);
-    return -EAGAIN;
-  }
-
-  /*
-   * Grab the region so we can find another board.
-   */
-  request_region(ioaddr,cards[p->cardno].total_size,cards[p->cardno].cardname);
-
-  dev->base_addr = ioaddr;
-
-  dev->open               = ni65_open;
-  dev->stop               = ni65_close;
-  dev->hard_start_xmit    = ni65_send_packet;
-  dev->get_stats          = ni65_get_stats;
-  dev->set_multicast_list = set_multicast_list;
-
-  ether_setup(dev);
-
-  dev->interrupt      = 0;
-  dev->tbusy          = 0;
-  dev->start          = 0;
+			int dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | (inb(DMA2_STAT_REG) & 0xf0);
+			for(i=1;i<5;i++) {
+				int dma = dmatab[i];
+				if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510"))
+					continue;
+				disable_dma(dma);
+				set_dma_mode(dma,DMA_MODE_CASCADE);
+				enable_dma(dma);
+				ni65_init_lance(p,dev->dev_addr,0,0); /* trigger memory access */
+				disable_dma(dma);
+				free_dma(dma);
+				if(readreg(CSR0) & CSR0_IDON)
+					break;
+			}
+			if(i == 5) {
+				printk("Can't detect DMA channel!\n");
+				ni65_free_buffer(p);
+				return -EAGAIN;
+			}
+			dev->dma = dmatab[i];
+			printk("DMA %d (autodetected), ",dev->dma);
+		}
+		else
+			printk("DMA %d (assigned), ",dev->dma);
+
+		if(dev->irq < 2)
+		{
+			ni65_init_lance(p,dev->dev_addr,0,0);
+			autoirq_setup(0);
+			writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */
+
+			if(!(dev->irq = autoirq_report(2)))
+			{
+				printk("Failed to detect IRQ line!\n");
+				ni65_free_buffer(p);
+				return -EAGAIN;
+			}
+			printk("IRQ %d (autodetected).\n",dev->irq);
+		}
+		else
+			printk("IRQ %d (assigned).\n",dev->irq);
+	}
+
+	if(request_dma(dev->dma, cards[p->cardno].cardname ) != 0)
+	{
+		printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma);
+		ni65_free_buffer(p);
+		return -EAGAIN;
+	}
+
+	/*
+	 * Grab the region so we can find another board.
+	 */
+	request_region(ioaddr,cards[p->cardno].total_size,cards[p->cardno].cardname);
+
+	dev->base_addr = ioaddr;
+
+	dev->open		= ni65_open;
+	dev->stop		= ni65_close;
+	dev->hard_start_xmit	= ni65_send_packet;
+	dev->get_stats		= ni65_get_stats;
+	dev->set_multicast_list = set_multicast_list;
+
+	ether_setup(dev);
+
+	dev->interrupt		= 0;
+	dev->tbusy		= 0;
+	dev->start		= 0;
 
-  return 0; /* everything is OK */
+	return 0; /* everything is OK */
 }
 
 /*
@@ -491,33 +491,33 @@
  */
 static void ni65_init_lance(struct priv *p,unsigned char *daddr,int filter,int mode)
 {
-  int i;
-  u32 pib;
+	int i;
+	u32 pib;
 
-  writereg(CSR0_CLRALL|CSR0_STOP,CSR0);
+	writereg(CSR0_CLRALL|CSR0_STOP,CSR0);
 
-  for(i=0;i<6;i++)
-    p->ib.eaddr[i] = daddr[i];
+	for(i=0;i<6;i++)
+		p->ib.eaddr[i] = daddr[i];
 
-  for(i=0;i<8;i++)
-    p->ib.filter[i] = filter;
-  p->ib.mode = mode;
-
-  p->ib.trp = (u32) virt_to_bus(p->tmdhead) | TMDNUMMASK;
-  p->ib.rrp = (u32) virt_to_bus(p->rmdhead) | RMDNUMMASK;
-  writereg(0,CSR3);  /* busmaster/no word-swap */
-  pib = (u32) virt_to_bus(&p->ib);
-  writereg(pib & 0xffff,CSR1);
-  writereg(pib >> 16,CSR2);
-
-  writereg(CSR0_INIT,CSR0); /* this changes L_ADDRREG to CSR0 */
-
-  for(i=0;i<32;i++)
-  {
-    udelay(4000);
-    if(inw(PORT+L_DATAREG) & (CSR0_IDON | CSR0_MERR) )
-      break; /* init ok ? */
-  }
+	for(i=0;i<8;i++)
+		p->ib.filter[i] = filter;
+	p->ib.mode = mode;
+
+	p->ib.trp = (u32) virt_to_bus(p->tmdhead) | TMDNUMMASK;
+	p->ib.rrp = (u32) virt_to_bus(p->rmdhead) | RMDNUMMASK;
+	writereg(0,CSR3);	/* busmaster/no word-swap */
+	pib = (u32) virt_to_bus(&p->ib);
+	writereg(pib & 0xffff,CSR1);
+	writereg(pib >> 16,CSR2);
+
+	writereg(CSR0_INIT,CSR0); /* this changes L_ADDRREG to CSR0 */
+
+	for(i=0;i<32;i++)
+	{
+		udelay(4000);
+		if(inw(PORT+L_DATAREG) & (CSR0_IDON | CSR0_MERR) )
+			break; /* init ok ? */
+	}
 }
 
 /*
@@ -525,37 +525,37 @@
  */
 static void *ni65_alloc_mem(struct device *dev,char *what,int size,int type)
 {
-  struct sk_buff *skb=NULL;
-  unsigned char *ptr;
-  void *ret;
-
-  if(type) {
-    ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA);
-    if(!skb) {
-      printk("%s: unable to allocate %s memory.\n",dev->name,what);
-      return NULL;
-    }
-    skb->dev = dev;
-    skb_reserve(skb,2+16);
-    skb_put(skb,R_BUF_SIZE);   /* grab the whole space .. (not necessary) */
-    ptr = skb->data;
-  }
-  else {
-    ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA);
-    if(!ret) {
-      printk("%s: unable to allocate %s memory.\n",dev->name,what);
-      return NULL;
-    }
-  }
-  if( (u32) virt_to_bus(ptr+size) > 0x1000000) {
-    printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what);
-    if(type)
-      kfree_skb(skb,FREE_WRITE);
-    else
-      kfree(ptr);
-    return NULL;
-  }
-  return ret;
+	struct sk_buff *skb=NULL;
+	unsigned char *ptr;
+	void *ret;
+
+	if(type) {
+		ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA);
+		if(!skb) {
+			printk("%s: unable to allocate %s memory.\n",dev->name,what);
+			return NULL;
+		}
+		skb->dev = dev;
+		skb_reserve(skb,2+16);
+		skb_put(skb,R_BUF_SIZE);	 /* grab the whole space .. (not necessary) */
+		ptr = skb->data;
+	}
+	else {
+		ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA);
+		if(!ret) {
+			printk("%s: unable to allocate %s memory.\n",dev->name,what);
+			return NULL;
+		}
+	}
+	if( (u32) virt_to_bus(ptr+size) > 0x1000000) {
+		printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what);
+		if(type)
+			kfree_skb(skb,FREE_WRITE);
+		else
+			kfree(ptr);
+		return NULL;
+	}
+	return ret;
 }
 
 /*
@@ -563,51 +563,51 @@
  */
 static int ni65_alloc_buffer(struct device *dev)
 {
-  unsigned char *ptr;
-  struct priv *p;
-  int i;
-
-  /*
-   * we need 8-aligned memory ..
-   */
-  ptr = ni65_alloc_mem(dev,"BUFFER",sizeof(struct priv)+8,0);
-  if(!ptr)
-    return -ENOMEM;
-
-  p = dev->priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7);
-  memset((char *) dev->priv,0,sizeof(struct priv));
-  p->self = ptr;
+	unsigned char *ptr;
+	struct priv *p;
+	int i;
+
+	/*
+	 * we need 8-aligned memory ..
+	 */
+	ptr = ni65_alloc_mem(dev,"BUFFER",sizeof(struct priv)+8,0);
+	if(!ptr)
+		return -ENOMEM;
+
+	p = dev->priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7);
+	memset((char *) dev->priv,0,sizeof(struct priv));
+	p->self = ptr;
+
+	for(i=0;i<TMDNUM;i++)
+	{
+#ifdef XMT_VIA_SKB
+		p->tmd_skb[i] = NULL;
+#endif
+		p->tmdbounce[i] = ni65_alloc_mem(dev,"XMIT",T_BUF_SIZE,0);
+		if(!p->tmdbounce[i]) {
+			ni65_free_buffer(p);
+			return -ENOMEM;
+		}
+	}
 
-  for(i=0;i<TMDNUM;i++)
-  {
-#ifdef XMT_VIA_SKB
-    p->tmd_skb[i] = NULL;
-#endif
-    p->tmdbounce[i] = ni65_alloc_mem(dev,"XMIT",T_BUF_SIZE,0);
-    if(!p->tmdbounce[i]) {
-      ni65_free_buffer(p);
-      return -ENOMEM;
-    }
-  }
-
-  for(i=0;i<RMDNUM;i++)
-  {
+	for(i=0;i<RMDNUM;i++)
+	{
 #ifdef RCV_VIA_SKB
-    p->recv_skb[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,1);
-    if(!p->recv_skb[i]) {
-      ni65_free_buffer(p);
-      return -ENOMEM;
-    }
+		p->recv_skb[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,1);
+		if(!p->recv_skb[i]) {
+			ni65_free_buffer(p);
+			return -ENOMEM;
+		}
 #else
-    p->recvbounce[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,0);
-    if(!p->recvbounce[i]) {
-      ni65_free_buffer(p);
-      return -ENOMEM;
-    }
+		p->recvbounce[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,0);
+		if(!p->recvbounce[i]) {
+			ni65_free_buffer(p);
+			return -ENOMEM;
+		}
 #endif
-  }
+	}
 
-  return 0; /* everything is OK */
+	return 0; /* everything is OK */
 }
 
 /*
@@ -615,32 +615,32 @@
  */
 static void ni65_free_buffer(struct priv *p)
 {
-  int i;
+	int i;
 
-  if(!p)
-    return;
+	if(!p)
+		return;
 
-  for(i=0;i<TMDNUM;i++) {
-    if(p->tmdbounce[i])
-      kfree(p->tmdbounce[i]);
+	for(i=0;i<TMDNUM;i++) {
+		if(p->tmdbounce[i])
+			kfree(p->tmdbounce[i]);
 #ifdef XMT_VIA_SKB
-    if(p->tmd_skb[i])
-      dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
+		if(p->tmd_skb[i])
+			dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
 #endif
-  }
+	}
 
-  for(i=0;i<RMDNUM;i++)
-  {
+	for(i=0;i<RMDNUM;i++)
+	{
 #ifdef RCV_VIA_SKB
-    if(p->recv_skb[i])
-      dev_kfree_skb(p->recv_skb[i],FREE_WRITE);
+		if(p->recv_skb[i])
+			dev_kfree_skb(p->recv_skb[i],FREE_WRITE);
 #else
-    if(p->recvbounce[i])
-      kfree(p->recvbounce[i]);
+		if(p->recvbounce[i])
+			kfree(p->recvbounce[i]);
 #endif
-  }
-  if(p->self)
-    kfree(p->self);
+	}
+	if(p->self)
+		kfree(p->self);
 }
 
 
@@ -649,68 +649,68 @@
  */
 static void ni65_stop_start(struct device *dev,struct priv *p)
 {
-  int csr0 = CSR0_INEA;
+	int csr0 = CSR0_INEA;
 
-  writedatareg(CSR0_STOP);
+	writedatareg(CSR0_STOP);
 
-  if(debuglevel > 1)
-    printk("ni65_stop_start\n");
-
-  if(p->features & INIT_RING_BEFORE_START) {
-    int i;
-#ifdef XMT_VIA_SKB
-    struct sk_buff *skb_save[TMDNUM];
-#endif
-    unsigned long buffer[TMDNUM];
-    short blen[TMDNUM];
+	if(debuglevel > 1)
+		printk("ni65_stop_start\n");
 
-    if(p->xmit_queued) {
-      while(1) {
-        if((p->tmdhead[p->tmdlast].u.s.status & XMIT_OWN))
-          break;
-        p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);
-        if(p->tmdlast == p->tmdnum)
-          break;
-      }
-    }
-
-    for(i=0;i<TMDNUM;i++) {
-      struct tmd *tmdp = p->tmdhead + i;
-#ifdef XMT_VIA_SKB
-      skb_save[i] = p->tmd_skb[i];
-#endif
-      buffer[i] = (u32) bus_to_virt(tmdp->u.buffer);
-      blen[i] = tmdp->blen;
-      tmdp->u.s.status = 0x0;
-    }
-
-    for(i=0;i<RMDNUM;i++) {
-      struct rmd *rmdp = p->rmdhead + i;
-      rmdp->u.s.status = RCV_OWN;
-    }
-    p->tmdnum = p->xmit_queued = 0;
-    writedatareg(CSR0_STRT | csr0);
-
-    for(i=0;i<TMDNUM;i++) {
-      int num = (i + p->tmdlast) & (TMDNUM-1);
-      p->tmdhead[i].u.buffer = (u32) virt_to_bus((char *)buffer[num]); /* status is part of buffer field */
-      p->tmdhead[i].blen = blen[num];
-      if(p->tmdhead[i].u.s.status & XMIT_OWN) {
-         p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
-         p->xmit_queued = 1;
+	if(p->features & INIT_RING_BEFORE_START) {
+		int i;
+#ifdef XMT_VIA_SKB
+		struct sk_buff *skb_save[TMDNUM];
+#endif
+		unsigned long buffer[TMDNUM];
+		short blen[TMDNUM];
+
+		if(p->xmit_queued) {
+			while(1) {
+				if((p->tmdhead[p->tmdlast].u.s.status & XMIT_OWN))
+					break;
+				p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);
+				if(p->tmdlast == p->tmdnum)
+					break;
+			}
+		}
+
+		for(i=0;i<TMDNUM;i++) {
+			struct tmd *tmdp = p->tmdhead + i;
+#ifdef XMT_VIA_SKB
+			skb_save[i] = p->tmd_skb[i];
+#endif
+			buffer[i] = (u32) bus_to_virt(tmdp->u.buffer);
+			blen[i] = tmdp->blen;
+			tmdp->u.s.status = 0x0;
+		}
+
+		for(i=0;i<RMDNUM;i++) {
+			struct rmd *rmdp = p->rmdhead + i;
+			rmdp->u.s.status = RCV_OWN;
+		}
+		p->tmdnum = p->xmit_queued = 0;
+		writedatareg(CSR0_STRT | csr0);
+
+		for(i=0;i<TMDNUM;i++) {
+			int num = (i + p->tmdlast) & (TMDNUM-1);
+			p->tmdhead[i].u.buffer = (u32) virt_to_bus((char *)buffer[num]); /* status is part of buffer field */
+			p->tmdhead[i].blen = blen[num];
+			if(p->tmdhead[i].u.s.status & XMIT_OWN) {
+				 p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
+				 p->xmit_queued = 1;
 	 writedatareg(CSR0_TDMD | CSR0_INEA | csr0);
-      }
+			}
 #ifdef XMT_VIA_SKB
-      p->tmd_skb[i] = skb_save[num];
+			p->tmd_skb[i] = skb_save[num];
 #endif
-    }
-    p->rmdnum = p->tmdlast = 0;
-    if(!p->lock)
-      dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1;
-    dev->trans_start = jiffies;
-  }
-  else
-    writedatareg(CSR0_STRT | csr0);
+		}
+		p->rmdnum = p->tmdlast = 0;
+		if(!p->lock)
+			dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1;
+		dev->trans_start = jiffies;
+	}
+	else
+		writedatareg(CSR0_STRT | csr0);
 }
 
 /*
@@ -718,74 +718,74 @@
  */
 static int ni65_lance_reinit(struct device *dev)
 {
-   int i;
-   struct priv *p = (struct priv *) dev->priv;
+	 int i;
+	 struct priv *p = (struct priv *) dev->priv;
 
-   p->lock = 0;
-   p->xmit_queued = 0;
+	 p->lock = 0;
+	 p->xmit_queued = 0;
 
-   disable_dma(dev->dma); /* I've never worked with dma, but we do it like the packetdriver */
-   set_dma_mode(dev->dma,DMA_MODE_CASCADE);
-   enable_dma(dev->dma);
-
-   outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
-   if( (i=readreg(CSR0) ) != 0x4)
-   {
-     printk(KERN_ERR "%s: can't RESET %s card: %04x\n",dev->name,
-              cards[p->cardno].cardname,(int) i);
-     disable_dma(dev->dma);
-     return 0;
-   }
-
-   p->rmdnum = p->tmdnum = p->tmdlast = p->tmdbouncenum = 0;
-   for(i=0;i<TMDNUM;i++)
-   {
-     struct tmd *tmdp = p->tmdhead + i;
-#ifdef XMT_VIA_SKB
-     if(p->tmd_skb[i]) {
-       dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
-       p->tmd_skb[i] = NULL;
-     }
-#endif
-     tmdp->u.buffer = 0x0;
-     tmdp->u.s.status = XMIT_START | XMIT_END;
-     tmdp->blen = tmdp->status2 = 0;
-   }
-
-   for(i=0;i<RMDNUM;i++)
-   {
-     struct rmd *rmdp = p->rmdhead + i;
+	 disable_dma(dev->dma); /* I've never worked with dma, but we do it like the packetdriver */
+	 set_dma_mode(dev->dma,DMA_MODE_CASCADE);
+	 enable_dma(dev->dma);
+
+	 outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
+	 if( (i=readreg(CSR0) ) != 0x4)
+	 {
+		 printk(KERN_ERR "%s: can't RESET %s card: %04x\n",dev->name,
+							cards[p->cardno].cardname,(int) i);
+		 disable_dma(dev->dma);
+		 return 0;
+	 }
+
+	 p->rmdnum = p->tmdnum = p->tmdlast = p->tmdbouncenum = 0;
+	 for(i=0;i<TMDNUM;i++)
+	 {
+		 struct tmd *tmdp = p->tmdhead + i;
+#ifdef XMT_VIA_SKB
+		 if(p->tmd_skb[i]) {
+			 dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
+			 p->tmd_skb[i] = NULL;
+		 }
+#endif
+		 tmdp->u.buffer = 0x0;
+		 tmdp->u.s.status = XMIT_START | XMIT_END;
+		 tmdp->blen = tmdp->status2 = 0;
+	 }
+
+	 for(i=0;i<RMDNUM;i++)
+	 {
+		 struct rmd *rmdp = p->rmdhead + i;
 #ifdef RCV_VIA_SKB
-     rmdp->u.buffer = (u32) virt_to_bus(p->recv_skb[i]->data);
+		 rmdp->u.buffer = (u32) virt_to_bus(p->recv_skb[i]->data);
 #else
-     rmdp->u.buffer = (u32) virt_to_bus(p->recvbounce[i]);
+		 rmdp->u.buffer = (u32) virt_to_bus(p->recvbounce[i]);
 #endif
-     rmdp->blen = -(R_BUF_SIZE-8);
-     rmdp->mlen = 0;
-     rmdp->u.s.status = RCV_OWN;
-   }
-
-   if(dev->flags & IFF_PROMISC)
-     ni65_init_lance(p,dev->dev_addr,0x00,M_PROM);
-   else if(dev->mc_count || dev->flags & IFF_ALLMULTI)
-     ni65_init_lance(p,dev->dev_addr,0xff,0x0);
-   else
-     ni65_init_lance(p,dev->dev_addr,0x00,0x00);
-
-  /*
-   * ni65_set_lance_mem() sets L_ADDRREG to CSR0
-   * NOW, WE WILL NEVER CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED
-   */
-
-   if(inw(PORT+L_DATAREG) & CSR0_IDON)  {
-     ni65_set_performance(p);
-           /* init OK: start lance , enable interrupts */
-     writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT);
-     return 1; /* ->OK */
-   }
-   printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));
-   disable_dma(dev->dma);
-   return 0; /* ->Error */
+		 rmdp->blen = -(R_BUF_SIZE-8);
+		 rmdp->mlen = 0;
+		 rmdp->u.s.status = RCV_OWN;
+	 }
+
+	 if(dev->flags & IFF_PROMISC)
+		 ni65_init_lance(p,dev->dev_addr,0x00,M_PROM);
+	 else if(dev->mc_count || dev->flags & IFF_ALLMULTI)
+		 ni65_init_lance(p,dev->dev_addr,0xff,0x0);
+	 else
+		 ni65_init_lance(p,dev->dev_addr,0x00,0x00);
+
+	/*
+	 * ni65_set_lance_mem() sets L_ADDRREG to CSR0
+	 * NOW, WE WILL NEVER CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED
+	 */
+
+	 if(inw(PORT+L_DATAREG) & CSR0_IDON)	{
+		 ni65_set_performance(p);
+					 /* init OK: start lance , enable interrupts */
+		 writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT);
+		 return 1; /* ->OK */
+	 }
+	 printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));
+	 disable_dma(dev->dma);
+	 return 0; /* ->Error */
 }
 
 /*
@@ -793,117 +793,117 @@
  */
 static void ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
 {
-  int csr0;
-  struct device *dev = (struct device *) irq2dev_map[irq];
-  struct priv *p;
-  int bcnt = 32;
-
-  if (dev == NULL) {
-    printk (KERN_ERR "ni65_interrupt(): irq %d for unknown device.\n", irq);
-    return;
-  }
-
-  if(set_bit(0,(int *) &dev->interrupt)) {
-    printk("ni65: oops .. interrupt while proceeding interrupt\n");
-    return;
-  }
-  p = (struct priv *) dev->priv;
+	int csr0;
+	struct device *dev = (struct device *) irq2dev_map[irq];
+	struct priv *p;
+	int bcnt = 32;
+
+	if (dev == NULL) {
+		printk (KERN_ERR "ni65_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	if(set_bit(0,(int *) &dev->interrupt)) {
+		printk("ni65: oops .. interrupt while proceeding interrupt\n");
+		return;
+	}
+	p = (struct priv *) dev->priv;
 
-  while(--bcnt) {
-    csr0 = inw(PORT+L_DATAREG);
+	while(--bcnt) {
+		csr0 = inw(PORT+L_DATAREG);
 
 #if 0
-    writedatareg( (csr0 & CSR0_CLRALL) ); /* ack interrupts, disable int. */
+		writedatareg( (csr0 & CSR0_CLRALL) ); /* ack interrupts, disable int. */
 #else
-    writedatareg( (csr0 & CSR0_CLRALL) | CSR0_INEA ); /* ack interrupts, interrupts enabled */
+		writedatareg( (csr0 & CSR0_CLRALL) | CSR0_INEA ); /* ack interrupts, interrupts enabled */
 #endif
 
-    if(!(csr0 & (CSR0_ERR | CSR0_RINT | CSR0_TINT)))
-      break;
+		if(!(csr0 & (CSR0_ERR | CSR0_RINT | CSR0_TINT)))
+			break;
 
-    if(csr0 & CSR0_RINT) /* RECV-int? */
-      ni65_recv_intr(dev,csr0);
-    if(csr0 & CSR0_TINT) /* XMIT-int? */
-      ni65_xmit_intr(dev,csr0);
-
-    if(csr0 & CSR0_ERR)
-    {
-      struct priv *p = (struct priv *) dev->priv;
-      if(debuglevel > 1)
-        printk("%s: general error: %04x.\n",dev->name,csr0);
-      if(csr0 & CSR0_BABL)
-        p->stats.tx_errors++;
-      if(csr0 & CSR0_MISS) {
-        int i;
-        for(i=0;i<RMDNUM;i++)
-          printk("%02x ",p->rmdhead[i].u.s.status);
-        printk("\n");
-        p->stats.rx_errors++;
-      }
-      if(csr0 & CSR0_MERR) {
-        if(debuglevel > 1)
-          printk("%s: Ooops .. memory error: %04x.\n",dev->name,csr0);
-        ni65_stop_start(dev,p);
-      }
-    }
-  }
+		if(csr0 & CSR0_RINT) /* RECV-int? */
+			ni65_recv_intr(dev,csr0);
+		if(csr0 & CSR0_TINT) /* XMIT-int? */
+			ni65_xmit_intr(dev,csr0);
+
+		if(csr0 & CSR0_ERR)
+		{
+			struct priv *p = (struct priv *) dev->priv;
+			if(debuglevel > 1)
+				printk("%s: general error: %04x.\n",dev->name,csr0);
+			if(csr0 & CSR0_BABL)
+				p->stats.tx_errors++;
+			if(csr0 & CSR0_MISS) {
+				int i;
+				for(i=0;i<RMDNUM;i++)
+					printk("%02x ",p->rmdhead[i].u.s.status);
+				printk("\n");
+				p->stats.rx_errors++;
+			}
+			if(csr0 & CSR0_MERR) {
+				if(debuglevel > 1)
+					printk("%s: Ooops .. memory error: %04x.\n",dev->name,csr0);
+				ni65_stop_start(dev,p);
+			}
+		}
+	}
 
 #ifdef RCV_PARANOIA_CHECK
 {
  int j;
  for(j=0;j<RMDNUM;j++)
  {
-  struct priv *p = (struct priv *) dev->priv;
-  int i,k,num1,num2;
-  for(i=RMDNUM-1;i>0;i--) {
-     num2 = (p->rmdnum + i) & (RMDNUM-1);
-     if(!(p->rmdhead[num2].u.s.status & RCV_OWN))
-        break;
-  }
-
-  if(i) {
-    for(k=0;k<RMDNUM;k++) {
-      num1 = (p->rmdnum + k) & (RMDNUM-1);
-      if(!(p->rmdhead[num1].u.s.status & RCV_OWN))
-        break;
-    }
-    if(!k)
-      break;
-
-    if(debuglevel > 0)
-    {
-      char buf[256],*buf1;
-      int k;
-      buf1 = buf;
-      for(k=0;k<RMDNUM;k++) {
-        sprintf(buf1,"%02x ",(p->rmdhead[k].u.s.status)); /* & RCV_OWN) ); */
-        buf1 += 3;
-      }
-      *buf1 = 0;
-      printk(KERN_ERR "%s: Ooops, receive ring corrupted %2d %2d | %s\n",dev->name,p->rmdnum,i,buf);
-    }
-
-    p->rmdnum = num1;
-    ni65_recv_intr(dev,csr0);
-    if((p->rmdhead[num2].u.s.status & RCV_OWN))
-      break;	/* ok, we are 'in sync' again */
-  }
-  else
-    break;
+	struct priv *p = (struct priv *) dev->priv;
+	int i,k,num1,num2;
+	for(i=RMDNUM-1;i>0;i--) {
+		 num2 = (p->rmdnum + i) & (RMDNUM-1);
+		 if(!(p->rmdhead[num2].u.s.status & RCV_OWN))
+				break;
+	}
+
+	if(i) {
+		for(k=0;k<RMDNUM;k++) {
+			num1 = (p->rmdnum + k) & (RMDNUM-1);
+			if(!(p->rmdhead[num1].u.s.status & RCV_OWN))
+				break;
+		}
+		if(!k)
+			break;
+
+		if(debuglevel > 0)
+		{
+			char buf[256],*buf1;
+			int k;
+			buf1 = buf;
+			for(k=0;k<RMDNUM;k++) {
+				sprintf(buf1,"%02x ",(p->rmdhead[k].u.s.status)); /* & RCV_OWN) ); */
+				buf1 += 3;
+			}
+			*buf1 = 0;
+			printk(KERN_ERR "%s: Ooops, receive ring corrupted %2d %2d | %s\n",dev->name,p->rmdnum,i,buf);
+		}
+
+		p->rmdnum = num1;
+		ni65_recv_intr(dev,csr0);
+		if((p->rmdhead[num2].u.s.status & RCV_OWN))
+			break;	/* ok, we are 'in sync' again */
+	}
+	else
+		break;
  }
 }
 #endif
 
-  if( (csr0 & (CSR0_RXON | CSR0_TXON)) != (CSR0_RXON | CSR0_TXON) ) {
-    printk("%s: RX or TX was offline -> restart\n",dev->name);
-    ni65_stop_start(dev,p);
-  }
-  else
-    writedatareg(CSR0_INEA);
+	if( (csr0 & (CSR0_RXON | CSR0_TXON)) != (CSR0_RXON | CSR0_TXON) ) {
+		printk("%s: RX or TX was offline -> restart\n",dev->name);
+		ni65_stop_start(dev,p);
+	}
+	else
+		writedatareg(CSR0_INEA);
 
-  dev->interrupt = 0;
+	dev->interrupt = 0;
 
-  return;
+	return;
 }
 
 /*
@@ -912,62 +912,62 @@
  */
 static void ni65_xmit_intr(struct device *dev,int csr0)
 {
-  struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = (struct priv *) dev->priv;
 
-  while(p->xmit_queued)
-  {
-    struct tmd *tmdp = p->tmdhead + p->tmdlast;
-    int tmdstat = tmdp->u.s.status;
+	while(p->xmit_queued)
+	{
+		struct tmd *tmdp = p->tmdhead + p->tmdlast;
+		int tmdstat = tmdp->u.s.status;
 
-    if(tmdstat & XMIT_OWN)
-      break;
+		if(tmdstat & XMIT_OWN)
+			break;
 
-    if(tmdstat & XMIT_ERR)
-    {
+		if(tmdstat & XMIT_ERR)
+		{
 #if 0
-      if(tmdp->status2 & XMIT_TDRMASK && debuglevel > 3)
-        printk(KERN_ERR "%s: tdr-problems (e.g. no resistor)\n",dev->name);
+			if(tmdp->status2 & XMIT_TDRMASK && debuglevel > 3)
+				printk(KERN_ERR "%s: tdr-problems (e.g. no resistor)\n",dev->name);
 #endif
-     /* checking some errors */
-      if(tmdp->status2 & XMIT_RTRY)
-        p->stats.tx_aborted_errors++;
-      if(tmdp->status2 & XMIT_LCAR)
-        p->stats.tx_carrier_errors++;
-      if(tmdp->status2 & (XMIT_BUFF | XMIT_UFLO )) {
+		 /* checking some errors */
+			if(tmdp->status2 & XMIT_RTRY)
+				p->stats.tx_aborted_errors++;
+			if(tmdp->status2 & XMIT_LCAR)
+				p->stats.tx_carrier_errors++;
+			if(tmdp->status2 & (XMIT_BUFF | XMIT_UFLO )) {
 		/* this stops the xmitter */
-        p->stats.tx_fifo_errors++;
-        if(debuglevel > 0)
-          printk(KERN_ERR "%s: Xmit FIFO/BUFF error\n",dev->name);
-        if(p->features & INIT_RING_BEFORE_START) {
-          tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END;	/* test: resend this frame */
-          ni65_stop_start(dev,p);
-          break;	/* no more Xmit processing .. */
-        }
-        else
-         ni65_stop_start(dev,p);
-      }
-      if(debuglevel > 2)
-        printk(KERN_ERR "%s: xmit-error: %04x %02x-%04x\n",dev->name,csr0,(int) tmdstat,(int) tmdp->status2);
-      if(!(csr0 & CSR0_BABL)) /* don't count errors twice */
-        p->stats.tx_errors++;
-      tmdp->status2 = 0;
-    }
-    else
-      p->stats.tx_packets++;
-
-#ifdef XMT_VIA_SKB
-    if(p->tmd_skb[p->tmdlast]) {
-       dev_kfree_skb(p->tmd_skb[p->tmdlast],FREE_WRITE);
-       p->tmd_skb[p->tmdlast] = NULL;
-    }
-#endif
-
-    p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);
-    if(p->tmdlast == p->tmdnum)
-      p->xmit_queued = 0;
-  }
-  dev->tbusy = 0;
-  mark_bh(NET_BH);
+				p->stats.tx_fifo_errors++;
+				if(debuglevel > 0)
+					printk(KERN_ERR "%s: Xmit FIFO/BUFF error\n",dev->name);
+				if(p->features & INIT_RING_BEFORE_START) {
+					tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END;	/* test: resend this frame */
+					ni65_stop_start(dev,p);
+					break;	/* no more Xmit processing .. */
+				}
+				else
+				 ni65_stop_start(dev,p);
+			}
+			if(debuglevel > 2)
+				printk(KERN_ERR "%s: xmit-error: %04x %02x-%04x\n",dev->name,csr0,(int) tmdstat,(int) tmdp->status2);
+			if(!(csr0 & CSR0_BABL)) /* don't count errors twice */
+				p->stats.tx_errors++;
+			tmdp->status2 = 0;
+		}
+		else
+			p->stats.tx_packets++;
+
+#ifdef XMT_VIA_SKB
+		if(p->tmd_skb[p->tmdlast]) {
+			 dev_kfree_skb(p->tmd_skb[p->tmdlast],FREE_WRITE);
+			 p->tmd_skb[p->tmdlast] = NULL;
+		}
+#endif
+
+		p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);
+		if(p->tmdlast == p->tmdnum)
+			p->xmit_queued = 0;
+	}
+	dev->tbusy = 0;
+	mark_bh(NET_BH);
 }
 
 /*
@@ -975,90 +975,90 @@
  */
 static void ni65_recv_intr(struct device *dev,int csr0)
 {
-  struct rmd *rmdp;
-  int rmdstat,len;
-  int cnt=0;
-  struct priv *p = (struct priv *) dev->priv;
-
-  rmdp = p->rmdhead + p->rmdnum;
-  while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN))
-  {
-    cnt++;
-    if( (rmdstat & (RCV_START | RCV_END | RCV_ERR)) != (RCV_START | RCV_END) ) /* error or oversized? */
-    {
-      if(!(rmdstat & RCV_ERR)) {
-        if(rmdstat & RCV_START)
-        {
-          p->stats.rx_length_errors++;
-          printk(KERN_ERR "%s: recv, packet too long: %d\n",dev->name,rmdp->mlen & 0x0fff);
-        }
-      }
-      else {
-        if(debuglevel > 2)
-          printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n",
-                  dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) );
-        if(rmdstat & RCV_FRAM)
-          p->stats.rx_frame_errors++;
-        if(rmdstat & RCV_OFLO)
-          p->stats.rx_over_errors++;
-        if(rmdstat & RCV_CRC)
-          p->stats.rx_crc_errors++;
-        if(rmdstat & RCV_BUF_ERR)
-          p->stats.rx_fifo_errors++;
-      }
-      if(!(csr0 & CSR0_MISS)) /* don't count errors twice */
-        p->stats.rx_errors++;
-    }
-    else if( (len = (rmdp->mlen & 0x0fff) - 4) >= 60)
-    {
+	struct rmd *rmdp;
+	int rmdstat,len;
+	int cnt=0;
+	struct priv *p = (struct priv *) dev->priv;
+
+	rmdp = p->rmdhead + p->rmdnum;
+	while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN))
+	{
+		cnt++;
+		if( (rmdstat & (RCV_START | RCV_END | RCV_ERR)) != (RCV_START | RCV_END) ) /* error or oversized? */
+		{
+			if(!(rmdstat & RCV_ERR)) {
+				if(rmdstat & RCV_START)
+				{
+					p->stats.rx_length_errors++;
+					printk(KERN_ERR "%s: recv, packet too long: %d\n",dev->name,rmdp->mlen & 0x0fff);
+				}
+			}
+			else {
+				if(debuglevel > 2)
+					printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n",
+									dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) );
+				if(rmdstat & RCV_FRAM)
+					p->stats.rx_frame_errors++;
+				if(rmdstat & RCV_OFLO)
+					p->stats.rx_over_errors++;
+				if(rmdstat & RCV_CRC)
+					p->stats.rx_crc_errors++;
+				if(rmdstat & RCV_BUF_ERR)
+					p->stats.rx_fifo_errors++;
+			}
+			if(!(csr0 & CSR0_MISS)) /* don't count errors twice */
+				p->stats.rx_errors++;
+		}
+		else if( (len = (rmdp->mlen & 0x0fff) - 4) >= 60)
+		{
 #ifdef RCV_VIA_SKB
-      struct sk_buff *skb = alloc_skb(R_BUF_SIZE+2+16,GFP_ATOMIC);
-      if (skb)
-        skb_reserve(skb,16);
+			struct sk_buff *skb = alloc_skb(R_BUF_SIZE+2+16,GFP_ATOMIC);
+			if (skb)
+				skb_reserve(skb,16);
 #else
-      struct sk_buff *skb = dev_alloc_skb(len+2);
+			struct sk_buff *skb = dev_alloc_skb(len+2);
 #endif
-      if(skb)
-      {
-        skb_reserve(skb,2);
+			if(skb)
+			{
+				skb_reserve(skb,2);
 	skb->dev = dev;
 #ifdef RCV_VIA_SKB
-        if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000) {
-          skb_put(skb,len);
-          eth_copy_and_sum(skb, (unsigned char *)(p->recv_skb[p->rmdnum]->data),len,0);
-        }
-        else {
-          struct sk_buff *skb1 = p->recv_skb[p->rmdnum];
-          skb_put(skb,R_BUF_SIZE);
-          p->recv_skb[p->rmdnum] = skb;
-          rmdp->u.buffer = (u32) virt_to_bus(skb->data);
-          skb = skb1;
-          skb_trim(skb,len);
-        }
+				if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000) {
+					skb_put(skb,len);
+					eth_copy_and_sum(skb, (unsigned char *)(p->recv_skb[p->rmdnum]->data),len,0);
+				}
+				else {
+					struct sk_buff *skb1 = p->recv_skb[p->rmdnum];
+					skb_put(skb,R_BUF_SIZE);
+					p->recv_skb[p->rmdnum] = skb;
+					rmdp->u.buffer = (u32) virt_to_bus(skb->data);
+					skb = skb1;
+					skb_trim(skb,len);
+				}
 #else
-        skb_put(skb,len);
-        eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0);
+				skb_put(skb,len);
+				eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0);
 #endif
-        p->stats.rx_packets++;
-        skb->protocol=eth_type_trans(skb,dev);
-        netif_rx(skb);
-      }
-      else
-      {
-        printk(KERN_ERR "%s: can't alloc new sk_buff\n",dev->name);
-        p->stats.rx_dropped++;
-      }
-    }
-    else {
-      printk(KERN_INFO "%s: received runt packet\n",dev->name);
-      p->stats.rx_errors++;
-    }
-    rmdp->blen = -(R_BUF_SIZE-8);
-    rmdp->mlen = 0;
-    rmdp->u.s.status = RCV_OWN; /* change owner */
-    p->rmdnum = (p->rmdnum + 1) & (RMDNUM-1);
-    rmdp = p->rmdhead + p->rmdnum;
-  }
+				p->stats.rx_packets++;
+				skb->protocol=eth_type_trans(skb,dev);
+				netif_rx(skb);
+			}
+			else
+			{
+				printk(KERN_ERR "%s: can't alloc new sk_buff\n",dev->name);
+				p->stats.rx_dropped++;
+			}
+		}
+		else {
+			printk(KERN_INFO "%s: received runt packet\n",dev->name);
+			p->stats.rx_errors++;
+		}
+		rmdp->blen = -(R_BUF_SIZE-8);
+		rmdp->mlen = 0;
+		rmdp->u.s.status = RCV_OWN; /* change owner */
+		p->rmdnum = (p->rmdnum + 1) & (RMDNUM-1);
+		rmdp = p->rmdhead + p->rmdnum;
+	}
 }
 
 /*
@@ -1066,106 +1066,99 @@
  */
 static int ni65_send_packet(struct sk_buff *skb, struct device *dev)
 {
-  struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = (struct priv *) dev->priv;
 
-  if(dev->tbusy)
-  {
-    int tickssofar = jiffies - dev->trans_start;
-    if (tickssofar < 50)
-      return 1;
+	if(dev->tbusy)
+	{
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 50)
+			return 1;
 
-    printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
-{
-  int i;
-  for(i=0;i<TMDNUM;i++)
-    printk("%02x ",p->tmdhead[i].u.s.status);
-  printk("\n");
-}
-    ni65_lance_reinit(dev);
-    dev->tbusy=0;
-    dev->trans_start = jiffies;
-  }
-
-  if(skb == NULL) {
-    dev_tint(dev);
-    return 0;
-  }
-
-  if (skb->len <= 0)
-    return 0;
-
-  if (set_bit(0, (void*)&dev->tbusy) != 0) {
-     printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
-     return 1;
-  }
-  if (set_bit(0, (void*)&p->lock)) {
-	printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
-	return 1;
-  }
-
-  {
-    short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-    struct tmd *tmdp;
-    long flags;
+		printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
+		{
+			int i;
+			for(i=0;i<TMDNUM;i++)
+				printk("%02x ",p->tmdhead[i].u.s.status);
+			printk("\n");
+		}
+		ni65_lance_reinit(dev);
+		dev->tbusy=0;
+		dev->trans_start = jiffies;
+	}
+
+	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+		 printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
+		 return 1;
+	}
+	if (set_bit(0, (void*)&p->lock)) {
+		printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
+		return 1;
+	}
+
+	{
+		short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		struct tmd *tmdp;
+		long flags;
 
 #ifdef XMT_VIA_SKB
-    if( (unsigned long) (skb->data + skb->len) > 0x1000000) {
+		if( (unsigned long) (skb->data + skb->len) > 0x1000000) {
 #endif
 
-      memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data,
-               (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len);
-      dev_kfree_skb (skb, FREE_WRITE);
+			memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data,
+							 (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len);
+			dev_kfree_skb (skb, FREE_WRITE);
 
-      save_flags(flags);
-      cli();
+			save_flags(flags);
+			cli();
 
-      tmdp = p->tmdhead + p->tmdnum;
-      tmdp->u.buffer = (u32) virt_to_bus(p->tmdbounce[p->tmdbouncenum]);
-      p->tmdbouncenum = (p->tmdbouncenum + 1) & (TMDNUM - 1);
+			tmdp = p->tmdhead + p->tmdnum;
+			tmdp->u.buffer = (u32) virt_to_bus(p->tmdbounce[p->tmdbouncenum]);
+			p->tmdbouncenum = (p->tmdbouncenum + 1) & (TMDNUM - 1);
 
 #ifdef XMT_VIA_SKB
-    }
-    else {
-      save_flags(flags);
-      cli();
+		}
+		else {
+			save_flags(flags);
+			cli();
 
-      tmdp = p->tmdhead + p->tmdnum;
-      tmdp->u.buffer = (u32) virt_to_bus(skb->data);
-      p->tmd_skb[p->tmdnum] = skb;
-    }
+			tmdp = p->tmdhead + p->tmdnum;
+			tmdp->u.buffer = (u32) virt_to_bus(skb->data);
+			p->tmd_skb[p->tmdnum] = skb;
+		}
 #endif
-    tmdp->blen = -len;
+		tmdp->blen = -len;
 
-    tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END;
-    writedatareg(CSR0_TDMD | CSR0_INEA); /* enable xmit & interrupt */
+		tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END;
+		writedatareg(CSR0_TDMD | CSR0_INEA); /* enable xmit & interrupt */
 
-    p->xmit_queued = 1;
-    p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
+		p->xmit_queued = 1;
+		p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
 
-    dev->tbusy = (p->tmdnum == p->tmdlast) ? 1 : 0;
-    p->lock = 0;
-    dev->trans_start = jiffies;
+		dev->tbusy = (p->tmdnum == p->tmdlast) ? 1 : 0;
+		p->lock = 0;
+		dev->trans_start = jiffies;
 
-    restore_flags(flags);
-  }
+		restore_flags(flags);
+	}
 
-  return 0;
+	return 0;
 }
 
-static struct enet_statistics *ni65_get_stats(struct device *dev)
+static struct net_device_stats *ni65_get_stats(struct device *dev)
 {
 
 #if 0
- int i;
- struct priv *p = (struct priv *) dev->priv;
- for(i=0;i<RMDNUM;i++) {
-   struct rmd *rmdp = p->rmdhead + ((p->rmdnum + i) & (RMDNUM-1));
-   printk("%02x ",rmdp->u.s.status);
- }
- printk("\n");
+	int i;
+	struct priv *p = (struct priv *) dev->priv;
+	for(i=0;i<RMDNUM;i++)
+	{
+		struct rmd *rmdp = p->rmdhead + ((p->rmdnum + i) & (RMDNUM-1));
+		printk("%02x ",rmdp->u.s.status);
+	}
+	printk("\n");
 #endif
 
-  return &((struct priv *) dev->priv)->stats;
+	return &((struct priv *) dev->priv)->stats;
 }
 
 static void set_multicast_list(struct device *dev)
@@ -1177,10 +1170,10 @@
 
 #ifdef MODULE
 static struct device dev_ni65 = {
-  "        ",  /* "ni6510": device name inserted by net_init.c */
-  0, 0, 0, 0,
-  0x360, 9,   /* I/O address, IRQ */
-  0, 0, 0, NULL, ni65_probe };
+	"				",	/* "ni6510": device name inserted by net_init.c */
+	0, 0, 0, 0,
+	0x360, 9,	 /* I/O address, IRQ */
+	0, 0, 0, NULL, ni65_probe };
 
 /* set: io,irq,dma or set it when calling insmod */
 static int irq=0;
@@ -1193,35 +1186,28 @@
 
 int init_module(void)
 {
-#if 0
-  if(io <= 0x0 || irq < 2) {
-    printk("ni65: Autoprobing not allowed for modules.\n");
-    printk("ni65: Set symbols 'io' 'irq' and 'dma'\n");
-    return -ENODEV;
-  }
-#endif
-  dev_ni65.irq = irq;
-  dev_ni65.dma = dma;
-  dev_ni65.base_addr = io;
-  if (register_netdev(&dev_ni65) != 0)
-    return -EIO;
-  return 0;
+	dev_ni65.irq = irq;
+	dev_ni65.dma = dma;
+	dev_ni65.base_addr = io;
+	if (register_netdev(&dev_ni65) != 0)
+		return -EIO;
+	return 0;
 }
 
 void cleanup_module(void)
 {
-  struct priv *p;
-  p = (struct priv *) dev_ni65.priv;
-  if(!p) {
-    printk("Ooops .. no privat struct\n");
-    return;
-  }
-  disable_dma(dev_ni65.dma);
-  free_dma(dev_ni65.dma);
-  release_region(dev_ni65.base_addr,cards[p->cardno].total_size);
-  ni65_free_buffer(p);
-  dev_ni65.priv = NULL;
-  unregister_netdev(&dev_ni65);
+	struct priv *p;
+	p = (struct priv *) dev_ni65.priv;
+	if(!p) {
+		printk("Ooops .. no private struct\n");
+		return;
+	}
+	disable_dma(dev_ni65.dma);
+	free_dma(dev_ni65.dma);
+	release_region(dev_ni65.base_addr,cards[p->cardno].total_size);
+	ni65_free_buffer(p);
+	dev_ni65.priv = NULL;
+	unregister_netdev(&dev_ni65);
 }
 #endif /* MODULE */
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/pi2.c linux/drivers/net/pi2.c
--- v2.1.24/linux/drivers/net/pi2.c	Thu Jan 23 21:06:47 1997
+++ linux/drivers/net/pi2.c	Sun Feb  2 15:18:40 1997
@@ -146,7 +146,7 @@
 static void pi_interrupt(int reg_ptr, void *dev_id, struct pt_regs *regs);
 static int pi_close(struct device *dev);
 static int pi_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static struct enet_statistics *pi_get_stats(struct device *dev);
+static struct net_device_stats *pi_get_stats(struct device *dev);
 static void rts(struct pi_local *lp, int x);
 static void b_rxint(struct device *dev, struct pi_local *lp);
 static void b_txint(struct pi_local *lp);
@@ -164,69 +164,71 @@
 
 static int ext2_secrm_seed = 152;	/* Random generator base */
 
-static inline unsigned char random(void)
+extern inline unsigned char random(void)
 {
-    return (unsigned char) (ext2_secrm_seed = ext2_secrm_seed
+	return (unsigned char) (ext2_secrm_seed = ext2_secrm_seed
 			    * 69069l + 1);
 }
 
-static inline void wrtscc(int cbase, int ctl, int sccreg, int val)
+extern inline void wrtscc(int cbase, int ctl, int sccreg, int val)
 {
-    /* assume caller disables interrupts! */
-    outb_p(0, cbase + DMAEN);	/* Disable DMA while we touch the scc */
-    outb_p(sccreg, ctl);	/* Select register */
-    outb_p(val, ctl);		/* Output value */
-    outb_p(1, cbase + DMAEN);	/* Enable DMA */
+	/* assume caller disables interrupts! */
+	outb_p(0, cbase + DMAEN);	/* Disable DMA while we touch the scc */
+	outb_p(sccreg, ctl);		/* Select register */
+	outb_p(val, ctl);		/* Output value */
+	outb_p(1, cbase + DMAEN);	/* Enable DMA */
 }
 
-static inline int rdscc(int cbase, int ctl, int sccreg)
+extern inline int rdscc(int cbase, int ctl, int sccreg)
 {
-    int retval;
+	int retval;
 
-    /* assume caller disables interrupts! */
-    outb_p(0, cbase + DMAEN);	/* Disable DMA while we touch the scc */
-    outb_p(sccreg, ctl);	/* Select register */
-    retval = inb_p(ctl);
-    outb_p(1, cbase + DMAEN);	/* Enable DMA */
-    return retval;
+	/* assume caller disables interrupts! */
+	outb_p(0, cbase + DMAEN);	/* Disable DMA while we touch the scc */
+	outb_p(sccreg, ctl);	/* Select register */
+	retval = inb_p(ctl);
+	outb_p(1, cbase + DMAEN);	/* Enable DMA */
+	return retval;
 }
 
 static void switchbuffers(struct pi_local *lp)
 {
-    if (lp->rcvbuf == lp->rxdmabuf1)
-	lp->rcvbuf = lp->rxdmabuf2;
-    else
-	lp->rcvbuf = lp->rxdmabuf1;
+	if (lp->rcvbuf == lp->rxdmabuf1)
+		lp->rcvbuf = lp->rxdmabuf2;
+	else
+		lp->rcvbuf = lp->rxdmabuf1;
 }
 
 static void hardware_send_packet(struct pi_local *lp, struct sk_buff *skb)
 {
-    char kickflag;
-    unsigned long flags;
+	char kickflag;
+	unsigned long flags;
 
-    lp->stats.tx_packets++;
+	lp->stats.tx_packets++;
 
-    save_flags(flags);
-    cli();
-    kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL);
-    restore_flags(flags);
+	save_flags(flags);
+	cli();
+	kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL);
+	restore_flags(flags);
 
-    skb_queue_tail(&lp->sndq, skb);
-    if (kickflag) {
-	/* simulate interrupt to xmit */
-	switch (lp->base & 2) {
-	case 2:
-	    a_txint(lp);	/* process interrupt */
-	    break;
-	case 0:
-	    save_flags(flags);
-	    cli();
-	    if (lp->tstate == IDLE)
-		b_txint(lp);
-	    restore_flags(flags);
-	    break;
+	skb_queue_tail(&lp->sndq, skb);
+	if (kickflag) 
+	{
+		/* simulate interrupt to xmit */
+		switch (lp->base & 2) 
+		{
+			case 2:
+				a_txint(lp);	/* process interrupt */
+				break;
+			case 0:
+				save_flags(flags);
+				cli();
+				if (lp->tstate == IDLE)
+					b_txint(lp);
+				restore_flags(flags);
+				break;
+		}
 	}
-    }
 }
 
 static void setup_rx_dma(struct pi_local *lp)
@@ -1662,12 +1664,11 @@
 
 /* Get the current statistics.	This may be called with the card open or
    closed. */
-static struct netstats *
- pi_get_stats(struct device *dev)
+static struct net_device_stats *pi_get_stats(struct device *dev)
 {
-    struct pi_local *lp = (struct pi_local *) dev->priv;
+	struct pi_local *lp = (struct pi_local *) dev->priv;
 
-    return &lp->stats;
+	return &lp->stats;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.24/linux/drivers/net/pi2.h linux/drivers/net/pi2.h
--- v2.1.24/linux/drivers/net/pi2.h	Tue Jun  6 11:22:10 1995
+++ linux/drivers/net/pi2.h	Sun Feb  2 15:18:40 1997
@@ -1,9 +1,6 @@
 
 #define DMA_BUFF_SIZE 2200
 
-/* Network statistics, with the same names as 'struct enet_statistics'. */
-#define netstats enet_statistics
-
 #define ON 1
 #define OFF 0
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.1.24/linux/drivers/net/plip.c	Tue Dec 31 21:41:05 1996
+++ linux/drivers/net/plip.c	Sun Feb  2 15:18:41 1997
@@ -147,7 +147,7 @@
 static int plip_tx_packet(struct sk_buff *skb, struct device *dev);
 static int plip_open(struct device *dev);
 static int plip_close(struct device *dev);
-static struct enet_statistics *plip_get_stats(struct device *dev);
+static struct net_device_stats *plip_get_stats(struct device *dev);
 static int plip_config(struct device *dev, struct ifmap *map);
 static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
 
@@ -198,7 +198,7 @@
 };
 
 struct net_local {
-	struct enet_statistics enet_stats;
+	struct net_device_stats enet_stats;
 	struct tq_struct immediate;
 	struct tq_struct deferred;
 	struct plip_local snd_data;
@@ -213,8 +213,8 @@
 
 /* Entry point of PLIP driver.
    Probe the hardware, and register/initialize the driver. */
-int
-plip_init(struct device *dev)
+
+int plip_init(struct device *dev)
 {
 	struct net_local *nl;
 	int iosize = (PAR_DATA(dev) == 0x3bc) ? 3 : 8;
@@ -306,8 +306,8 @@
 /* Bottom half handler for the delayed request.
    This routine is kicked by do_timer().
    Request `plip_bh' to be invoked. */
-static void
-plip_kick_bh(struct device *dev)
+   
+static void plip_kick_bh(struct device *dev)
 {
 	struct net_local *nl = (struct net_local *)dev->priv;
 
@@ -350,8 +350,7 @@
 };
 
 /* Bottom half handler of PLIP. */
-static void
-plip_bh(struct device *dev)
+static void plip_bh(struct device *dev)
 {
 	struct net_local *nl = (struct net_local *)dev->priv;
 	struct plip_local *snd = &nl->snd_data;
@@ -368,8 +367,7 @@
 	}
 }
 
-static int
-plip_bh_timeout_error(struct device *dev, struct net_local *nl,
+static int plip_bh_timeout_error(struct device *dev, struct net_local *nl,
 		      struct plip_local *snd, struct plip_local *rcv,
 		      int error)
 {
@@ -431,8 +429,7 @@
 	return TIMEOUT;
 }
 
-static int
-plip_none(struct device *dev, struct net_local *nl,
+static int plip_none(struct device *dev, struct net_local *nl,
 	  struct plip_local *snd, struct plip_local *rcv)
 {
 	return OK;
@@ -440,8 +437,7 @@
 
 /* PLIP_RECEIVE --- receive a byte(two nibbles)
    Returns OK on success, TIMEOUT on timeout */
-inline static int
-plip_receive(unsigned short nibble_timeout, unsigned short status_addr,
+extern inline int plip_receive(unsigned short nibble_timeout, unsigned short status_addr,
 	     enum plip_nibble_state *ns_p, unsigned char *data_p)
 {
 	unsigned char c0, c1;
@@ -490,8 +486,7 @@
 }
 
 /* PLIP_RECEIVE_PACKET --- receive a packet */
-static int
-plip_receive_packet(struct device *dev, struct net_local *nl,
+static int plip_receive_packet(struct device *dev, struct net_local *nl,
 		    struct plip_local *snd, struct plip_local *rcv)
 {
 	unsigned short status_addr = PAR_STATUS(dev);
@@ -607,8 +602,7 @@
 
 /* PLIP_SEND --- send a byte (two nibbles)
    Returns OK on success, TIMEOUT when timeout    */
-inline static int
-plip_send(unsigned short nibble_timeout, unsigned short data_addr,
+extern inline int plip_send(unsigned short nibble_timeout, unsigned short data_addr,
 	  enum plip_nibble_state *ns_p, unsigned char data)
 {
 	unsigned char c0;
@@ -654,8 +648,7 @@
 }
 
 /* PLIP_SEND_PACKET --- send a packet */
-static int
-plip_send_packet(struct device *dev, struct net_local *nl,
+static int plip_send_packet(struct device *dev, struct net_local *nl,
 		 struct plip_local *snd, struct plip_local *rcv)
 {
 	unsigned short data_addr = PAR_DATA(dev);
@@ -759,8 +752,7 @@
 	return OK;
 }
 
-static int
-plip_connection_close(struct device *dev, struct net_local *nl,
+static int plip_connection_close(struct device *dev, struct net_local *nl,
 		      struct plip_local *snd, struct plip_local *rcv)
 {
 	cli();
@@ -774,8 +766,7 @@
 }
 
 /* PLIP_ERROR --- wait till other end settled */
-static int
-plip_error(struct device *dev, struct net_local *nl,
+static int plip_error(struct device *dev, struct net_local *nl,
 	   struct plip_local *snd, struct plip_local *rcv)
 {
 	unsigned char status;
@@ -799,8 +790,7 @@
 }
 
 /* Handle the parallel port interrupts. */
-static void
-plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct device *dev = (struct device *) irq2dev_map[irq];
 	struct net_local *nl = (struct net_local *)dev->priv;
@@ -853,8 +843,7 @@
 }
 
 /* We don't need to send arp, for plip is point-to-point. */
-static int
-plip_rebuild_header(struct sk_buff *skb)
+static int plip_rebuild_header(struct sk_buff *skb)
 {
 	struct device *dev = skb->dev;
 	struct net_local *nl = (struct net_local *)dev->priv;
@@ -888,8 +877,7 @@
 	return 0;
 }
 
-static int
-plip_tx_packet(struct sk_buff *skb, struct device *dev)
+static int plip_tx_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct net_local *nl = (struct net_local *)dev->priv;
 	struct plip_local *snd = &nl->snd_data;
@@ -941,8 +929,7 @@
    This routine gets exclusive access to the parallel port by allocating
    its IRQ line.
  */
-static int
-plip_open(struct device *dev)
+static int plip_open(struct device *dev)
 {
 	struct net_local *nl = (struct net_local *)dev->priv;
 	int i;
@@ -985,8 +972,7 @@
 }
 
 /* The inverse routine to plip_open (). */
-static int
-plip_close(struct device *dev)
+static int plip_close(struct device *dev)
 {
 	struct net_local *nl = (struct net_local *)dev->priv;
 	struct plip_local *snd = &nl->snd_data;
@@ -1019,17 +1005,15 @@
 	return 0;
 }
 
-static struct enet_statistics *
-plip_get_stats(struct device *dev)
+static struct net_device_stats *plip_get_stats(struct device *dev)
 {
 	struct net_local *nl = (struct net_local *)dev->priv;
-	struct enet_statistics *r = &nl->enet_stats;
+	struct net_device_stats *r = &nl->enet_stats;
 
 	return r;
 }
 
-static int
-plip_config(struct device *dev, struct ifmap *map)
+static int plip_config(struct device *dev, struct ifmap *map)
 {
 	if (dev->flags & IFF_UP)
 		return -EBUSY;
@@ -1043,8 +1027,7 @@
 	return 0;
 }
 
-static int
-plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+static int plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
 	struct net_local *nl = (struct net_local *) dev->priv;
 	struct plipconf *pc = (struct plipconf *) &rq->ifr_data;
@@ -1092,8 +1075,7 @@
 	}
 };
 
-int
-init_module(void)
+int init_module(void)
 {
 	int no_parameters=1;
 	int devices=0;
@@ -1134,8 +1116,7 @@
 	return 0;
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
 	int i;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v2.1.24/linux/drivers/net/ppp.c	Sun Feb  2 15:46:19 1997
+++ linux/drivers/net/ppp.c	Sun Feb  2 15:18:41 1997
@@ -183,7 +183,7 @@
 static int ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd);
 static int ppp_dev_close (struct device *);
 static int ppp_dev_xmit (sk_buff *, struct device *);
-static struct enet_statistics *ppp_dev_stats (struct device *);
+static struct net_device_stats *ppp_dev_stats (struct device *);
 
 /*
  * TTY callbacks
@@ -3080,11 +3080,11 @@
  * Generate the statistic information for the /proc/net/dev listing.
  */
 
-static struct enet_statistics *
+static struct net_device_stats *
 ppp_dev_stats (struct device *dev)
 {
 	struct ppp *ppp = dev2ppp (dev);
-	static struct enet_statistics ppp_stats;
+	static struct net_device_stats ppp_stats;
 
 	ppp_stats.rx_packets	      = ppp->stats.ppp_ipackets;
 	ppp_stats.rx_errors	      = ppp->stats.ppp_ierrors;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/pt.c linux/drivers/net/pt.c
--- v2.1.24/linux/drivers/net/pt.c	Thu Jan  2 15:55:19 1997
+++ linux/drivers/net/pt.c	Sun Feb  2 15:18:41 1997
@@ -124,7 +124,7 @@
 static void pt_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int pt_close(struct device *dev);
 static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static struct enet_statistics *pt_get_stats(struct device *dev);
+static struct net_device_stats *pt_get_stats(struct device *dev);
 static void pt_rts(struct pt_local *lp, int x);
 static void pt_rxisr(struct device *dev);
 static void pt_txisr(struct pt_local *lp);
@@ -175,10 +175,10 @@
 
 static void hardware_send_packet(struct pt_local *lp, struct sk_buff *skb)
 {
-    char kickflag;
-    unsigned long flags;
-    char *ptr;
-    struct device *dev;
+	char kickflag;
+	unsigned long flags;
+	char *ptr;
+	struct device *dev;
 
 	/* First, let's see if this packet is actually a KISS packet */
 	ptr = skb->data;
@@ -215,73 +215,78 @@
 		return;
 	}
 
-    lp->stats.tx_packets++;
-
-    save_flags(flags);
-    cli();
-    kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL);
-    restore_flags(flags);
+	lp->stats.tx_packets++;
+	lp->stats.tx_bytes+=skb->len;
+	save_flags(flags);
+	cli();
+	kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL);
+	restore_flags(flags);
 
 #ifdef PT_DEBUG
 	printk(KERN_DEBUG "PT: hardware_send_packet(): kickflag = %d (%d).\n", kickflag, lp->base & CHANA);
 #endif
-    skb_queue_tail(&lp->sndq, skb);
-    if (kickflag) {
+	skb_queue_tail(&lp->sndq, skb);
+	if (kickflag) 
+	{
         /* Simulate interrupt to transmit */
-            if (lp->dmachan)
-            {
-            	pt_txisr(lp);
-            } else {
-            	save_flags(flags);
+        	if (lp->dmachan)
+			pt_txisr(lp);
+		else 
+		{
+            		save_flags(flags);
 	           	cli();
-            	if (lp->tstate == IDLE)
-                	pt_txisr(lp);
-            	restore_flags(flags);
-            }
-    }
+            		if (lp->tstate == IDLE)
+                		pt_txisr(lp);
+            		restore_flags(flags);
+		}
+	}
 } /* hardware_send_packet() */
 
 static void setup_rx_dma(struct pt_local *lp)
 {
-    unsigned long flags;
-    int cmd;
-    unsigned long dma_abs;
-    unsigned char dmachan;
+	unsigned long flags;
+	int cmd;
+	unsigned long dma_abs;
+	unsigned char dmachan;
 
-    save_flags(flags);
-    cli();
+	save_flags(flags);
+	cli();
 
-    dma_abs = (unsigned long) (lp->rcvbuf->data);
-    dmachan = lp->dmachan;
-    cmd = lp->base + CTL;
+	dma_abs = (unsigned long) (lp->rcvbuf->data);
+	dmachan = lp->dmachan;
+	cmd = lp->base + CTL;
 
-    if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf)))
-	panic("PI: RX buffer violates DMA boundary!");
+	if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf)))
+		panic("PI: RX buffer violates DMA boundary!");
 
-    /* Get ready for RX DMA */
-    wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);
+	/* Get ready for RX DMA */
+	wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);
 
-    disable_dma(dmachan);
-    clear_dma_ff(dmachan);
+	disable_dma(dmachan);
+	clear_dma_ff(dmachan);
 
-    /* Set DMA mode register to single transfers, incrementing address,
-     *  auto init, writes
-     */
-    set_dma_mode(dmachan, DMA_MODE_READ | 0x10);
-    set_dma_addr(dmachan, dma_abs);
-    set_dma_count(dmachan, lp->bufsiz);
-    enable_dma(dmachan);
+	/*
+	 *	Set DMA mode register to single transfers, incrementing address,
+	 *	auto init, writes
+	 */
 
-    /* If a packet is already coming in, this line is supposed to
-	   avoid receiving a partial packet.
-     */
-    wrtscc(lp->cardbase, cmd, R0, RES_Rx_CRC);
+	set_dma_mode(dmachan, DMA_MODE_READ | 0x10);
+	set_dma_addr(dmachan, dma_abs);
+	set_dma_count(dmachan, lp->bufsiz);
+	enable_dma(dmachan);
 
-    /* Enable RX dma */
-    wrtscc(lp->cardbase, cmd, R1,
-      WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);
+	/*
+	 *	If a packet is already coming in, this line is supposed to
+	 *	avoid receiving a partial packet.
+	 */
 
-    restore_flags(flags);
+	wrtscc(lp->cardbase, cmd, R0, RES_Rx_CRC);
+
+	/* Enable RX dma */
+	wrtscc(lp->cardbase, cmd, R1,
+		WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);
+
+	restore_flags(flags);
 }
 
 static void setup_tx_dma(struct pt_local *lp, int length)
@@ -324,79 +329,76 @@
  */
 static void scc_init(struct device *dev)
 {
-    unsigned long flags;
-    struct pt_local *lp = (struct pt_local*) dev->priv;
-    register int cmd = lp->base + CTL;
-    int tc, br;
+	unsigned long flags;
+	struct pt_local *lp = (struct pt_local*) dev->priv;
+	register int cmd = lp->base + CTL;
+	int tc, br;
 
 #ifdef PT_DEBUG
 	printk(KERN_DEBUG "PT: scc_init(): (%d).\n", lp->base & CHANA);
 #endif
-    save_flags(flags);
-    cli();
+	save_flags(flags);
+	cli();
 
-    /* We may put something here to enable_escc */
+	/* We may put something here to enable_escc */
 
-    if (cmd & CHANA)
-    {
-        wrtscc(lp->cardbase, cmd, R9, CHRA);		/* Reset channel A */
-        wrtscc(lp->cardbase, cmd, R2, 0xff);		/* Initialise interrupt vector */
-    } else {
-    	wrtscc(lp->cardbase, cmd, R9, CHRB);		/* Reset channel B */
-    }
+	if (cmd & CHANA)
+	{
+	        wrtscc(lp->cardbase, cmd, R9, CHRA);	/* Reset channel A */
+	        wrtscc(lp->cardbase, cmd, R2, 0xff);	/* Initialise interrupt vector */
+	}
+	else
+	    	wrtscc(lp->cardbase, cmd, R9, CHRB);	/* Reset channel B */
 
-    /* Deselect all Rx and Tx interrupts */
-    wrtscc(lp->cardbase, cmd, R1, 0);
+	/* Deselect all Rx and Tx interrupts */
+	wrtscc(lp->cardbase, cmd, R1, 0);
 
-    /* Turn off external interrupts (like CTS/CD) */
-    wrtscc(lp->cardbase, cmd, R15, 0);
+	/* Turn off external interrupts (like CTS/CD) */
+	wrtscc(lp->cardbase, cmd, R15, 0);
 
-    /* X1 clock, SDLC mode */
-    wrtscc(lp->cardbase, cmd, R4, SDLC | X1CLK);
+	/* X1 clock, SDLC mode */
+	wrtscc(lp->cardbase, cmd, R4, SDLC | X1CLK);
 
 	/* Preset CRC and set mode */
 	if (lp->nrzi)
-	{
-    	/* Preset Tx CRC, put into NRZI mode */
-       wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI);
-    } else {
-    	/* Preset Tx CRC, put into NRZ mode */
-       wrtscc(lp->cardbase, cmd, R10, CRCPS);
-    }
-
-    /* Tx/Rx parameters */
-    if (lp->speed)		/* Use internal clocking */
-    {
-       /* Tx Clk from BRG. Rx Clk form DPLL, TRxC pin outputs DPLL */
-       wrtscc(lp->cardbase, cmd, R11, TCBR | RCDPLL | TRxCDP | TRxCOI);
+	    	/* Preset Tx CRC, put into NRZI mode */
+		wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI);
+	else
+		/* Preset Tx CRC, put into NRZ mode */
+		wrtscc(lp->cardbase, cmd, R10, CRCPS);
 
-    } else {			/* Use external clocking */
-           /* Tx Clk from TRxCL. Rx Clk from RTxCL, TRxC pin if input */
-           wrtscc(lp->cardbase, cmd, R11, TCTRxCP | RCRTxCP | TRxCBR);
-           wrtscc(lp->cardbase,cmd, R14, 0);	/* wiz1 */
-    }
+	/* Tx/Rx parameters */
+	if (lp->speed)		/* Use internal clocking */
+	       /* Tx Clk from BRG. Rx Clk form DPLL, TRxC pin outputs DPLL */
+	       wrtscc(lp->cardbase, cmd, R11, TCBR | RCDPLL | TRxCDP | TRxCOI);
+	else	/* Use external clocking */
+	{
+		/* Tx Clk from TRxCL. Rx Clk from RTxCL, TRxC pin if input */
+		wrtscc(lp->cardbase, cmd, R11, TCTRxCP | RCRTxCP | TRxCBR);
+        	wrtscc(lp->cardbase,cmd, R14, 0);	/* wiz1 */
+	}
 
-    /* Null out SDLC start address */
-    wrtscc(lp->cardbase, cmd, R6, 0);
+	/* Null out SDLC start address */
+	wrtscc(lp->cardbase, cmd, R6, 0);
 
-    /* SDLC flag */
-    wrtscc(lp->cardbase, cmd, R7, FLAG);
+	/* SDLC flag */
+	wrtscc(lp->cardbase, cmd, R7, FLAG);
 
-    /* Setup Tx but don't enable it */
-    wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR);
+	/* Setup Tx but don't enable it */
+	wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR);
 
-    /* Setup Rx */
-    wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8);
+	/* Setup Rx */
+	wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8);
 
-    /* Setup the BRG, turn it off first */
-    wrtscc(lp->cardbase, cmd, R14, BRSRC);
+	/* Setup the BRG, turn it off first */
+	wrtscc(lp->cardbase, cmd, R14, BRSRC);
 
-    /* set the 32x time constant for the BRG in Rx mode */
+	/* set the 32x time constant for the BRG in Rx mode */
 	if (lp->speed)
 	{
 		br = lp->speed;
 		tc = ((lp->xtal / 32) / (br * 2)) - 2;
-	    wrtscc(lp->cardbase, cmd, R12, tc & 0xff);		/* lower byte */
+		wrtscc(lp->cardbase, cmd, R12, tc & 0xff);		/* lower byte */
    		wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff);	/* upper byte */
 	}
 
@@ -409,36 +411,37 @@
 		/* DPLL frm BRG, BRG src PCLK */
 		wrtscc(lp->cardbase, cmd, R14, BRSRC | SSBR);
 		wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH);	/* SEARCH mode, keep BRG src */
-	    wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL);	/* Enable the BRG */
+		wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL);	/* Enable the BRG */
 
 	    /* Turn off external clock port */
-        if (lp->base & CHANA)
-            outb_p( (pt_sercfg &= ~PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );
-        else
-            outb_p( (pt_sercfg &= ~PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );
-    } else {
+		if (lp->base & CHANA)
+			outb_p( (pt_sercfg &= ~PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );
+		else
+			outb_p( (pt_sercfg &= ~PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );
+	}
+	else
+	{
 		/* DPLL frm rtxc,BRG src PCLK */
-/*		wrtscc(lp->cardbase, cmd, R14, BRSRC | SSRTxC);*/
-        /* Turn on external clock port */
-        if (lp->base & CHANA)
-            outb_p( (pt_sercfg |= PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );
-        else
-            outb_p( (pt_sercfg |= PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );
-    }
+		/* Turn on external clock port */
+		if (lp->base & CHANA)
+			outb_p( (pt_sercfg |= PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );
+		else
+			outb_p( (pt_sercfg |= PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );
+	}
 
-    if (!lp->dmachan)
+	if (!lp->dmachan)
 		wrtscc(lp->cardbase, cmd, R1, (INT_ALL_Rx | EXT_INT_ENAB));
 
-    wrtscc(lp->cardbase, cmd, R15, BRKIE);	/* ABORT int */
+	wrtscc(lp->cardbase, cmd, R15, BRKIE);	/* ABORT int */
 
 	/* Turn on the DTR to tell modem we're alive */
 	if (lp->base & CHANA)
-	    outb_p( (pt_sercfg |= PT_DTRA_ON), (lp->cardbase + SERIAL_CFG) );
+		outb_p( (pt_sercfg |= PT_DTRA_ON), (lp->cardbase + SERIAL_CFG) );
 	else
-    	outb_p( (pt_sercfg |= PT_DTRB_ON), (lp->cardbase + SERIAL_CFG) );
+	    	outb_p( (pt_sercfg |= PT_DTRB_ON), (lp->cardbase + SERIAL_CFG) );
 
-    /* Now, turn on the receiver and hunt for a flag */
-    wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | AUTO_ENAB | Rx8 );
+	/* Now, turn on the receiver and hunt for a flag */
+	wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | AUTO_ENAB | Rx8 );
 
 	restore_flags(flags);
 
@@ -1075,14 +1078,15 @@
     return ret;
 }
 
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
-static struct netstats *
- pt_get_stats(struct device *dev)
+/*
+ *	Get the current statistics.
+ *	This may be called with the card open or closed. 
+ */
+ 
+static struct net_device_stats *pt_get_stats(struct device *dev)
 {
-    struct pt_local *lp = (struct pt_local *) dev->priv;
-
-    return &lp->stats;
+	struct pt_local *lp = (struct pt_local *) dev->priv;
+	return &lp->stats;
 }
 
 
@@ -1102,13 +1106,16 @@
 	if (!lp->dmachan)
 		wrtscc(lp->cardbase, lp->base + CTL, R1, INT_ALL_Rx | EXT_INT_ENAB);
 
-    if (lp->base & CHANA) {
-        outb_p(time & 0xff, lp->cardbase + TMR1);
-        outb_p((time >> 8)&0xff, lp->cardbase + TMR1);
-    } else {
-        outb_p(time & 0xff, lp->cardbase + TMR2);
-        outb_p((time >> 8)&0xff, lp->cardbase + TMR2);
-    }
+	if (lp->base & CHANA) 
+	{
+		outb_p(time & 0xff, lp->cardbase + TMR1);
+		outb_p((time >> 8)&0xff, lp->cardbase + TMR1);
+	}
+	else
+	{
+		outb_p(time & 0xff, lp->cardbase + TMR2);
+		outb_p((time >> 8)&0xff, lp->cardbase + TMR2);
+	}
 } /* tdelay */
 
 
@@ -1379,6 +1386,7 @@
                     memcpy(cfix, lp->rcvbuf->data, pkt_len - 1);
                  skb->protocol = ntohs(ETH_P_AX25);
                  skb->mac.raw=skb->data;
+                 lp->stats.rx_bytes+=skb->len;
                  IS_SKB(skb);
                  netif_rx(skb);
                  lp->stats.rx_packets++;
@@ -1767,21 +1775,21 @@
 
 int init_module(void)
 {
-    return pt_init();
+	return pt_init();
 }
 
 void cleanup_module(void)
 {
-    free_irq(pt0a.irq, NULL);	/* IRQs and IO Ports are shared */
-    release_region(pt0a.base_addr & 0x3f0, PT_TOTAL_SIZE);
-    irq2dev_map[pt0a.irq] = NULL;
-
-    kfree(pt0a.priv);
-    pt0a.priv = NULL;
-    unregister_netdev(&pt0a);
-
-    kfree(pt0b.priv);
-    pt0b.priv = NULL;
-    unregister_netdev(&pt0b);
+	free_irq(pt0a.irq, NULL);	/* IRQs and IO Ports are shared */
+	release_region(pt0a.base_addr & 0x3f0, PT_TOTAL_SIZE);
+	irq2dev_map[pt0a.irq] = NULL;
+
+	kfree(pt0a.priv);
+	pt0a.priv = NULL;
+	unregister_netdev(&pt0a);
+
+	kfree(pt0b.priv);
+	pt0b.priv = NULL;
+	unregister_netdev(&pt0b);
 }
 #endif
diff -u --recursive --new-file v2.1.24/linux/drivers/net/pt.h linux/drivers/net/pt.h
--- v2.1.24/linux/drivers/net/pt.h	Tue Dec 26 06:03:00 1995
+++ linux/drivers/net/pt.h	Sun Feb  2 15:18:41 1997
@@ -6,9 +6,6 @@
  */
 #define DMA_BUFF_SIZE 2200
 
-/* Network statistics, with the same names as 'struct enet_statistics'. */
-#define netstats enet_statistics
-
 #define ON 1
 #define OFF 0
 
@@ -98,16 +95,17 @@
 #define SIOCGPIIRQ		0x5006	/* get only IRQ */
 #define SIOCSPIIRQ		0x5007	
 
-struct pt_req  {
-    int cmd;
-    int speed;
-    int clockmode;
-    int txdelay;
-    unsigned char persist;
-    int slotime; 
-    int squeldelay;
-    int dmachan;    
-    int irq;    
+struct pt_req
+{
+	int cmd;
+	int speed;
+	int clockmode;
+	int txdelay;
+	unsigned char persist;
+	int slotime; 
+	int squeldelay;
+	int dmachan;    
+	int irq;    
 };
 
 /* SCC Interrupt vectors, if we have set 'status low' */
@@ -124,53 +122,53 @@
 #ifdef __KERNEL__
 
 /* Information that needs to be kept for each channel. */
-struct pt_local {
-    struct netstats stats; /* %%%dp*/
-    long open_time;             /* Useless example local info. */
-    unsigned long xtal; 
-
-    struct mbuf *rcvbuf;/* Buffer for current rx packet */
-    struct mbuf *rxdmabuf1; /* DMA rx buffer */
-    struct mbuf *rxdmabuf2; /* DMA rx buffer */
-
-    int bufsiz;         /* Size of rcvbuf */
-    char *rcp;          /* Pointer into rcvbuf */
-
-    struct sk_buff_head sndq;  /* Packets awaiting transmission */
-    int sndcnt;         /* Number of packets on sndq */
-    struct sk_buff *sndbuf;/* Current buffer being transmitted */
-    char *txdmabuf;     /* Transmit DMA buffer */
-	char *txptr;		/* Used by B port tx */
+struct pt_local
+{
+	struct net_device_stats stats; /* %%%dp*/
+	long open_time;             /* Useless example local info. */
+	unsigned long xtal; 
+
+	struct mbuf *rcvbuf;/* Buffer for current rx packet */
+	struct mbuf *rxdmabuf1; /* DMA rx buffer */
+	struct mbuf *rxdmabuf2; /* DMA rx buffer */
+
+	int bufsiz;			/* Size of rcvbuf 			*/
+	char *rcp;			/* Pointer into rcvbuf 			*/
+	struct sk_buff_head sndq;	/* Packets awaiting transmission 	*/
+	int sndcnt;			/* Number of packets on sndq 		*/
+	struct sk_buff *sndbuf;		/* Current buffer being transmitted	*/
+	char *txdmabuf; 		/* Transmit DMA buffer 			*/
+	char *txptr;			/* Used by B port tx 			*/
 	int txcnt;			
-    char tstate;        /* Transmitter state */
-#define IDLE    0       /* Transmitter off, no data pending */
-#define ACTIVE  1       /* Transmitter on, sending data */
-#define UNDERRUN 2      /* Transmitter on, flushing CRC */
-#define FLAGOUT 3       /* CRC sent - attempt to start next frame */
-#define DEFER 4         /* Receive Active - DEFER Transmit */
-#define ST_TXDELAY 5    /* Sending leading flags */
+	char tstate;			/* Transmitter state 			*/
+#define IDLE    0       /* Transmitter off, no data pending 		*/
+#define ACTIVE  1       /* Transmitter on, sending data 		*/
+#define UNDERRUN 2      /* Transmitter on, flushing CRC			*/
+#define FLAGOUT 3       /* CRC sent - attempt to start next frame	*/
+#define DEFER 4         /* Receive Active - DEFER Transmit		*/
+#define ST_TXDELAY 5    /* Sending leading flags			*/
 #define CRCOUT 6
-    char rstate;        /* Set when !DCD goes to 0 (TRUE) */
+	char rstate;        /* Set when !DCD goes to 0 (TRUE)		*/
 /* Normal state is ACTIVE if Receive enabled */
-#define RXERROR 2       /* Error -- Aborting current Frame */
-#define RXABORT 3       /* ABORT sequence detected */
-#define TOOBIG 4        /* too large a frame to store */
+#define RXERROR 2       /* Error -- Aborting current Frame		*/
+#define RXABORT 3       /* ABORT sequence detected			*/
+#define TOOBIG 4        /* too large a frame to store			*/
 	
-    int dev;            /* Device number */
-    int base;       /* Base of I/O registers */
-    int cardbase;     /* Base address of card */
-    int stata;        /* address of Channel A status regs */
-    int statb;        /* address of Channel B status regs */
-    int speed;        /* Line speed, bps */
-    int clockmode;    /* tapr 9600 modem clocking option */
-    int txdelay;      /* Transmit Delay 10 ms/cnt */
-    unsigned char persist;       /* Persistence (0-255) as a % */
-    int slotime;      /* Delay to wait on persistence hit */
-    int squeldelay;   /* Delay after XMTR OFF for squelch tail */
-    struct iface *iface;    /* Associated interface */
-    int dmachan;           /* DMA channel for this port */
-    char saved_RR0;	/* The saved version of RR) that we compare with */
-    int nrzi;			/* Do we use NRZI (or NRZ) */
+	int dev;		/* Device number */
+	int base;		/* Base of I/O registers */
+	int cardbase;		/* Base address of card */
+	int stata;		/* address of Channel A status regs */
+	int statb;		/* address of Channel B status regs */
+	int speed;        	/* Line speed, bps */
+	int clockmode;    	/* tapr 9600 modem clocking option */
+	int txdelay;      	/* Transmit Delay 10 ms/cnt */
+	unsigned char persist;  /* Persistence (0-255) as a % */
+	int slotime;		/* Delay to wait on persistence hit */
+	int squeldelay; 	/* Delay after XMTR OFF for squelch tail */
+	struct iface *iface;    /* Associated interface */
+	int dmachan;		/* DMA channel for this port */
+	char saved_RR0;		/* The saved version of RR) that we compare with */
+	int nrzi;		/* Do we use NRZI (or NRZ) */
 };
 
 #endif
diff -u --recursive --new-file v2.1.24/linux/drivers/net/scc.c linux/drivers/net/scc.c
--- v2.1.24/linux/drivers/net/scc.c	Thu Jan 23 21:06:48 1997
+++ linux/drivers/net/scc.c	Sun Feb  2 15:18:41 1997
@@ -204,7 +204,7 @@
 static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
 static int scc_net_set_mac_address(struct device *dev, void *addr);
 static int scc_net_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);
-static struct enet_statistics * scc_net_get_stats(struct device *dev);
+static struct net_device_stats * scc_net_get_stats(struct device *dev);
 
 static unsigned char *SCC_DriverName = "scc";
 
@@ -1663,12 +1663,6 @@
                 dev->trans_start = jiffies;
         }
         
-	if (skb == NULL)
-	{
-		dev_tint(dev);
-		return 0;
-	}
-	
 	if (scc == NULL || scc->magic != SCC_MAGIC)
 	{
 		dev_kfree_skb(skb, FREE_WRITE);
@@ -1971,12 +1965,12 @@
 static int  scc_net_header(struct sk_buff *skb, struct device *dev, 
 	unsigned short type, void *daddr, void *saddr, unsigned len)
 {
-    return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
+	return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
 }
 
 /* ----> get statistics <---- */
 
-static struct enet_statistics *scc_net_get_stats(struct device *dev)
+static struct net_device_stats *scc_net_get_stats(struct device *dev)
 {
 	struct scc_channel *scc = (struct scc_channel *) dev->priv;
 	
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- v2.1.24/linux/drivers/net/sdla.c	Thu Jan  2 15:55:19 1997
+++ linux/drivers/net/sdla.c	Sun Feb  2 15:18:41 1997
@@ -82,147 +82,145 @@
 
 static void sdla_read(struct device *dev, int addr, void *buf, short len)
 {
-   unsigned long flags;
-   char          *temp, *base;
-   int           offset, bytes;
-
-   temp = buf;
-   while(len)
-   {
-      offset = addr & SDLA_ADDR_MASK;
-      bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
-      base = (void *) (dev->mem_start + offset);
-
-      save_flags(flags);
-      cli();
-      SDLA_WINDOW(dev, addr);
-      memcpy(temp, base, bytes);
-      restore_flags(flags);
-
-      addr += bytes;
-      temp += bytes;
-      len  -= bytes;
-   }  
+	unsigned long flags;
+	char          *temp, *base;
+	int           offset, bytes;
+
+	temp = buf;
+	while(len)
+	{	
+		offset = addr & SDLA_ADDR_MASK;
+		bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
+		base = (void *) (dev->mem_start + offset);
+
+		save_flags(flags);
+		cli();
+		SDLA_WINDOW(dev, addr);
+		memcpy(temp, base, bytes);
+		restore_flags(flags);
+
+		addr += bytes;
+		temp += bytes;
+		len  -= bytes;
+	}  
 }
 
 static void sdla_write(struct device *dev, int addr, void *buf, short len)
 {
-   unsigned long flags;
-   char          *temp, *base;
-   int           offset, bytes;
-
-   temp = buf;
-   while(len)
-   {
-      offset = addr & SDLA_ADDR_MASK;
-      bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
-      base = (void *) (dev->mem_start + offset);
-
-      save_flags(flags);
-      cli();
-      SDLA_WINDOW(dev, addr);
-      memcpy(base, temp, bytes);
-      restore_flags(flags);
-
-      addr += bytes;
-      temp += bytes;
-      len  -= bytes;
-   }
+	unsigned long flags;
+	char          *temp, *base;
+	int           offset, bytes;
+
+	temp = buf;
+	while(len)
+	{
+		offset = addr & SDLA_ADDR_MASK;
+		bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
+		base = (void *) (dev->mem_start + offset);
+		save_flags(flags);
+		cli();
+		SDLA_WINDOW(dev, addr);
+		memcpy(base, temp, bytes);
+		restore_flags(flags);
+		addr += bytes;
+		temp += bytes;
+		len  -= bytes;
+	}
 }
 
 static void sdla_clear(struct device *dev)
 {
-   unsigned long flags;
-   char          *base;
-   int           len, addr, bytes;
-
-   len = 65536;
-   addr = 0;
-   bytes = SDLA_WINDOW_SIZE;
-   base = (void *) dev->mem_start;
-
-   save_flags(flags);
-   cli();
-   while(len)
-   {
-      SDLA_WINDOW(dev, addr);
-      memset(base, 0, bytes);
-
-      addr += bytes;
-      len  -= bytes;
-   }
-   restore_flags(flags);
+	unsigned long flags;
+	char          *base;
+	int           len, addr, bytes;
+
+	len = 65536;	
+	addr = 0;
+	bytes = SDLA_WINDOW_SIZE;
+	base = (void *) dev->mem_start;
+
+	save_flags(flags);
+	cli();
+	while(len)
+	{
+		SDLA_WINDOW(dev, addr);
+		memset(base, 0, bytes);
+
+		addr += bytes;
+		len  -= bytes;
+	}
+	restore_flags(flags);
 }
 
 static char sdla_byte(struct device *dev, int addr)
 {
-   unsigned long flags;
-   char          byte, *temp;
+	unsigned long flags;
+	char          byte, *temp;
 
-   temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK));
+	temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK));
 
-   save_flags(flags);
-   cli();
-   SDLA_WINDOW(dev, addr);
-   byte = *temp;
-   restore_flags(flags);
+	save_flags(flags);
+	cli();
+	SDLA_WINDOW(dev, addr);
+	byte = *temp;
+	restore_flags(flags);
 
-   return(byte);
+	return(byte);
 }
 
 void sdla_stop(struct device *dev)
 {
-   struct frad_local *flp;
+	struct frad_local *flp;
 
-   flp = dev->priv;
-   switch(flp->type)
-   {
-      case SDLA_S502A:
-         outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
-         flp->state = SDLA_HALT;
-         break;
-      case SDLA_S502E:
-         outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
-         outb(SDLA_S502E_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
-         flp->state = SDLA_S502E_ENABLE;
-         break;
-      case SDLA_S507:
-         flp->state &= ~SDLA_CPUEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-      case SDLA_S508:
-         flp->state &= ~SDLA_CPUEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-   }
+	flp = dev->priv;
+	switch(flp->type)
+	{
+		case SDLA_S502A:
+			outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
+			flp->state = SDLA_HALT;
+			break;
+		case SDLA_S502E:
+			outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
+			outb(SDLA_S502E_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
+			flp->state = SDLA_S502E_ENABLE;
+			break;
+		case SDLA_S507:
+			flp->state &= ~SDLA_CPUEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+		case SDLA_S508:
+			flp->state &= ~SDLA_CPUEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+	}
 }
 
 void sdla_start(struct device *dev)
 {
-   struct frad_local *flp;
+	struct frad_local *flp;
 
-   flp = dev->priv;
-   switch(flp->type)
-   {
-      case SDLA_S502A:
-         outb(SDLA_S502A_NMI, dev->base_addr + SDLA_REG_CONTROL);
-         outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
-         flp->state = SDLA_S502A_START;
-         break;
-      case SDLA_S502E:
-         outb(SDLA_S502E_CPUEN, dev->base_addr + SDLA_REG_Z80_CONTROL);
-         outb(0x00, dev->base_addr + SDLA_REG_CONTROL);
-         flp->state = 0;
-         break;
-      case SDLA_S507:
-         flp->state |= SDLA_CPUEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-      case SDLA_S508:
-         flp->state |= SDLA_CPUEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-   }
+	flp = dev->priv;
+	switch(flp->type)
+	{
+		case SDLA_S502A:
+			outb(SDLA_S502A_NMI, dev->base_addr + SDLA_REG_CONTROL);
+			outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
+			flp->state = SDLA_S502A_START;
+			break;
+		case SDLA_S502E:
+			outb(SDLA_S502E_CPUEN, dev->base_addr + SDLA_REG_Z80_CONTROL);
+			outb(0x00, dev->base_addr + SDLA_REG_CONTROL);
+			flp->state = 0;
+			break;
+		case SDLA_S507:
+			flp->state |= SDLA_CPUEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+		case SDLA_S508:
+			flp->state |= SDLA_CPUEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+	}
 }
 
 /****************************************************
@@ -237,26 +235,26 @@
 
 int sdla_z80_poll(struct device *dev, int z80_addr, int jiffs, char resp1, char resp2)
 {
-   unsigned long start, done, now;
-   char          resp, *temp;
+	unsigned long start, done, now;
+	char          resp, *temp;
 
-   start = now = jiffies;
-   done = jiffies + jiffs;
+	start = now = jiffies;
+	done = jiffies + jiffs;
 
-   temp = (void *)dev->mem_start;
-   temp += z80_addr & SDLA_ADDR_MASK;
-
-   resp = ~resp1;
-   while ((jiffies < done) && (resp != resp1) && (!resp2 || (resp != resp2)))
-   {
-      if (jiffies != now)
-      {
-         SDLA_WINDOW(dev, z80_addr);
-         now = jiffies;
-         resp = *temp;
-      }
-   }
-   return(jiffies < done ? jiffies - start : -1);
+	temp = (void *)dev->mem_start;
+	temp += z80_addr & SDLA_ADDR_MASK;
+	
+	resp = ~resp1;
+	while ((jiffies < done) && (resp != resp1) && (!resp2 || (resp != resp2)))
+	{
+		if (jiffies != now)
+		{
+			SDLA_WINDOW(dev, z80_addr);
+			now = jiffies;
+			resp = *temp;
+		}
+	}
+	return(jiffies < done ? jiffies - start : -1);
 }
 
 /* constants for Z80 CPU speed */
@@ -267,46 +265,45 @@
 
 static int sdla_cpuspeed(struct device *dev, struct ifreq *ifr)
 {
-   int  jiffs;
-   char data;
+	int  jiffs;
+	char data;
 
-   sdla_start(dev);
-   if (sdla_z80_poll(dev, 0, 3*HZ, Z80_READY, 0) < 0)
-      return(-EIO);
-
-   data = LOADER_READY;
-   sdla_write(dev, 0, &data, 1);
-
-   if ((jiffs = sdla_z80_poll(dev, 0, 8*HZ, Z80_SCC_OK, Z80_SCC_BAD)) < 0)
-      return(-EIO);
-
-   sdla_stop(dev);
-   sdla_read(dev, 0, &data, 1);
-
-   if (data == Z80_SCC_BAD)
-      return(-EIO);
-
-   if (data != Z80_SCC_OK)
-      return(-EINVAL);
-
-   if (jiffs < 165)
-      ifr->ifr_mtu = SDLA_CPU_16M;
-   else
-      if (jiffs < 220)
-         ifr->ifr_mtu = SDLA_CPU_10M;
-      else
-         if (jiffs < 258)
-            ifr->ifr_mtu = SDLA_CPU_8M;
-         else
-            if (jiffs < 357)
-               ifr->ifr_mtu = SDLA_CPU_7M;
-            else
-               if (jiffs < 467)
-                  ifr->ifr_mtu = SDLA_CPU_5M;
-               else
-                  ifr->ifr_mtu = SDLA_CPU_3M;
+	sdla_start(dev);
+	if (sdla_z80_poll(dev, 0, 3*HZ, Z80_READY, 0) < 0)
+		return(-EIO);
+
+	data = LOADER_READY;
+	sdla_write(dev, 0, &data, 1);
+
+	if ((jiffs = sdla_z80_poll(dev, 0, 8*HZ, Z80_SCC_OK, Z80_SCC_BAD)) < 0)
+		return(-EIO);
+
+	sdla_stop(dev);
+	sdla_read(dev, 0, &data, 1);
+
+	if (data == Z80_SCC_BAD)
+	{
+		printk("%s: SCC bad\n", dev->name);
+		return(-EIO);
+	}
+
+	if (data != Z80_SCC_OK)
+		return(-EINVAL);
+
+	if (jiffs < 165)
+		ifr->ifr_mtu = SDLA_CPU_16M;
+	else if (jiffs < 220)
+		ifr->ifr_mtu = SDLA_CPU_10M;
+	else if (jiffs < 258)
+		ifr->ifr_mtu = SDLA_CPU_8M;
+	else if (jiffs < 357)
+		ifr->ifr_mtu = SDLA_CPU_7M;
+	else if (jiffs < 467)
+		ifr->ifr_mtu = SDLA_CPU_5M;
+	else
+		ifr->ifr_mtu = SDLA_CPU_3M;
  
-   return(0);
+	return(0);
 }
 
 /************************************************
@@ -316,175 +313,174 @@
  *
  ************************************************/
 
-struct _dlci_stat {
-   short dlci		__attribute__((packed));
-   char  flags		__attribute__((packed));
+struct _dlci_stat 
+{
+	short dlci		__attribute__((packed));
+	char  flags		__attribute__((packed));
 };
 
-struct _frad_stat {
-   char    flags;
-   struct _dlci_stat dlcis[SDLA_MAX_DLCI];
+struct _frad_stat 
+{
+	char    flags;
+	struct _dlci_stat dlcis[SDLA_MAX_DLCI];
 };
 
 static void sdla_errors(struct device *dev, int cmd, int dlci, int ret, int len, void *data) 
 {
-   struct _dlci_stat *pstatus;
-   short             *pdlci;
-   int               i;
-   char              *state, line[30];
-
-   switch (ret)
-   {
-      case SDLA_RET_MODEM:
-         state = data;
-         if (*state & SDLA_MODEM_DCD_LOW)
-            printk(KERN_INFO "%s: Modem DCD unexpectedly low!\n", dev->name);
-         if (*state & SDLA_MODEM_CTS_LOW)
-            printk(KERN_INFO "%s: Modem CTS unexpectedly low!\n", dev->name);
-/* I should probably do something about this! */
-         break;
-
-      case SDLA_RET_CHANNEL_OFF:
-         printk(KERN_INFO "%s: Channel became inoperative!\n", dev->name);
-/* same here */
-         break;
-
-      case SDLA_RET_CHANNEL_ON:
-         printk(KERN_INFO "%s: Channel became operative!\n", dev->name);
-/* same here */
-         break;
-
-      case SDLA_RET_DLCI_STATUS:
-         printk(KERN_INFO "%s: Status change reported by Access Node.\n", dev->name);
-         len /= sizeof(struct _dlci_stat);
-         for(pstatus = data, i=0;i < len;i++,pstatus++)
-         {
-            if (pstatus->flags & SDLA_DLCI_NEW)
-               state = "new";
-            else
-               if (pstatus->flags & SDLA_DLCI_DELETED)
-                  state = "deleted";
-               else
-                  if (pstatus->flags & SDLA_DLCI_ACTIVE)
-                     state = "active";
-                  else
-                  {
-                     sprintf(line, "unknown status: %02X", pstatus->flags);
-                     state = line;
-                  }
-            printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);
-/* same here */
-         }
-         break;
-
-      case SDLA_RET_DLCI_UNKNOWN:
-         printk(KERN_INFO "%s: Received unknown DLCIs:", dev->name);
-         len /= sizeof(short);
-         for(pdlci = data,i=0;i < len;i++,pdlci++)
-            printk(" %i", *pdlci);
-         printk("\n");
-         break;
-
-      case SDLA_RET_TIMEOUT:
-         printk(KERN_ERR "%s: Command timed out!\n", dev->name);
-         break;
-
-      case SDLA_RET_BUF_OVERSIZE:
-         printk(KERN_INFO "%s: Bc/CIR overflow, acceptable size is %i\n", dev->name, len);
-         break;
-
-      case SDLA_RET_BUF_TOO_BIG:
-         printk(KERN_INFO "%s: Buffer size over specified max of %i\n", dev->name, len);
-         break;
-
-      case SDLA_RET_CHANNEL_INACTIVE:
-      case SDLA_RET_DLCI_INACTIVE:
-      case SDLA_RET_CIR_OVERFLOW:
-      case SDLA_RET_NO_BUFS:
-         if (cmd == SDLA_INFORMATION_WRITE)
-            break;
-
-      default: 
-         printk(KERN_DEBUG "%s: Cmd 0x%2.2X generated return code 0x%2.2X\n", dev->name, cmd, ret);
-/* Further processing could be done here */
-         break;
-   }
+	struct _dlci_stat *pstatus;
+	short             *pdlci;
+	int               i;
+	char              *state, line[30];
+
+	switch (ret)
+	{
+		case SDLA_RET_MODEM:
+			state = data;
+			if (*state & SDLA_MODEM_DCD_LOW)
+				printk(KERN_INFO "%s: Modem DCD unexpectedly low!\n", dev->name);
+			if (*state & SDLA_MODEM_CTS_LOW)
+				printk(KERN_INFO "%s: Modem CTS unexpectedly low!\n", dev->name);
+			/* I should probably do something about this! */
+			break;
+
+		case SDLA_RET_CHANNEL_OFF:
+			printk(KERN_INFO "%s: Channel became inoperative!\n", dev->name);
+			/* same here */
+			break;
+
+		case SDLA_RET_CHANNEL_ON:
+			printk(KERN_INFO "%s: Channel became operative!\n", dev->name);
+			/* same here */
+			break;
+
+		case SDLA_RET_DLCI_STATUS:
+			printk(KERN_INFO "%s: Status change reported by Access Node.\n", dev->name);
+			len /= sizeof(struct _dlci_stat);
+			for(pstatus = data, i=0;i < len;i++,pstatus++)
+			{
+				if (pstatus->flags & SDLA_DLCI_NEW)
+					state = "new";
+				else if (pstatus->flags & SDLA_DLCI_DELETED)
+					state = "deleted";
+				else if (pstatus->flags & SDLA_DLCI_ACTIVE)
+					state = "active";
+				else
+				{
+					sprintf(line, "unknown status: %02X", pstatus->flags);
+					state = line;
+				}
+				printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);
+				/* same here */
+			}
+			break;
+
+		case SDLA_RET_DLCI_UNKNOWN:
+			printk(KERN_INFO "%s: Received unknown DLCIs:", dev->name);
+			len /= sizeof(short);
+			for(pdlci = data,i=0;i < len;i++,pdlci++)
+				printk(" %i", *pdlci);
+			printk("\n");
+			break;
+
+		case SDLA_RET_TIMEOUT:
+			printk(KERN_ERR "%s: Command timed out!\n", dev->name);
+			break;
+
+		case SDLA_RET_BUF_OVERSIZE:
+			printk(KERN_INFO "%s: Bc/CIR overflow, acceptable size is %i\n", dev->name, len);
+			break;
+
+		case SDLA_RET_BUF_TOO_BIG:
+			printk(KERN_INFO "%s: Buffer size over specified max of %i\n", dev->name, len);
+			break;
+
+		case SDLA_RET_CHANNEL_INACTIVE:
+		case SDLA_RET_DLCI_INACTIVE:
+		case SDLA_RET_CIR_OVERFLOW:
+		case SDLA_RET_NO_BUFS:
+			if (cmd == SDLA_INFORMATION_WRITE)
+				break;
+
+		default: 
+			printk(KERN_DEBUG "%s: Cmd 0x%2.2X generated return code 0x%2.2X\n", dev->name, cmd, ret);
+			/* Further processing could be done here */
+			break;
+	}
 }
 
 static int sdla_cmd(struct device *dev, int cmd, short dlci, short flags, 
                         void *inbuf, short inlen, void *outbuf, short *outlen)
 {
-   static struct _frad_stat status;
-   struct frad_local        *flp;
-   struct sdla_cmd          *cmd_buf;
-   unsigned long            pflags;
-   int                      jiffs, ret, waiting, len;
-   long                     window;
-
-   flp = dev->priv;
-
-   window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;
-   cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));
-   ret = 0;
-   len = 0;
-   jiffs = jiffies + HZ;  /* 1 second is plenty */
-   save_flags(pflags);
-   cli();
-   SDLA_WINDOW(dev, window);
-   cmd_buf->cmd = cmd;
-   cmd_buf->dlci = dlci;
-   cmd_buf->flags = flags;
-
-   if (inbuf)
-      memcpy(cmd_buf->data, inbuf, inlen);
-
-   cmd_buf->length = inlen;
-
-   cmd_buf->opp_flag = 1;
-   restore_flags(pflags);
-
-   waiting = 1;
-   len = 0;
-   while (waiting && (jiffies <= jiffs))
-   {
-      if (waiting++ % 3) 
-      {
-         save_flags(pflags);
-         cli();
-         SDLA_WINDOW(dev, window);
-         waiting = ((volatile)(cmd_buf->opp_flag));
-         restore_flags(pflags);
-      }
-   }
-   
-   if (!waiting)
-   {
-      save_flags(pflags);
-      cli();
-      SDLA_WINDOW(dev, window);
-      ret = cmd_buf->retval;
-      len = cmd_buf->length;
-      if (outbuf && outlen)
-      {
-         *outlen = *outlen >= len ? len : *outlen;
-
-         if (*outlen)
-            memcpy(outbuf, cmd_buf->data, *outlen);
-      }
-
-      /* This is a local copy that's used for error handling */
-      if (ret)
-         memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len);
-
-      restore_flags(pflags);
-   }
-   else
-      ret = SDLA_RET_TIMEOUT;
+	static struct _frad_stat status;
+	struct frad_local        *flp;
+	struct sdla_cmd          *cmd_buf;
+	unsigned long            pflags;
+	int                      jiffs, ret, waiting, len;
+	long                     window;
+
+	flp = dev->priv;
+	window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;
+	cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));
+	ret = 0;
+	len = 0;
+	jiffs = jiffies + HZ;  /* 1 second is plenty */
+	save_flags(pflags);
+	cli();
+	SDLA_WINDOW(dev, window);
+	cmd_buf->cmd = cmd;
+	cmd_buf->dlci = dlci;
+	cmd_buf->flags = flags;
+
+	if (inbuf)
+		amemcpy(cmd_buf->data, inbuf, inlen);
+
+	cmd_buf->length = inlen;
+
+	cmd_buf->opp_flag = 1;
+	restore_flags(pflags);
+
+	waiting = 1;
+	len = 0;
+	while (waiting && (jiffies <= jiffs))
+	{
+		if (waiting++ % 3) 
+		{
+			save_flags(pflags);
+			cli();
+			SDLA_WINDOW(dev, window);
+			waiting = ((volatile)(cmd_buf->opp_flag));
+			restore_flags(pflags);
+		}
+	}
+	
+	if (!waiting)
+	{
+		save_flags(pflags);
+		cli();
+		SDLA_WINDOW(dev, window);
+		ret = cmd_buf->retval;
+		len = cmd_buf->length;
+		if (outbuf && outlen)
+		{
+			*outlen = *outlen >= len ? len : *outlen;
+
+			if (*outlen)
+				memcpy(outbuf, cmd_buf->data, *outlen);
+		}
+
+		/* This is a local copy that's used for error handling */
+		if (ret)
+			memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len);
+
+		restore_flags(pflags);
+	}
+	else
+		ret = SDLA_RET_TIMEOUT;
 
-   if (ret != SDLA_RET_OK)
-      sdla_errors(dev, cmd, dlci, ret, len, &status);
+	if (ret != SDLA_RET_OK)
+	   	sdla_errors(dev, cmd, dlci, ret, len, &status);
 
-   return(ret);
+	return(ret);
 }
 
 /***********************************************
@@ -497,141 +493,141 @@
 
 int sdla_activate(struct device *slave, struct device *master)
 {
-   struct frad_local *flp;
-   int               i;
+	struct frad_local *flp;
+	int i;
 
-   flp = slave->priv;
+	flp = slave->priv;
 
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->master[i] == master)
-         break;
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->master[i] == master)
+			break;
 
-   if (i == CONFIG_DLCI_MAX)
-      return(-ENODEV);
+	if (i == CONFIG_DLCI_MAX)
+		return(-ENODEV);
 
-   flp->dlci[i] = abs(flp->dlci[i]);
+	flp->dlci[i] = abs(flp->dlci[i]);
 
-   if (slave->start && (flp->config.station == FRAD_STATION_NODE))
-      sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
+	if (slave->start && (flp->config.station == FRAD_STATION_NODE))
+		sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
 
-   return(0);
+	return(0);
 }
 
 int sdla_deactivate(struct device *slave, struct device *master)
 {
-   struct frad_local *flp;
-   int               i;
+	struct frad_local *flp;
+	int               i;
 
-   flp = slave->priv;
+	flp = slave->priv;
 
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->master[i] == master)
-         break;
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->master[i] == master)
+			break;
 
-   if (i == CONFIG_DLCI_MAX)
-      return(-ENODEV);
+	if (i == CONFIG_DLCI_MAX)
+		return(-ENODEV);
 
-   flp->dlci[i] = -abs(flp->dlci[i]);
+	flp->dlci[i] = -abs(flp->dlci[i]);
 
-   if (slave->start && (flp->config.station == FRAD_STATION_NODE))
-      sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
+	if (slave->start && (flp->config.station == FRAD_STATION_NODE))
+		sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
 
-   return(0);
+	return(0);
 }
 
 int sdla_assoc(struct device *slave, struct device *master)
 {
-   struct frad_local *flp;
-   int               i;
+	struct frad_local *flp;
+	int               i;
 
-   if (master->type != ARPHRD_DLCI)
-      return(-EINVAL);
+	if (master->type != ARPHRD_DLCI)
+		return(-EINVAL);
 
-   flp = slave->priv;
+	flp = slave->priv;
 
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-   {
-      if (!flp->master[i])
-         break;
-      if (abs(flp->dlci[i]) == *(short *)(master->dev_addr))
-         return(-EADDRINUSE);
-   } 
-
-   if (i == CONFIG_DLCI_MAX)
-      return(-EMLINK);  /* #### Alan: Comments on this ?? */
-
-   MOD_INC_USE_COUNT;
-
-   flp->master[i] = master;
-   flp->dlci[i] = -*(short *)(master->dev_addr);
-   master->mtu = slave->mtu;
-
-   if (slave->start)
-      if (flp->config.station == FRAD_STATION_CPE)
-         sdla_reconfig(slave);
-      else
-         sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+	{
+		if (!flp->master[i])
+			break;
+		if (abs(flp->dlci[i]) == *(short *)(master->dev_addr))
+			return(-EADDRINUSE);
+	} 
+
+	if (i == CONFIG_DLCI_MAX)
+		return(-EMLINK);  /* #### Alan: Comments on this ?? */
+
+	MOD_INC_USE_COUNT;
+
+	flp->master[i] = master;
+	flp->dlci[i] = -*(short *)(master->dev_addr);
+	master->mtu = slave->mtu;
+
+	if (slave->start)
+		if (flp->config.station == FRAD_STATION_CPE)
+			sdla_reconfig(slave);
+		else
+			sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
 
-   return(0);
+	return(0);
 }
 
 int sdla_deassoc(struct device *slave, struct device *master)
 {
-   struct frad_local *flp;
-   int               i;
+	struct frad_local *flp;
+	int               i;
 
-   flp = slave->priv;
+	flp = slave->priv;
 
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->master[i] == master)
-         break;
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->master[i] == master)
+			break;
 
-   if (i == CONFIG_DLCI_MAX)
-      return(-ENODEV);
+	if (i == CONFIG_DLCI_MAX)
+		return(-ENODEV);
 
-   flp->master[i] = NULL;
-   flp->dlci[i] = 0;
+	flp->master[i] = NULL;
+	flp->dlci[i] = 0;
 
-   MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 
-   if (slave->start)
-      if (flp->config.station == FRAD_STATION_CPE)
-         sdla_reconfig(slave);
-      else
-         sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+	if (slave->start)
+		if (flp->config.station == FRAD_STATION_CPE)
+			sdla_reconfig(slave);
+		else
+			sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
 
-   return(0);
+	return(0);
 }
 
 int sdla_dlci_conf(struct device *slave, struct device *master, int get)
 {
-   struct frad_local *flp;
-   struct dlci_local *dlp;
-   int               i;
-   short             len, ret;
-
-   flp = slave->priv;
-
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->master[i] == master)
-         break;
-
-   if (i == CONFIG_DLCI_MAX)
-      return(-ENODEV);
-
-   dlp = master->priv;
-
-   ret = SDLA_RET_OK;
-   len = sizeof(struct dlci_conf);
-   if (slave->start)
-      if (get)
-         ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
-                     NULL, 0, &dlp->config, &len);
-      else
-         ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
-                     &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
+	struct frad_local *flp;
+	struct dlci_local *dlp;
+	int               i;
+	short             len, ret;
+
+	flp = slave->priv;
+
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->master[i] == master)
+			break;
+
+	if (i == CONFIG_DLCI_MAX)
+		return(-ENODEV);
+
+	dlp = master->priv;
+
+	ret = SDLA_RET_OK;
+	len = sizeof(struct dlci_conf);
+	if (slave->start)
+		if (get)
+			ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
+			            NULL, 0, &dlp->config, &len);
+		else
+			ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
+			            &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
 
-   return(ret == SDLA_RET_OK ? 0 : -EIO);
+	return(ret == SDLA_RET_OK ? 0 : -EIO);
 }
 
 /**************************
@@ -643,656 +639,643 @@
 /* NOTE: the DLCI driver deals with freeing the SKB!! */
 static int sdla_transmit(struct sk_buff *skb, struct device *dev)
 {
-   struct frad_local *flp;
-   int               ret, addr, accept;
-   short             size;
-   unsigned long     flags;
-   struct buf_entry  *pbuf;
-
-   flp = dev->priv;
-   ret = 0;
-   accept = 1;
-
-   if (dev->tbusy) 
-      return(1);
-
-   if (skb == NULL) 
-      return(0);
-
-   if (set_bit(0, (void*)&dev->tbusy) != 0)
-      printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
-   else
-   {
-      /*
-       * stupid GateD insists on setting up the multicast router thru us
-       * and we're ill equipped to handle a non Frame Relay packet at this
-       * time!
-       */
-
-      accept = 1;
-      switch (dev->type)
-      {
-         case ARPHRD_FRAD:
-            if (skb->dev->type != ARPHRD_DLCI)
-            {
-               printk(KERN_WARNING "%s: Non DLCI device, type %i, tried to send on FRAD module.\n", dev->name, skb->dev->type);
-               accept = 0;
-            }
-            break;
-
-         default:
-            printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
-            accept = 0;
-            break;
-      }
-
-      if (accept)
-      {
-         /* this is frame specific, but till there's a PPP module, it's the default */
-         switch (flp->type)
-         {
-            case SDLA_S502A:
-            case SDLA_S502E:
-               ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
-               break;
-
-            case SDLA_S508:
-               size = sizeof(addr);
-               ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
-               if (ret == SDLA_RET_OK)
-               {
-                  save_flags(flags); 
-                  cli();
-                  SDLA_WINDOW(dev, addr);
-                  pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
-
-                  sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
-
-                  SDLA_WINDOW(dev, addr);
-                  pbuf->opp_flag = 1;
-                  restore_flags(flags);
-               }
-               break;
-         }
-
-         switch (ret)
-         {
-            case SDLA_RET_OK:
-               flp->stats.tx_packets++;
-               ret = DLCI_RET_OK;
-               break;
-
-            case SDLA_RET_CIR_OVERFLOW:
-            case SDLA_RET_BUF_OVERSIZE:
-            case SDLA_RET_NO_BUFS:
-               flp->stats.tx_dropped++;
-               ret = DLCI_RET_DROP;
-               break;
-
-            default:
-               flp->stats.tx_errors++;
-               ret = DLCI_RET_ERR;
-               break;
-         }
-      }
-      dev->tbusy = 0;
-   }
-   return(ret);
+	struct frad_local *flp;
+	int               ret, addr, accept;
+	short             size;
+	unsigned long     flags;
+	struct buf_entry  *pbuf;
+
+	flp = dev->priv;
+	ret = 0;
+	accept = 1;
+
+	if (dev->tbusy) 
+		return(1);
+
+	if (skb == NULL) 
+		return(0);
+
+	if (set_bit(0, (void*)&dev->tbusy) != 0)
+		printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
+	else
+	{
+		/*
+		 * stupid GateD insists on setting up the multicast router thru us
+		 * and we're ill equipped to handle a non Frame Relay packet at this
+		 * time!
+		 */
+
+		accept = 1;
+		switch (dev->type)
+		{
+			case ARPHRD_FRAD:
+				if (skb->dev->type != ARPHRD_DLCI)
+				{
+					printk(KERN_WARNING "%s: Non DLCI device, type %i, tried to send on FRAD module.\n", dev->name, skb->dev->type);
+					accept = 0;
+				}
+				break;
+
+			default:
+				printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
+				accept = 0;
+				break;
+		}
+
+		if (accept)
+		{
+			/* this is frame specific, but till there's a PPP module, it's the default */
+			switch (flp->type)
+			{
+				case SDLA_S502A:
+				case SDLA_S502E:
+					ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
+					break;
+
+				case SDLA_S508:
+					size = sizeof(addr);
+					ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
+					if (ret == SDLA_RET_OK)
+					{
+						save_flags(flags); 
+						cli();
+						SDLA_WINDOW(dev, addr);
+						pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
+
+						sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
+
+						SDLA_WINDOW(dev, addr);
+						pbuf->opp_flag = 1;
+						restore_flags(flags);
+					}
+					break;
+			}
+
+			switch (ret)
+			{
+				case SDLA_RET_OK:
+					flp->stats.tx_packets++;
+					ret = DLCI_RET_OK;
+					break;
+
+				case SDLA_RET_CIR_OVERFLOW:
+				case SDLA_RET_BUF_OVERSIZE:
+				case SDLA_RET_NO_BUFS:
+					flp->stats.tx_dropped++;
+					ret = DLCI_RET_DROP;
+					break;
+
+				default:
+					flp->stats.tx_errors++;
+					ret = DLCI_RET_ERR;
+					break;
+			}
+		}
+		dev->tbusy = 0;
+	}
+	return(ret);
 }
 
 static void sdla_receive(struct device *dev)
 {
-   struct device     *master;
-   struct frad_local *flp;
-   struct dlci_local *dlp;
-   struct sk_buff    *skb;
-
-   struct sdla_cmd   *cmd;
-   struct buf_info   *pbufi;
-   struct buf_entry  *pbuf;
-
-   unsigned long     flags;
-   int               i, received, success, addr, buf_base, buf_top;
-   short             dlci, len, len2, split;
-
-   flp = dev->priv;
-   success = 1;
-   received = addr = buf_top = buf_base = 0;
-   len = dlci = 0;
-   skb = NULL;
-   master = NULL;
-   cmd = NULL;
-   pbufi = NULL;
-   pbuf = NULL;
-
-   save_flags(flags);
-   cli();
-
-   switch (flp->type)
-   {
-      case SDLA_S502A:
-      case SDLA_S502E:
-         cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & SDLA_ADDR_MASK));
-         SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
-         success = cmd->opp_flag;
-         if (!success)
-            break;
-
-         dlci = cmd->dlci;
-         len = cmd->length;
-         break;
-
-      case SDLA_S508:
-         pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK));
-         SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
-         pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & SDLA_ADDR_MASK));
-         success = pbuf->opp_flag;
-         if (!success)
-            break;
-
-         buf_top = pbufi->buf_top;
-         buf_base = pbufi->buf_base;
-         dlci = pbuf->dlci;
-         len = pbuf->length;
-         addr = pbuf->buf_addr;
-         break;
-   }
-
-   /* common code, find the DLCI and get the SKB */
-   if (success)
-   {
-      for (i=0;i<CONFIG_DLCI_MAX;i++)
-         if (flp->dlci[i] == dlci)
-            break;
-
-      if (i == CONFIG_DLCI_MAX)
-      {
-         printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
-         flp->stats.rx_errors++;
-         success = 0;
-      }
-   }
-
-   if (success)
-   {
-      master = flp->master[i];
-      skb = dev_alloc_skb(len + sizeof(struct frhdr));
-      if (skb == NULL) 
-      {
-         printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-         flp->stats.rx_dropped++; 
-         success = 0;
-      }
-      else
-         skb_reserve(skb, sizeof(struct frhdr));
-   }
-
-   /* pick up the data */
-   switch (flp->type)
-   {
-      case SDLA_S502A:
-      case SDLA_S502E:
-         if (success)
-            sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len);
-
-         SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
-         cmd->opp_flag = 0;
-         break;
-
-      case SDLA_S508:
-         if (success)
-         {
-            /* is this buffer split off the end of the internal ring buffer */
-            split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0;
-            len2 = len - split;
-
-            sdla_read(dev, addr, skb_put(skb, len2), len2);
-            if (split)
-               sdla_read(dev, buf_base, skb_put(skb, split), split);
-         }
-
-         /* increment the buffer we're looking at */
-         SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
-         flp->buffer = (flp->buffer + 1) % pbufi->rse_num;
-         pbuf->opp_flag = 0;
-         break;
-   }
-
-   if (success)
-   {
-      flp->stats.rx_packets++;
-      dlp = master->priv;
-      (*dlp->receive)(skb, master);
-   }
+	struct device	  *master;
+	struct frad_local *flp;
+	struct dlci_local *dlp;
+	struct sk_buff	 *skb;
+
+	struct sdla_cmd	*cmd;
+	struct buf_info	*pbufi;
+	struct buf_entry  *pbuf;
+
+	unsigned long	  flags;
+	int               i, received, success, addr, buf_base, buf_top;
+	short             dlci, len, len2, split;
+
+	flp = dev->priv;
+	success = 1;
+	received = addr = buf_top = buf_base = 0;
+	len = dlci = 0;
+	skb = NULL;
+	master = NULL;
+	cmd = NULL;
+	pbufi = NULL;
+	pbuf = NULL;
+
+	save_flags(flags);
+	cli();
+
+	switch (flp->type)
+	{
+		case SDLA_S502A:
+		case SDLA_S502E:
+			cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & SDLA_ADDR_MASK));
+			SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
+			success = cmd->opp_flag;
+			if (!success)
+				break;
+
+			dlci = cmd->dlci;
+			len = cmd->length;
+			break;
+
+		case SDLA_S508:
+			pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK));
+			SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
+			pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & SDLA_ADDR_MASK));
+			success = pbuf->opp_flag;
+			if (!success)
+				break;
+
+			buf_top = pbufi->buf_top;
+			buf_base = pbufi->buf_base;
+			dlci = pbuf->dlci;
+			len = pbuf->length;
+			addr = pbuf->buf_addr;
+			break;
+	}
+
+	/* common code, find the DLCI and get the SKB */
+	if (success)
+	{
+		for (i=0;i<CONFIG_DLCI_MAX;i++)
+			if (flp->dlci[i] == dlci)
+				break;
+
+		if (i == CONFIG_DLCI_MAX)
+		{
+			printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
+			flp->stats.rx_errors++;
+			success = 0;
+		}
+	}
+
+	if (success)
+	{
+		master = flp->master[i];
+		skb = dev_alloc_skb(len + sizeof(struct frhdr));
+		if (skb == NULL) 
+		{
+			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+			flp->stats.rx_dropped++; 
+			success = 0;
+		}
+		else
+			skb_reserve(skb, sizeof(struct frhdr));
+	}
+
+	/* pick up the data */
+	switch (flp->type)
+	{
+		case SDLA_S502A:
+		case SDLA_S502E:
+			if (success)
+				sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len);
+
+			SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
+			cmd->opp_flag = 0;
+			break;
+
+		case SDLA_S508:
+			if (success)
+			{
+				/* is this buffer split off the end of the internal ring buffer */
+				split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0;
+				len2 = len - split;
+
+				sdla_read(dev, addr, skb_put(skb, len2), len2);
+				if (split)
+					sdla_read(dev, buf_base, skb_put(skb, split), split);
+			}
+
+			/* increment the buffer we're looking at */
+			SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
+			flp->buffer = (flp->buffer + 1) % pbufi->rse_num;
+			pbuf->opp_flag = 0;
+			break;
+	}
+
+	if (success)
+	{
+		flp->stats.rx_packets++;
+		dlp = master->priv;
+		(*dlp->receive)(skb, master);
+	}
 
-   restore_flags(flags);
+	restore_flags(flags);
 }
 
 static void sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
 {
-   struct device     *dev;
-   struct frad_local *flp;
-   char              byte;
-
-   dev = irq2dev_map[irq];
-
-   if (dev == NULL)
-   {
-      printk(KERN_WARNING "sdla_isr(): irq %d for unknown device.\n", irq);
-      return;
-   }
-
-   flp = dev->priv;
-
-   if (!flp->initialized)
-   {
-      printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq);
-      return;
-   }
-
-   dev->interrupt = 1;
-   byte = sdla_byte(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE);
-   switch (byte)
-   {
-      case SDLA_INTR_RX:
-         sdla_receive(dev);
-         break;
-
-      /* the command will get an error return, which is processed above */
-      case SDLA_INTR_MODEM:
-      case SDLA_INTR_STATUS:
-         sdla_cmd(dev, SDLA_READ_DLC_STATUS, 0, 0, NULL, 0, NULL, NULL);
-         break;
-
-      case SDLA_INTR_TX:
-      case SDLA_INTR_COMPLETE:
-      case SDLA_INTR_TIMER:
-         printk(KERN_WARNING "%s: invalid irq flag 0x%02X.\n", dev->name, byte);
-         break;
-   }
-
-   /* the S502E requires a manual acknowledgement of the interrupt */ 
-   if (flp->type == SDLA_S502E)
-   {
-      flp->state &= ~SDLA_S502E_INTACK;
-      outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-      flp->state |= SDLA_S502E_INTACK;
-      outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-   }
-
-   /* this clears the byte, informing the Z80 we're done */
-   byte = 0;
-   sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
-   dev->interrupt = 0;
+	struct device     *dev;
+	struct frad_local *flp;
+	char              byte;
+
+	dev = irq2dev_map[irq];
+
+	if (dev == NULL)
+	{
+		printk(KERN_WARNING "sdla_isr(): irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	flp = dev->priv;
+
+	if (!flp->initialized)
+	{
+		printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq);
+		return;
+	}
+
+	dev->interrupt = 1;
+	byte = sdla_byte(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE);
+	switch (byte)
+	{
+		case SDLA_INTR_RX:
+			sdla_receive(dev);
+			break;
+
+		/* the command will get an error return, which is processed above */
+		case SDLA_INTR_MODEM:
+		case SDLA_INTR_STATUS:
+			sdla_cmd(dev, SDLA_READ_DLC_STATUS, 0, 0, NULL, 0, NULL, NULL);
+			break;
+
+		case SDLA_INTR_TX:
+		case SDLA_INTR_COMPLETE:
+		case SDLA_INTR_TIMER:
+			printk(KERN_WARNING "%s: invalid irq flag 0x%02X.\n", dev->name, byte);
+			break;
+	}
+
+	/* the S502E requires a manual acknowledgement of the interrupt */ 
+	if (flp->type == SDLA_S502E)
+	{
+		flp->state &= ~SDLA_S502E_INTACK;
+		outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+		flp->state |= SDLA_S502E_INTACK;
+		outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+	}
+
+	/* this clears the byte, informing the Z80 we're done */
+	byte = 0;
+	sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
+	dev->interrupt = 0;
 }
 
 static void sdla_poll(unsigned long device)
 {
-   struct device     *dev;
-   struct frad_local *flp;
+	struct device	  *dev;
+	struct frad_local *flp;
 
-   dev = (struct device *) device;
-   flp = dev->priv;
+	dev = (struct device *) device;
+	flp = dev->priv;
 
-   if (sdla_byte(dev, SDLA_502_RCV_BUF))
-      sdla_receive(dev);
+	if (sdla_byte(dev, SDLA_502_RCV_BUF))
+		sdla_receive(dev);
 
-   flp->timer.expires = 1;
-   add_timer(&flp->timer);
+	flp->timer.expires = 1;
+	add_timer(&flp->timer);
 }
 
 static int sdla_close(struct device *dev)
 {
-   struct frad_local *flp;
-   struct intr_info  intr;
-   int               len, i;
-   short             dlcis[CONFIG_DLCI_MAX];
-
-   flp = dev->priv;
-
-   len = 0;
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->dlci[i])
-         dlcis[len++] = abs(flp->dlci[i]);
-   len *= 2;
-
-   if (flp->config.station == FRAD_STATION_NODE)
-   {
-      for(i=0;i<CONFIG_DLCI_MAX;i++)
-         if (flp->dlci[i] > 0) 
-            sdla_cmd(dev, SDLA_DEACTIVATE_DLCI, 0, 0, dlcis, len, NULL, NULL);
-      sdla_cmd(dev, SDLA_DELETE_DLCI, 0, 0, &flp->dlci[i], sizeof(flp->dlci[i]), NULL, NULL);
-   }
-
-   memset(&intr, 0, sizeof(intr));
-   /* let's start up the reception */
-   switch(flp->type)
-   {
-      case SDLA_S502A:
-         del_timer(&flp->timer); 
-         break;
-
-      case SDLA_S502E:
-         sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
-         flp->state &= ~SDLA_S502E_INTACK;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-
-      case SDLA_S507:
-         break;
-
-      case SDLA_S508:
-         sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
-         flp->state &= ~SDLA_S508_INTEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         break;
-   }
+	struct frad_local *flp;
+	struct intr_info  intr;
+	int               len, i;
+	short             dlcis[CONFIG_DLCI_MAX];
+
+	flp = dev->priv;
+
+	len = 0;
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->dlci[i])
+			dlcis[len++] = abs(flp->dlci[i]);
+	len *= 2;
+
+	if (flp->config.station == FRAD_STATION_NODE)
+	{
+		for(i=0;i<CONFIG_DLCI_MAX;i++)
+			if (flp->dlci[i] > 0) 
+				sdla_cmd(dev, SDLA_DEACTIVATE_DLCI, 0, 0, dlcis, len, NULL, NULL);
+		sdla_cmd(dev, SDLA_DELETE_DLCI, 0, 0, &flp->dlci[i], sizeof(flp->dlci[i]), NULL, NULL);
+	}
+
+	memset(&intr, 0, sizeof(intr));
+	/* let's start up the reception */
+	switch(flp->type)
+	{
+		case SDLA_S502A:
+			del_timer(&flp->timer); 
+			break;
+
+		case SDLA_S502E:
+			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
+			flp->state &= ~SDLA_S502E_INTACK;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+
+		case SDLA_S507:
+			break;
+
+		case SDLA_S508:
+			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
+			flp->state &= ~SDLA_S508_INTEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			break;
+	}
 
-   sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+	sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
 
-   dev->tbusy = 1;
-   dev->start = 0;
+	dev->tbusy = 1;
+	dev->start = 0;
 
-   MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 
-   return(0);
+	return(0);
 }
 
 struct conf_data {
-   struct frad_conf config;
-   short            dlci[CONFIG_DLCI_MAX];
+	struct frad_conf config;
+	short            dlci[CONFIG_DLCI_MAX];
 };
 
 static int sdla_open(struct device *dev)
 {
-   struct frad_local *flp;
-   struct dlci_local *dlp;
-   struct conf_data  data;
-   struct intr_info  intr;
-   int               len, i;
-   char              byte;
-
-   flp = dev->priv;
-
-   if (!flp->initialized)
-      return(-EPERM);
-
-   if (!flp->configured)
-      return(-EPERM);
-
-   /* time to send in the configuration */
-   len = 0;
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->dlci[i])
-         data.dlci[len++] = abs(flp->dlci[i]);
-   len *= 2;
-
-   memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
-   len += sizeof(struct frad_conf);
-
-   sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-   sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
-
-   if (flp->type == SDLA_S508)
-      flp->buffer = 0;
-
-   sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-
-   /* let's start up the reception */
-   memset(&intr, 0, sizeof(intr));
-   switch(flp->type)
-   {
-      case SDLA_S502A:
-         flp->timer.expires = 1;
-         add_timer(&flp->timer);
-         break;
-
-      case SDLA_S502E:
-         flp->state |= SDLA_S502E_ENABLE;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         flp->state |= SDLA_S502E_INTACK;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         byte = 0;
-         sdla_write(dev, SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
-         intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
-         sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
-         break;
-
-      case SDLA_S507:
-         break;
-
-      case SDLA_S508:
-         flp->state |= SDLA_S508_INTEN;
-         outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
-         byte = 0;
-         sdla_write(dev, SDLA_508_IRQ_INTERFACE, &byte, sizeof(byte));
-         intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
-         intr.irq = dev->irq;
-         sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
-         break;
-   }
-
-   if (flp->config.station == FRAD_STATION_CPE)
-   {
-      byte = SDLA_ICS_STATUS_ENQ;
-      sdla_cmd(dev, SDLA_ISSUE_IN_CHANNEL_SIGNAL, 0, 0, &byte, sizeof(byte), NULL, NULL);
-   }
-   else
-   {
-      sdla_cmd(dev, SDLA_ADD_DLCI, 0, 0, data.dlci, len - sizeof(struct frad_conf), NULL, NULL);
-      for(i=0;i<CONFIG_DLCI_MAX;i++)
-         if (flp->dlci[i] > 0)
-            sdla_cmd(dev, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], 2*sizeof(flp->dlci[i]), NULL, NULL);
-   }
-
-   /* configure any specific DLCI settings */
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->dlci[i])
-      {
-         dlp = flp->master[i]->priv;
-         if (dlp->configured)
-            sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL);
-      }
-
-   dev->tbusy = 0;
-   dev->interrupt = 0;
-   dev->start = 1;
+	struct frad_local *flp;
+	struct dlci_local *dlp;
+	struct conf_data  data;
+	struct intr_info  intr;
+	int               len, i;
+	char              byte;
+
+	flp = dev->priv;
+
+	if (!flp->initialized)
+		return(-EPERM);
+
+	if (!flp->configured)
+		return(-EPERM);
+
+	/* time to send in the configuration */
+	len = 0;
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->dlci[i])
+			data.dlci[len++] = abs(flp->dlci[i]);
+	len *= 2;
+
+	memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
+	len += sizeof(struct frad_conf);
+
+	sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+	sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
+
+	if (flp->type == SDLA_S508)
+		flp->buffer = 0;
+
+	sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+
+	/* let's start up the reception */
+	memset(&intr, 0, sizeof(intr));
+	switch(flp->type)
+	{
+		case SDLA_S502A:
+			flp->timer.expires = 1;
+			add_timer(&flp->timer);
+			break;
+
+		case SDLA_S502E:
+			flp->state |= SDLA_S502E_ENABLE;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			flp->state |= SDLA_S502E_INTACK;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			byte = 0;
+			sdla_write(dev, SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
+			intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
+			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
+			break;
+
+		case SDLA_S507:
+			break;
+
+		case SDLA_S508:
+			flp->state |= SDLA_S508_INTEN;
+			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+			byte = 0;
+			sdla_write(dev, SDLA_508_IRQ_INTERFACE, &byte, sizeof(byte));
+			intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
+			intr.irq = dev->irq;
+			sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
+			break;
+	}
+
+	if (flp->config.station == FRAD_STATION_CPE)
+	{
+		byte = SDLA_ICS_STATUS_ENQ;
+		sdla_cmd(dev, SDLA_ISSUE_IN_CHANNEL_SIGNAL, 0, 0, &byte, sizeof(byte), NULL, NULL);
+	}
+	else
+	{
+		sdla_cmd(dev, SDLA_ADD_DLCI, 0, 0, data.dlci, len - sizeof(struct frad_conf), NULL, NULL);
+		for(i=0;i<CONFIG_DLCI_MAX;i++)
+			if (flp->dlci[i] > 0)
+				sdla_cmd(dev, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], 2*sizeof(flp->dlci[i]), NULL, NULL);
+	}
+
+	/* configure any specific DLCI settings */
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->dlci[i])
+		{
+			dlp = flp->master[i]->priv;
+			if (dlp->configured)
+				sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL);
+		}
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
 
-   MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 
-   return(0);
+	return(0);
 }
 
 static int sdla_config(struct device *dev, struct frad_conf *conf, int get)
 {
-   struct frad_local *flp;
-   struct conf_data  data;
-   int               i, err;
-   short             size;
-
-   if (dev->type == 0xFFFF)
-      return(-EUNATCH);
-
-   flp = dev->priv;
-
-   if (!get)
-   {
-      if (dev->start)
-         return(-EBUSY);
-
-      err = verify_area(VERIFY_READ, conf, sizeof(struct frad_conf));
-      if (err)
-         return(err);
-
-      copy_from_user(&data.config, conf, sizeof(struct frad_conf));
-
-      if (data.config.station & ~FRAD_STATION_NODE)
-         return(-EINVAL);
-
-      if (data.config.flags & ~FRAD_VALID_FLAGS)
-         return(-EINVAL);
-
-      if ((data.config.kbaud < 0) || 
-          ((data.config.kbaud > 128) && (flp->type != SDLA_S508)))
-         return(-EINVAL);
-
-      if (data.config.clocking & ~(FRAD_CLOCK_INT | SDLA_S508_PORT_RS232))
-         return(-EINVAL);
-
-      if ((data.config.mtu < 0) || (data.config.mtu > SDLA_MAX_MTU))
-         return(-EINVAL);
-
-      if ((data.config.T391 < 5) || (data.config.T391 > 30))
-         return(-EINVAL);
-
-      if ((data.config.T392 < 5) || (data.config.T392 > 30))
-         return(-EINVAL);
-
-      if ((data.config.N391 < 1) || (data.config.N391 > 255))
-         return(-EINVAL);
-
-      if ((data.config.N392 < 1) || (data.config.N392 > 10))
-         return(-EINVAL);
-
-      if ((data.config.N393 < 1) || (data.config.N393 > 10))
-         return(-EINVAL);
-
-      memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
-      flp->config.flags |= SDLA_DIRECT_RECV;
-
-      if (flp->type == SDLA_S508)
-         flp->config.flags |= SDLA_TX70_RX30;
-
-      if (dev->mtu != flp->config.mtu)
-      {
-         /* this is required to change the MTU */
-         dev->mtu = flp->config.mtu;
-         for(i=0;i<CONFIG_DLCI_MAX;i++)
-            if (flp->master[i])
-               flp->master[i]->mtu = flp->config.mtu;
-      }
-
-      flp->config.mtu += sizeof(struct frhdr);
-
-      /* off to the races! */
-      if (!flp->configured)
-         sdla_start(dev);
-
-      flp->configured = 1;
-   }
-   else
-   {
-      err = verify_area(VERIFY_WRITE, conf, sizeof(struct frad_conf));
-      if (err)
-         return(err);
-
-      /* no sense reading if the CPU isn't started */
-      if (dev->start)
-      {
-         size = sizeof(data);
-         if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
-            return(-EIO);
-      }
-      else
-         if (flp->configured)
-            memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
-         else
-            memset(&data.config, 0, sizeof(struct frad_conf));
-
-      memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
-      data.config.flags &= FRAD_VALID_FLAGS;
-      data.config.mtu -= data.config.mtu > sizeof(struct frhdr) ? sizeof(struct frhdr) : data.config.mtu;
-      copy_to_user(conf, &data.config, sizeof(struct frad_conf));
-   }
+	struct frad_local *flp;
+	struct conf_data  data;
+	int               i, err;
+	short             size;
+
+	if (dev->type == 0xFFFF)
+		return(-EUNATCH);
+
+	flp = dev->priv;
+
+	if (!get)
+	{
+		if (dev->start)
+			return(-EBUSY);
+
+		if(copy_from_user(&data.config, conf, sizeof(struct frad_conf)))
+			return -EFAULT;
+
+		if (data.config.station & ~FRAD_STATION_NODE)
+			return(-EINVAL);
+
+		if (data.config.flags & ~FRAD_VALID_FLAGS)
+			return(-EINVAL);
+
+		if ((data.config.kbaud < 0) || 
+			 ((data.config.kbaud > 128) && (flp->type != SDLA_S508)))
+			return(-EINVAL);
+
+		if (data.config.clocking & ~(FRAD_CLOCK_INT | SDLA_S508_PORT_RS232))
+			return(-EINVAL);
+
+		if ((data.config.mtu < 0) || (data.config.mtu > SDLA_MAX_MTU))
+			return(-EINVAL);
+
+		if ((data.config.T391 < 5) || (data.config.T391 > 30))
+			return(-EINVAL);
+
+		if ((data.config.T392 < 5) || (data.config.T392 > 30))
+			return(-EINVAL);
+
+		if ((data.config.N391 < 1) || (data.config.N391 > 255))
+			return(-EINVAL);
+
+		if ((data.config.N392 < 1) || (data.config.N392 > 10))
+			return(-EINVAL);
+
+		if ((data.config.N393 < 1) || (data.config.N393 > 10))
+			return(-EINVAL);
+
+		memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
+		flp->config.flags |= SDLA_DIRECT_RECV;
+
+		if (flp->type == SDLA_S508)
+			flp->config.flags |= SDLA_TX70_RX30;
+
+		if (dev->mtu != flp->config.mtu)
+		{
+			/* this is required to change the MTU */
+			dev->mtu = flp->config.mtu;
+			for(i=0;i<CONFIG_DLCI_MAX;i++)
+				if (flp->master[i])
+					flp->master[i]->mtu = flp->config.mtu;
+		}
+
+		flp->config.mtu += sizeof(struct frhdr);
+
+		/* off to the races! */
+		if (!flp->configured)
+			sdla_start(dev);
+
+		flp->configured = 1;
+	}
+	else
+	{
+		/* no sense reading if the CPU isn't started */
+		if (dev->start)
+		{
+			size = sizeof(data);
+			if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
+				return(-EIO);
+		}
+		else
+			if (flp->configured)
+				memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
+			else
+				memset(&data.config, 0, sizeof(struct frad_conf));
+
+		memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
+		data.config.flags &= FRAD_VALID_FLAGS;
+		data.config.mtu -= data.config.mtu > sizeof(struct frhdr) ? sizeof(struct frhdr) : data.config.mtu;
+		return copy_to_user(conf, &data.config, sizeof(struct frad_conf))?-EFAULT:0;
+	}
 
-   return(0);
+	return(0);
 }
 
 static int sdla_xfer(struct device *dev, struct sdla_mem *info, int read)
 {
-   struct sdla_mem mem;
-   int    err;
-   char   *temp;
-
-   err = verify_area(VERIFY_READ, info, sizeof(struct sdla_mem));
-   if (err)
-      return(err);
-
-   copy_from_user(&mem, info, sizeof(mem));
-   if (read)
-   {
-      err = verify_area(VERIFY_WRITE, mem.data, mem.len);
-      if (err)
-         return(err);
-
-      temp = kmalloc(mem.len, GFP_KERNEL);
-      if (!temp)
-         return(-ENOMEM);
-      sdla_read(dev, mem.addr, temp, mem.len);
-      copy_to_user(mem.data, temp, mem.len);
-      kfree(temp);
-   }
-   else
-   {
-      err = verify_area(VERIFY_READ, mem.data, mem.len);
-      if (err)
-         return(err);
-
-      temp = kmalloc(mem.len, GFP_KERNEL);
-      if (!temp)
-         return(-ENOMEM);
-      copy_from_user(temp, mem.data, mem.len);
-      sdla_write(dev, mem.addr, temp, mem.len);
-      kfree(temp);
-   }
-   return(0);
+	struct sdla_mem mem;
+	char	*temp;
+
+	if(copy_from_user(&mem, info, sizeof(mem)))
+		return -EFAULT;
+		
+	if (read)
+	{	
+		temp = kmalloc(mem.len, GFP_KERNEL);
+		if (!temp)
+			return(-ENOMEM);
+		sdla_read(dev, mem.addr, temp, mem.len);
+		if(copy_to_user(mem.data, temp, mem.len))
+			return -EFAULT;
+		kfree(temp);
+	}
+	else
+	{
+		temp = kmalloc(mem.len, GFP_KERNEL);
+		if (!temp)
+			return(-ENOMEM);
+		if(copy_from_user(temp, mem.data, mem.len))
+			return -EFAULT;
+		sdla_write(dev, mem.addr, temp, mem.len);
+		kfree(temp);
+	}
+	return(0);
 }
 
 static int sdla_reconfig(struct device *dev)
 {
-   struct frad_local *flp;
-   struct conf_data  data;
-   int               i, len;
-
-   flp = dev->priv;
-
-   len = 0;
-   for(i=0;i<CONFIG_DLCI_MAX;i++)
-      if (flp->dlci[i])
-         data.dlci[len++] = flp->dlci[i];
-   len *= 2;
-
-   memcpy(&data, &flp->config, sizeof(struct frad_conf));
-   len += sizeof(struct frad_conf);
-
-   sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-   sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
-   sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+	struct frad_local *flp;
+	struct conf_data  data;
+	int               i, len;
+
+	flp = dev->priv;
+
+	len = 0;
+	for(i=0;i<CONFIG_DLCI_MAX;i++)
+		if (flp->dlci[i])
+			data.dlci[len++] = flp->dlci[i];
+	len *= 2;
+
+	memcpy(&data, &flp->config, sizeof(struct frad_conf));
+	len += sizeof(struct frad_conf);
+
+	sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
+	sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
+	sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
 
-   return(0);
+	return(0);
 }
 
 static int sdla_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
 {
-   struct frad_local *flp;
+	struct frad_local *flp;
 
-   flp = dev->priv;
+	if(!suser())
+		return -EPERM;
+		
+	flp = dev->priv;
+
+	if (!flp->initialized)
+		return(-EINVAL);
+
+	switch (cmd)
+	{
+		case FRAD_GET_CONF:
+		case FRAD_SET_CONF:
+			return(sdla_config(dev, (struct frad_conf *)ifr->ifr_data, cmd == FRAD_GET_CONF));
+
+		case SDLA_IDENTIFY:
+			ifr->ifr_flags = flp->type;
+			break;
 
-   if (!flp->initialized)
-      return(-EPERM);
-
-   switch (cmd)
-   {
-      case FRAD_GET_CONF:
-      case FRAD_SET_CONF:
-         return(sdla_config(dev, (struct frad_conf *)ifr->ifr_data, cmd == FRAD_GET_CONF));
-
-      case SDLA_IDENTIFY:
-         ifr->ifr_flags = flp->type;
-         break;
-
-      case SDLA_CPUSPEED:
-         return(sdla_cpuspeed(dev, ifr)); 
+		case SDLA_CPUSPEED:
+			return(sdla_cpuspeed(dev, ifr)); 
 
 /* ==========================================================
 NOTE:  This is rather a useless action right now, as the
@@ -1300,391 +1283,396 @@
        FR.  However, Sangoma has modules for a number of
        other protocols in the works.
 ============================================================*/
-      case SDLA_PROTOCOL:
-         if (flp->configured)
-            return(-EALREADY);
-
-         switch (ifr->ifr_flags)
-         {
-            case ARPHRD_FRAD:
-               dev->type = ifr->ifr_flags;
-               dev->family = AF_UNSPEC;
-               break;
-
-            default:
-               return(-ENOPROTOOPT);
-         }
-         break;
-
-      case SDLA_CLEARMEM:
-         sdla_clear(dev);
-         break;
-
-      case SDLA_WRITEMEM:
-      case SDLA_READMEM:
-         return(sdla_xfer(dev, (struct sdla_mem *)ifr->ifr_data, cmd == SDLA_READMEM));
-
-      case SDLA_START:
-         sdla_start(dev);
-         break;
-
-      case SDLA_STOP:
-         sdla_stop(dev);
-         break;
-
-      default:
-         return(-EOPNOTSUPP);
-   }
-   return(0);
+		case SDLA_PROTOCOL:
+			if (flp->configured)
+				return(-EALREADY);
+
+			switch (ifr->ifr_flags)
+			{
+				case ARPHRD_FRAD:
+					dev->type = ifr->ifr_flags;
+					dev->family = AF_UNSPEC;
+					break;
+				default:
+					return(-ENOPROTOOPT);
+			}
+			break;
+
+		case SDLA_CLEARMEM:
+			sdla_clear(dev);
+			break;
+
+		case SDLA_WRITEMEM:
+		case SDLA_READMEM:
+			return(sdla_xfer(dev, (struct sdla_mem *)ifr->ifr_data, cmd == SDLA_READMEM));
+
+		case SDLA_START:
+			sdla_start(dev);
+			break;
+
+		case SDLA_STOP:
+			sdla_stop(dev);
+			break;
+
+		default:
+			return(-EOPNOTSUPP);
+	}
+	return(0);
 }
 
 int sdla_change_mtu(struct device *dev, int new_mtu)
 {
-   struct frad_local *flp;
+	struct frad_local *flp;
 
-   flp = dev->priv;
+	flp = dev->priv;
 
-   if (dev->start)
-      return(-EBUSY);
+	if (dev->start)
+		return(-EBUSY);
 
-   /* for now, you can't change the MTU! */
-   return(-EACCES);
+	/* for now, you can't change the MTU! */
+	return(-EOPNOTSUPP);
 }
 
 int sdla_set_config(struct device *dev, struct ifmap *map)
 {
-   struct frad_local *flp;
-   int               i;
-   char              byte;
+	struct frad_local *flp;
+	int               i;
+	char              byte;
 
-   flp = dev->priv;
+	flp = dev->priv;
 
-   if (flp->initialized)
-      return(-EINVAL);
+	if (flp->initialized)
+		return(-EINVAL);
 
-   for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++)
-      if (valid_port[i] == map->base_addr)
-         break;   
+	for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++)
+		if (valid_port[i] == map->base_addr)
+			break;   
 
-   if (i == sizeof(valid_port) / sizeof(int))
-      return(-EINVAL);
+	if (i == sizeof(valid_port) / sizeof(int))
+		return(-EINVAL);
 
-   dev->base_addr = map->base_addr;
-   request_region(dev->base_addr, SDLA_IO_EXTENTS, dev->name);
+	dev->base_addr = map->base_addr;
+	request_region(dev->base_addr, SDLA_IO_EXTENTS, dev->name);
 
-   /* test for card types, S502A, S502E, S507, S508                 */
-   /* these tests shut down the card completely, so clear the state */
-   flp->type = SDLA_UNKNOWN;
-   flp->state = 0;
+	/* test for card types, S502A, S502E, S507, S508                 */
+	/* these tests shut down the card completely, so clear the state */
+	flp->type = SDLA_UNKNOWN;
+	flp->state = 0;
    
-   for(i=1;i<SDLA_IO_EXTENTS;i++)
-      if (inb(dev->base_addr + i) != 0xFF)
-        break;
-
-   if (i == SDLA_IO_EXTENTS)
-   {   
-      outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
-      if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x08)
-      {
-         outb(SDLA_S502E_INTACK, dev->base_addr + SDLA_REG_CONTROL);
-         if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x0C)
-         {
-            outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-            flp->type = SDLA_S502E;
-         }
-      }
-   }
-
-   if (flp->type == SDLA_UNKNOWN)
-   {
-      for(byte=inb(dev->base_addr),i=0;i<SDLA_IO_EXTENTS;i++)
-         if (inb(dev->base_addr + i) != byte)
-            break;
-
-      if (i == SDLA_IO_EXTENTS)
-      {
-         outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-         if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x30)
-         {
-            outb(SDLA_S507_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
-            if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x32)
-            {
-               outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-               flp->type = SDLA_S507;
-            }
-         }
-      }
-   }
-
-   if (flp->type == SDLA_UNKNOWN)
-   {
-      outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-      if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x00)
-      {
-         outb(SDLA_S508_INTEN, dev->base_addr + SDLA_REG_CONTROL);
-         if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x10)
-         {
-            outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-            flp->type = SDLA_S508;
-         }
-      }
-   }
-
-   if (flp->type == SDLA_UNKNOWN)
-   {
-      outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
-      if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
-      {
-         outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
-         if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
-         {
-            outb(SDLA_S502A_INTEN, dev->base_addr + SDLA_REG_CONTROL);
-            if (inb(dev->base_addr + SDLA_S502_STS) == 0x44)
-            {
-               outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
-               flp->type = SDLA_S502A;
-            }
-         }
-      }
-   }
-
-   if (flp->type == SDLA_UNKNOWN)
-   {
-      printk(KERN_NOTICE "%s: Unknown card type\n", dev->name);
-      return(-ENODEV);
-   }
-
-   switch(dev->base_addr)
-   {
-      case 0x270:
-      case 0x280:
-      case 0x380: 
-      case 0x390:
-         if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
-            return(-EINVAL);
-   }
-
-   switch (map->irq)
-   {
-      case 2:
-         if (flp->type != SDLA_S502E)
-            return(-EINVAL);
-         break;
-
-      case 10:
-      case 11:
-      case 12:
-      case 15:
-      case 4:
-         if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
-            return(-EINVAL);
-
-      case 3:
-      case 5:
-      case 7:
-         if (flp->type == SDLA_S502A)
-            return(-EINVAL);
-         break;
-
-      default:
-         return(-EINVAL);
-   }
-   dev->irq = map->irq;
-
-   if (request_irq(dev->irq, &sdla_isr, 0, dev->name, NULL)) 
-      return(-EADDRINUSE);
-
-   irq2dev_map[dev->irq] = dev;
-
-   if (flp->type == SDLA_S507)
-   {
-      switch(dev->irq)
-      {
-         case 3:
-            flp->state = SDLA_S507_IRQ3;
-            break;
-         case 4:
-            flp->state = SDLA_S507_IRQ4;
-            break;
-         case 5:
-            flp->state = SDLA_S507_IRQ5;
-            break;
-         case 7:
-            flp->state = SDLA_S507_IRQ7;
-            break;
-         case 10:
-            flp->state = SDLA_S507_IRQ10;
-            break;
-         case 11:
-            flp->state = SDLA_S507_IRQ11;
-            break;
-         case 12:
-            flp->state = SDLA_S507_IRQ12;
-            break;
-         case 15:
-            flp->state = SDLA_S507_IRQ15;
-            break;
-      }
-   }
-
-   for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++)
-      if (valid_mem[i] == map->mem_start)
-         break;   
-
-   if (i == sizeof(valid_mem) / sizeof(int))
-      return(-EINVAL);
-
-   if ((flp->type == SDLA_S502A) && (((map->mem_start & 0xF000) >> 12) == 0x0E))
-      return(-EINVAL);
-
-   if ((flp->type != SDLA_S507) && ((map->mem_start >> 16) == 0x0B))
-      return(-EINVAL);
-
-   if ((flp->type == SDLA_S507) && ((map->mem_start >> 16) == 0x0D))
-      return(-EINVAL);
-
-   dev->mem_start = map->mem_start;
-   dev->mem_end = dev->mem_start + 0x2000;
-
-   byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0;
-   byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0));
-   switch(flp->type)
-   {
-      case SDLA_S502A:
-      case SDLA_S502E:
-         switch (map->mem_start >> 16)
-         {
-            case 0x0A:
-               byte |= SDLA_S502_SEG_A;
-               break;
-            case 0x0C:
-               byte |= SDLA_S502_SEG_C;
-               break;
-            case 0x0D:
-               byte |= SDLA_S502_SEG_D;
-               break;
-            case 0x0E:
-               byte |= SDLA_S502_SEG_E;
-               break;
-         }
-         break;
-      case SDLA_S507:
-         switch (map->mem_start >> 16)
-         {
-            case 0x0A:
-               byte |= SDLA_S507_SEG_A;
-               break;
-            case 0x0B:
-               byte |= SDLA_S507_SEG_B;
-               break;
-            case 0x0C:
-               byte |= SDLA_S507_SEG_C;
-               break;
-            case 0x0E:
-               byte |= SDLA_S507_SEG_E;
-               break;
-         }
-         break;
-      case SDLA_S508:
-         switch (map->mem_start >> 16)
-         {
-            case 0x0A:
-               byte |= SDLA_S508_SEG_A;
-               break;
-            case 0x0C:
-               byte |= SDLA_S508_SEG_C;
-               break;
-            case 0x0D:
-               byte |= SDLA_S508_SEG_D;
-               break;
-            case 0x0E:
-               byte |= SDLA_S508_SEG_E;
-               break;
-         }
-         break;
-   }
-
-   /* set the memory bits, and enable access */
-   outb(byte, dev->base_addr + SDLA_REG_PC_WINDOW);
-   switch(flp->type)
-   {
-      case SDLA_S502E:
-         flp->state = SDLA_S502E_ENABLE;
-         break;
-      case SDLA_S507:
-         flp->state |= SDLA_MEMEN;
-         break;
-      case SDLA_S508:
-         flp->state = SDLA_MEMEN;
-         break;
-   }
-   outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+	for(i=1;i<SDLA_IO_EXTENTS;i++)
+		if (inb(dev->base_addr + i) != 0xFF)
+			break;
+
+	if (i == SDLA_IO_EXTENTS)
+	{   
+		outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
+		if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x08)
+		{
+			outb(SDLA_S502E_INTACK, dev->base_addr + SDLA_REG_CONTROL);
+			if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x0C)
+			{
+				outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+				flp->type = SDLA_S502E;
+			}
+		}
+	}
+
+	if (flp->type == SDLA_UNKNOWN)
+	{
+		for(byte=inb(dev->base_addr),i=0;i<SDLA_IO_EXTENTS;i++)
+			if (inb(dev->base_addr + i) != byte)
+				break;
+
+		if (i == SDLA_IO_EXTENTS)
+		{
+			outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+			if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x30)
+			{
+				outb(SDLA_S507_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
+				if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x32)
+				{
+					outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+					flp->type = SDLA_S507;
+				}
+			}
+		}
+	}
+
+	if (flp->type == SDLA_UNKNOWN)
+	{
+		outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+		if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x00)
+		{
+			outb(SDLA_S508_INTEN, dev->base_addr + SDLA_REG_CONTROL);
+			if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x10)
+			{
+				outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+				flp->type = SDLA_S508;
+			}
+		}
+	}
+
+	if (flp->type == SDLA_UNKNOWN)
+	{
+		outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
+		if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
+		{
+			outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
+			if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
+			{
+				outb(SDLA_S502A_INTEN, dev->base_addr + SDLA_REG_CONTROL);
+				if (inb(dev->base_addr + SDLA_S502_STS) == 0x44)
+				{
+					outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
+					flp->type = SDLA_S502A;
+				}
+			}
+		}
+	}
+
+	if (flp->type == SDLA_UNKNOWN)
+	{
+		printk(KERN_NOTICE "%s: Unknown card type\n", dev->name);
+		return(-ENODEV);
+	}
+
+	switch(dev->base_addr)
+	{
+		case 0x270:
+		case 0x280:
+		case 0x380: 
+		case 0x390:
+			if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
+				return(-EINVAL);
+	}
+
+	switch (map->irq)
+	{
+		case 2:
+			if (flp->type != SDLA_S502E)
+				return(-EINVAL);
+			break;
+
+		case 10:
+		case 11:
+		case 12:
+		case 15:
+		case 4:
+			if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
+				return(-EINVAL);
+
+		case 3:
+		case 5:
+		case 7:
+			if (flp->type == SDLA_S502A)
+				return(-EINVAL);
+			break;
+
+		default:
+			return(-EINVAL);
+	}
+	dev->irq = map->irq;
+
+	if (request_irq(dev->irq, &sdla_isr, 0, dev->name, NULL)) 
+		return(-EAGAIN);
+
+	irq2dev_map[dev->irq] = dev;
+
+	if (flp->type == SDLA_S507)
+	{
+		switch(dev->irq)
+		{
+			case 3:
+				flp->state = SDLA_S507_IRQ3;
+				break;
+			case 4:
+				flp->state = SDLA_S507_IRQ4;
+				break;
+			case 5:
+				flp->state = SDLA_S507_IRQ5;
+				break;
+			case 7:
+				flp->state = SDLA_S507_IRQ7;
+				break;
+			case 10:
+				flp->state = SDLA_S507_IRQ10;
+				break;
+			case 11:
+				flp->state = SDLA_S507_IRQ11;
+				break;
+			case 12:
+				flp->state = SDLA_S507_IRQ12;
+				break;
+			case 15:
+				flp->state = SDLA_S507_IRQ15;
+				break;
+		}
+	}
+
+	for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++)
+		if (valid_mem[i] == map->mem_start)
+			break;   
+
+	if (i == sizeof(valid_mem) / sizeof(int))
+	/*
+	 *	FIXME:
+	 *	BUG BUG BUG: MUST RELEASE THE IRQ WE ALLOCATED IN
+	 *	ALL THESE CASES
+	 *
+	 */
+		return(-EINVAL);
+
+	if ((flp->type == SDLA_S502A) && (((map->mem_start & 0xF000) >> 12) == 0x0E))
+		return(-EINVAL);
+
+	if ((flp->type != SDLA_S507) && ((map->mem_start >> 16) == 0x0B))
+		return(-EINVAL);
+
+	if ((flp->type == SDLA_S507) && ((map->mem_start >> 16) == 0x0D))
+		return(-EINVAL);
+
+	dev->mem_start = map->mem_start;
+	dev->mem_end = dev->mem_start + 0x2000;
+
+	byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0;
+	byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0));
+	switch(flp->type)
+	{
+		case SDLA_S502A:
+		case SDLA_S502E:
+			switch (map->mem_start >> 16)
+			{
+				case 0x0A:
+					byte |= SDLA_S502_SEG_A;
+					break;
+				case 0x0C:
+					byte |= SDLA_S502_SEG_C;
+					break;
+				case 0x0D:
+					byte |= SDLA_S502_SEG_D;
+					break;
+				case 0x0E:
+					byte |= SDLA_S502_SEG_E;
+					break;
+			}
+			break;
+		case SDLA_S507:
+			switch (map->mem_start >> 16)
+			{
+				case 0x0A:
+					byte |= SDLA_S507_SEG_A;
+					break;
+				case 0x0B:
+					byte |= SDLA_S507_SEG_B;
+					break;
+				case 0x0C:
+					byte |= SDLA_S507_SEG_C;
+					break;
+				case 0x0E:
+					byte |= SDLA_S507_SEG_E;
+					break;
+			}
+			break;
+		case SDLA_S508:
+			switch (map->mem_start >> 16)
+			{
+				case 0x0A:
+					byte |= SDLA_S508_SEG_A;
+					break;
+				case 0x0C:
+					byte |= SDLA_S508_SEG_C;
+					break;
+				case 0x0D:
+					byte |= SDLA_S508_SEG_D;
+					break;
+				case 0x0E:
+					byte |= SDLA_S508_SEG_E;
+					break;
+			}
+			break;
+	}
+
+	/* set the memory bits, and enable access */
+	outb(byte, dev->base_addr + SDLA_REG_PC_WINDOW);
+
+	switch(flp->type)
+	{
+		case SDLA_S502E:
+			flp->state = SDLA_S502E_ENABLE;
+			break;
+		case SDLA_S507:
+			flp->state |= SDLA_MEMEN;
+			break;
+		case SDLA_S508:
+			flp->state = SDLA_MEMEN;
+			break;
+	}
+	outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
 
-   flp->initialized = 1;
-   return(0);
+	flp->initialized = 1;
+	return(0);
 }
  
-static struct enet_statistics *sdla_stats(struct device *dev)
+static struct net_device_stats *sdla_stats(struct device *dev)
 {
-   struct frad_local *flp;
+	struct frad_local *flp;
+	flp = dev->priv;
 
-   flp = dev->priv;
-
-   return(&flp->stats);
+	return(&flp->stats);
 }
 
 int sdla_init(struct device *dev)
 {
-   struct frad_local *flp;
+	struct frad_local *flp;
 
-   /* allocate the private data structure */
-   flp = kmalloc(sizeof(struct frad_local), GFP_KERNEL);
-   if (!flp)
-      return(-ENOMEM);
-
-   memset(flp, 0, sizeof(struct frad_local));
-   dev->priv = flp;
-
-   dev->flags           = 0;
-   dev->open            = sdla_open;
-   dev->stop            = sdla_close;
-   dev->do_ioctl        = sdla_ioctl;
-   dev->set_config      = sdla_set_config;
-   dev->get_stats       = sdla_stats;
-   dev->hard_start_xmit = sdla_transmit;
-   dev->change_mtu	= sdla_change_mtu;
-
-   dev->type            = 0xFFFF;
-   dev->family          = AF_UNSPEC;
-   dev->pa_alen         = 0;
-   dev->pa_addr         = 0;
-   dev->pa_dstaddr      = 0;
-   dev->pa_brdaddr      = 0;
-   dev->pa_mask         = 0;
-   dev->hard_header_len = 0;
-   dev->addr_len        = 0;
-   dev->mtu             = SDLA_MAX_MTU;
+	/* allocate the private data structure */
+	flp = kmalloc(sizeof(struct frad_local), GFP_KERNEL);
+	if (!flp)
+		return(-ENOMEM);
+
+	memset(flp, 0, sizeof(struct frad_local));
+	dev->priv = flp;
+
+	dev->flags		= 0;
+	dev->open		= sdla_open;
+	dev->stop		= sdla_close;
+	dev->do_ioctl		= sdla_ioctl;
+	dev->set_config		= sdla_set_config;
+	dev->get_stats		= sdla_stats;
+	dev->hard_start_xmit	= sdla_transmit;
+	dev->change_mtu		= sdla_change_mtu;
+
+	dev->type		= 0xFFFF;
+	dev->family		= AF_UNSPEC;
+	dev->pa_alen		= 0;
+	dev->pa_addr		= 0;
+	dev->pa_dstaddr 	= 0;
+	dev->pa_brdaddr		= 0;
+	dev->pa_mask		= 0;
+	dev->hard_header_len = 0;
+	dev->addr_len		= 0;
+	dev->mtu		= SDLA_MAX_MTU;
 
-   dev_init_buffers(dev);
+	dev_init_buffers(dev);
    
-   flp->activate        = sdla_activate;
-   flp->deactivate      = sdla_deactivate;
-   flp->assoc           = sdla_assoc;
-   flp->deassoc         = sdla_deassoc;
-   flp->dlci_conf       = sdla_dlci_conf;
-
-   init_timer(&flp->timer);
-   flp->timer.expires   = 1;
-   flp->timer.data      = (unsigned long) dev;
-   flp->timer.function  = sdla_poll;
+	flp->activate		= sdla_activate;
+	flp->deactivate		= sdla_deactivate;
+	flp->assoc		= sdla_assoc;
+	flp->deassoc		= sdla_deassoc;
+	flp->dlci_conf		= sdla_dlci_conf;
+
+	init_timer(&flp->timer);
+	flp->timer.expires	= 1;
+	flp->timer.data		= (unsigned long) dev;
+	flp->timer.function	= sdla_poll;
 
-   return(0);
+	return(0);
 }
 
 void sdla_setup(void)
 {
-   printk("%s.\n", version);
-   register_frad(devname);
+	printk("%s.\n", version);
+	register_frad(devname);
 }
 
 #ifdef MODULE
@@ -1692,21 +1680,20 @@
 
 int init_module(void)
 {
-   int result;
-
-   sdla_setup();
-   if ((result = register_netdev(&sdla0)) != 0)
-      return result;
+	int result;
 
-   return 0;
+	sdla_setup();
+	if ((result = register_netdev(&sdla0)) != 0)
+		return result;
+	return 0;
 }
 
 void cleanup_module(void)
 {
-   unregister_netdev(&sdla0);
-   if (sdla0.priv)
-      kfree(sdla0.priv);
-   if (sdla0.irq)
-      free_irq(sdla0.irq, NULL);
+	unregister_netdev(&sdla0);
+	if (sdla0.priv)
+		kfree(sdla0.priv);
+	if (sdla0.irq)
+		free_irq(sdla0.irq, NULL);
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c
--- v2.1.24/linux/drivers/net/sdla_fr.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/sdla_fr.c	Sun Feb  2 16:42:57 1997
@@ -0,0 +1,1428 @@
+/*****************************************************************************
+* sdla_fr.c	WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Jan 02, 1997	Gene Kozin	Initial version.
+*****************************************************************************/
+
+#if	!defined(__KERNEL__) || !defined(MODULE)
+#error	This code MUST be compiled as a kernel module!
+#endif
+
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/router.h>	/* WAN router definitions */
+#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
+#include <linux/if_arp.h>	/* ARPHRD_* defines */
+#include <asm/byteorder.h>	/* htons(), etc. */
+#include <asm/io.h>		/* for inb(), outb(), etc. */
+
+#define	_GNUC_
+#include <linux/sdla_fr.h>	/* frame relay firmware API definitions */
+
+/****** Defines & Macros ****************************************************/
+
+#define	CMD_OK		0		/* normal firmware return code */
+#define	CMD_TIMEOUT	0xFF		/* firmware command timed out */
+#define	MAX_CMD_RETRY	10		/* max number of firmware retries */
+
+#define	FR_HEADER_LEN	8		/* max encapsulation header size */
+#define	FR_CHANNEL_MTU	1500		/* unfragmented logical channel MTU */
+
+/* Q.922 frame types */
+#define	Q922_UI		0x03		/* Unnumbered Info frame */
+#define	Q922_XID	0xAF		/* ??? */
+
+/****** Data Structures *****************************************************/
+
+/* This is an extention of the 'struct device' we create for each network
+ * interface to keep the rest of channel-specific data.
+ */
+typedef struct fr_channel
+{
+	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
+	unsigned dlci;			/* logical channel number */
+	unsigned cir;			/* committed information rate */
+	char state;			/* channel state */
+	unsigned long state_tick;	/* time of the last state change */
+	sdla_t* card;			/* -> owner */
+	struct enet_statistics ifstats;	/* interface statistics */
+} fr_channel_t;
+
+typedef struct dlci_status
+{
+	unsigned short dlci	PACKED;
+	unsigned char state	PACKED;
+} dlci_status_t;
+
+/****** Function Prototypes *************************************************/
+
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int update (wan_device_t* wandev);
+static int new_if (wan_device_t* wandev, struct device* dev,
+	wanif_conf_t* conf);
+static int del_if (wan_device_t* wandev, struct device* dev);
+
+/* Network device interface */
+static int if_init   (struct device* dev);
+static int if_open   (struct device* dev);
+static int if_close  (struct device* dev);
+static int if_header (struct sk_buff* skb, struct device* dev,
+	unsigned short type, void* daddr, void* saddr, unsigned len);
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+	struct sk_buff* skb);
+static int if_send (struct sk_buff* skb, struct device* dev);
+static struct enet_statistics* if_stats (struct device* dev);
+
+/* Interrupt handlers */
+static void fr502_isr (sdla_t* card);
+static void fr508_isr (sdla_t* card);
+static void fr502_rx_intr (sdla_t* card);
+static void fr508_rx_intr (sdla_t* card);
+static void tx_intr (sdla_t* card);
+static void spur_intr (sdla_t* card);
+
+/* Background polling routines */
+static void wpf_poll (sdla_t* card);
+
+/* Frame relay firmware interface functions */
+static int fr_read_version (sdla_t* card, char* str);
+static int fr_configure (sdla_t* card, fr_conf_t *conf);
+static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu);
+static int fr_comm_enable (sdla_t* card);
+static int fr_comm_disable (sdla_t* card);
+static int fr_add_dlci (sdla_t* card, int dlci, int num);
+static int fr_activate_dlci (sdla_t* card, int dlci, int num);
+static int fr_issue_isf (sdla_t* card, int isf);
+static int fr502_send (sdla_t* card, int dlci, int attr, int len, void *buf);
+static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf);
+
+/* Firmware asynchronous event handlers */
+static int fr_event (sdla_t* card, int event, fr_mbox_t* mbox);
+static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox);
+static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox);
+
+/* Miscellaneous functions */
+static int update_chan_state (struct device* dev);
+static void set_chan_state (struct device* dev, int state);
+static struct device* find_channel (sdla_t* card, unsigned dlci);
+static int is_tx_ready (sdla_t* card);
+static unsigned int dec_to_uint (unsigned char* str, int len);
+static unsigned int hex_to_uint (unsigned char* str, int len);
+
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * Frame relay protocol initialization routine.
+ *
+ * This routine is called by the main WANPIPE module during setup.  At this
+ * point adapter is completely initialized and firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure.
+ */
+int wpf_init (sdla_t* card, wandev_conf_t* conf)
+{
+	union
+	{
+		char str[80];
+		fr_conf_t cfg;
+	} u;
+
+	/* Verify configuration ID */
+	if (conf->config_id != WANCONFIG_FR)
+	{
+		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+			card->devname, conf->config_id)
+		;
+		return -EINVAL;
+	}
+
+	/* Initialize protocol-specific fields of adapter data space */
+	switch (card->hw.fwid)
+	{
+	case SFID_FR502:
+		card->mbox  = (void*)(card->hw.dpmbase + FR502_MBOX_OFFS);
+		card->rxmb  = (void*)(card->hw.dpmbase + FR502_RXMB_OFFS);
+		card->flags = (void*)(card->hw.dpmbase + FR502_FLAG_OFFS);
+		card->isr = &fr502_isr;
+		break;
+
+	case SFID_FR508:
+		card->mbox  = (void*)(card->hw.dpmbase + FR508_MBOX_OFFS);
+		card->flags = (void*)(card->hw.dpmbase + FR508_FLAG_OFFS);
+		card->isr = &fr508_isr;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Read firmware version.  Note that when adapter initializes, it
+	 * clears the mailbox, so it may appear that the first command was
+	 * executed successfully when in fact it was merely erased. To work
+	 * around this, we execute the first command twice.
+	 */
+	if (fr_read_version(card, NULL) || fr_read_version(card, u.str))
+		return -EIO
+	;
+	printk(KERN_INFO "%s: running frame relay firmware v%s\n",
+		card->devname, u.str)
+	;
+
+	/* Adjust configuration */
+	conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN);
+	conf->bps = min(conf->bps, 2048000);
+
+	/* Configure adapter firmware */
+	memset(&u.cfg, 0, sizeof(u.cfg));
+	u.cfg.mtu	= conf->mtu;
+	u.cfg.t391	= 10;
+	u.cfg.t392	= 15;
+	u.cfg.n391	= 6;
+	u.cfg.n392	= 3;
+	u.cfg.n393	= 4;
+	u.cfg.kbps	= conf->bps / 1000;
+	u.cfg.cir_fwd	= max(min(u.cfg.kbps, 512), 1);
+	u.cfg.cir_bwd = u.cfg.bc_fwd = u.cfg.bc_bwd = u.cfg.cir_fwd;
+	u.cfg.options	= 0x0081;	/* direct Rx, no CIR check */
+	switch (conf->u.fr.signalling)
+	{
+	case WANOPT_FR_Q933:	u.cfg.options |= 0x0200; break;
+	case WANOPT_FR_LMI:	u.cfg.options |= 0x0400; break;
+	}
+	if (conf->station == WANOPT_CPE)
+	{
+		u.cfg.options |= 0x8000;	/* auto config DLCI */
+	}
+	else
+	{
+		u.cfg.station = 1;	/* switch emulation mode */
+		card->u.f.node_dlci = conf->u.fr.dlci ? conf->u.fr.dlci : 16;
+		card->u.f.dlci_num  = max(min(conf->u.fr.dlci_num, 1), 100);
+	}
+	if (conf->clocking == WANOPT_INTERNAL)
+		u.cfg.port |= 0x0001
+	;
+	if (conf->interface == WANOPT_RS232)
+		u.cfg.port |= 0x0002
+	;
+	if (conf->u.fr.t391)
+		u.cfg.t391 = min(conf->u.fr.t391, 30)
+	;
+	if (conf->u.fr.t392)
+		u.cfg.t392 = min(conf->u.fr.t392, 30)
+	;
+	if (conf->u.fr.n391)
+		u.cfg.n391 = min(conf->u.fr.n391, 255)
+	;
+	if (conf->u.fr.n392)
+		u.cfg.n392 = min(conf->u.fr.n392, 10)
+	;
+	if (conf->u.fr.n393)
+		u.cfg.n393 = min(conf->u.fr.n393, 10)
+	;
+
+	if (fr_configure(card, &u.cfg))
+		return -EIO
+	;
+
+	if (card->hw.fwid == SFID_FR508)
+	{
+		fr_buf_info_t* buf_info =
+			(void*)(card->hw.dpmbase + FR508_RXBC_OFFS)
+		;
+
+		card->rxmb =
+			(void*)(buf_info->rse_next -
+			FR_MB_VECTOR + card->hw.dpmbase)
+		;
+		card->u.f.rxmb_base =
+			(void*)(buf_info->rse_base -
+			FR_MB_VECTOR + card->hw.dpmbase)
+		;
+		card->u.f.rxmb_last =
+			(void*)(buf_info->rse_base +
+			(buf_info->rse_num - 1) * sizeof(fr_buf_ctl_t) -
+			FR_MB_VECTOR + card->hw.dpmbase)
+		;
+		card->u.f.rx_base = buf_info->buf_base;
+		card->u.f.rx_top  = buf_info->buf_top;
+	}
+	card->wandev.mtu	= conf->mtu;
+	card->wandev.bps	= conf->bps;
+	card->wandev.interface	= conf->interface;
+	card->wandev.clocking	= conf->clocking;
+	card->wandev.station	= conf->station;
+	card->poll		= &wpf_poll;
+	card->wandev.update	= &update;
+	card->wandev.new_if	= &new_if;
+	card->wandev.del_if	= &del_if;
+	card->wandev.state	= WAN_DISCONNECTED;
+	return 0;
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Update device status & statistics.
+ */
+static int update (wan_device_t* wandev)
+{
+/*
+	sdla_t* card = wandev->private;
+*/
+	return 0;
+}
+
+/*============================================================================
+ * Create new logical channel.
+ * This routine is called by the router when ROUTER_IFNEW IOCTL is being
+ * handled.
+ * o parse media- and hardware-specific configuration
+ * o make sure that a new channel can be created
+ * o allocate resources, if necessary
+ * o prepare network device structure for registaration.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure (channel will not be created)
+ */
+static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
+{
+	sdla_t* card = wandev->private;
+	fr_channel_t* chan;
+	int err = 0;
+
+	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ))
+	{
+		printk(KERN_INFO "%s: invalid interface name!\n",
+			card->devname)
+		;
+		return -EINVAL;
+	}
+
+	/* allocate and initialize private data */
+	chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL);
+	if (chan == NULL)
+		return -ENOMEM
+	;
+	memset(chan, 0, sizeof(fr_channel_t));
+	strcpy(chan->name, conf->name);
+	chan->card = card;
+
+	/* verify media address */
+	if (is_digit(conf->addr[0]))
+	{
+		int dlci = dec_to_uint(conf->addr, 0);
+
+		if (dlci && (dlci <= 4095))
+		{
+			chan->dlci = dlci;
+		}
+		else
+		{
+			printk(KERN_ERR
+				"%s: invalid DLCI %u on interface %s!\n",
+				wandev->name, dlci, chan->name)
+			;
+			err = -EINVAL;
+		}
+	}
+	else
+	{
+		printk(KERN_ERR
+			"%s: invalid media address on interface %s!\n",
+			wandev->name, chan->name)
+		;
+		err = -EINVAL;
+	}
+	if (err)
+	{
+		kfree(chan);
+		return err;
+	}
+
+	/* prepare network device data space for registration */
+	dev->name = chan->name;
+	dev->init = &if_init;
+	dev->priv = chan;
+	return 0;
+}
+
+/*============================================================================
+ * Delete logical channel.
+ */
+static int del_if (wan_device_t* wandev, struct device* dev)
+{
+	if (dev->priv)
+	{
+		kfree(dev->priv);
+		dev->priv = NULL;
+	}
+	return 0;
+}
+
+/****** Network Device Interface ********************************************/
+
+/*============================================================================
+ * Initialize Linux network interface.
+ *
+ * This routine is called only once for each interface, during Linux network
+ * interface registration.  Returning anything but zero will fail interface
+ * registration.
+ */
+static int if_init (struct device* dev)
+{
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	wan_device_t* wandev = &card->wandev;
+	int i;
+
+	/* Initialize device driver entry points */
+	dev->open		= &if_open;
+	dev->stop		= &if_close;
+	dev->hard_header	= &if_header;
+	dev->rebuild_header	= &if_rebuild_hdr;
+	dev->hard_start_xmit	= &if_send;
+	dev->get_stats		= &if_stats;
+
+	/* Initialize media-specific parameters */
+	dev->family		= AF_INET;	/* address family */
+	dev->type		= ARPHRD_DLCI;	/* ARP h/w type */
+	dev->mtu		= FR_CHANNEL_MTU;
+	dev->hard_header_len	= FR_HEADER_LEN;/* media header length */
+	dev->addr_len		= 2;		/* hardware address length */
+	*(unsigned short*)dev->dev_addr = htons(chan->dlci);
+
+	/* Initialize hardware parameters (just for reference) */
+	dev->irq	= wandev->irq;
+	dev->dma	= wandev->dma;
+	dev->base_addr	= wandev->ioport;
+	dev->mem_start	= wandev->maddr;
+	dev->mem_end	= wandev->maddr + wandev->msize - 1;
+
+	/* Initialize socket buffers */
+	for (i = 0; i < DEV_NUMBUFFS; ++i)
+		skb_queue_head_init(&dev->buffs[i])
+	;
+	set_chan_state(dev, WAN_DISCONNECTED);
+	return 0;
+}
+
+/*============================================================================
+ * Open network interface.
+ * o if this is the first open, then enable communications and interrupts.
+ * o prevent module from unloading by incrementing use count
+ *
+ * Return 0 if O.k. or errno.
+ */
+static int if_open (struct device* dev)
+{
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	int err = 0;
+
+	if (dev->start)
+		return -EBUSY		/* only one open is allowed */
+	;
+	if (set_bit(0, (void*)&card->wandev.critical))
+		return -EAGAIN;
+	;
+	if (!card->open_cnt)
+	{
+		if ((fr_comm_enable(card)) ||
+		    (fr_set_intr_mode(card, 0x03, card->wandev.mtu)))
+		{
+			err = -EIO;
+			goto done;
+		}
+		if (card->wandev.station == WANOPT_CPE)
+		{
+			/* CPE: issue full status enquiry */
+			fr_issue_isf(card, FR_ISF_FSE);
+		}
+		else	/* Switch: activate DLCI(s) */
+		{
+			fr_add_dlci(card,
+				card->u.f.node_dlci, card->u.f.dlci_num)
+			;
+			fr_activate_dlci(card,
+				card->u.f.node_dlci, card->u.f.dlci_num)
+			;
+		}
+		wanpipe_set_state(card, WAN_CONNECTED);
+	}
+	dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN);
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+	wanpipe_open(card);
+	update_chan_state(dev);
+
+done:
+	card->wandev.critical = 0;
+	return err;
+}
+
+/*============================================================================
+ * Close network interface.
+ * o if this is the last open, then disable communications and interrupts.
+ * o reset flags.
+ */
+static int if_close (struct device* dev)
+{
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+
+	if (set_bit(0, (void*)&card->wandev.critical))
+		return -EAGAIN;
+	;
+	dev->start = 0;
+	wanpipe_close(card);
+	if (!card->open_cnt)
+	{
+		wanpipe_set_state(card, WAN_DISCONNECTED);
+		fr_set_intr_mode(card, 0, 0);
+		fr_comm_disable(card);
+	}
+	card->wandev.critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Build media header.
+ * o encapsulate packet according to encapsulation type.
+ *
+ * The trick here is to put packet type (Ethertype) into 'protocol' field of
+ * the socket buffer, so that we don't forget it.  If encapsulation fails,
+ * set skb->protocol to 0 and discard packet later.
+ *
+ * Return:	media header length.
+ */
+static int if_header (struct sk_buff* skb, struct device* dev,
+	unsigned short type, void* daddr, void* saddr, unsigned len)
+{
+	int hdr_len = 0;
+
+	skb->protocol = type;
+	hdr_len = wan_encapsulate(skb, dev);
+	if (hdr_len < 0)
+	{
+		hdr_len = 0;
+		skb->protocol = 0;
+	}
+	skb_push(skb, 1);
+	skb->data[0] = Q922_UI;
+	++hdr_len;
+	return hdr_len;
+}
+
+/*============================================================================
+ * Re-build media header.
+ *
+ * Return:	1	physical address resolved.
+ *		0	physical address not resolved
+ */
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+			   struct sk_buff* skb)
+{
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+
+	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
+		card->devname, dev->name)
+	;
+	return 1;
+}
+
+/*============================================================================
+ * Send a packet on a network interface.
+ * o set tbusy flag (marks start of the transmission) to block a timer-based
+ *   transmit from overlapping.
+ * o check link state. If link is not up, then drop the packet.
+ * o check channel status. If it's down then initiate a call.
+ * o pass a packet to corresponding WAN device.
+ * o free socket buffer
+ *
+ * Return:	0	complete (socket buffer must be freed)
+ *		non-0	packet may be re-transmitted (tbusy must be set)
+ *
+ * Notes:
+ * 1. This routine is called either by the protocol stack or by the "net
+ *    bottom half" (with interrupts enabled).
+ * 2. Setting tbusy flag will inhibit further transmit requests from the
+ *    protocol stack and can be used for flow control with protocol layer.
+ */
+static int if_send (struct sk_buff* skb, struct device* dev)
+{
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	int retry = 0;
+
+	if (skb == NULL)
+	{
+		/* If we get here, some higher layer thinks we've missed an
+		 * tx-done interrupt.
+		 */
+#ifdef _DEBUG_
+		printk(KERN_INFO "%s: interface %s got kicked!\n",
+			card->devname, dev->name)
+		;
+#endif
+		dev_tint(dev);
+		return 0;
+	}
+
+	if (set_bit(0, (void*)&card->wandev.critical))
+	{
+#ifdef _DEBUG_
+		printk(KERN_INFO "%s: if_send() hit critical section!\n",
+			card->devname)
+		;
+#endif
+		return 1;
+	}
+
+	if (set_bit(0, (void*)&dev->tbusy))
+	{
+#ifdef _DEBUG_
+		printk(KERN_INFO "%s: Tx collision on interface %s!\n",
+			card->devname, dev->name)
+		;
+#endif
+		++chan->ifstats.collisions;
+		retry = 1;
+	}
+	else if ((card->wandev.state != WAN_CONNECTED) ||
+	    (chan->state != WAN_CONNECTED))
+		++chan->ifstats.tx_dropped
+	;
+	else if (!is_tx_ready(card))
+		retry = 1
+	;
+	else
+	{
+ 		int err = (card->hw.fwid == SFID_FR508) ?
+			fr508_send(card, chan->dlci, 0, skb->len, skb->data) :
+			fr502_send(card, chan->dlci, 0, skb->len, skb->data)
+		;
+		if (err) ++chan->ifstats.tx_errors;
+		else ++chan->ifstats.tx_packets;
+	}
+	if (!retry)
+	{
+		dev_kfree_skb(skb, FREE_WRITE);
+		dev->tbusy = 0;
+	}
+	card->wandev.critical = 0;
+	return retry;
+}
+
+/*============================================================================
+ * Get ethernet-style interface statistics.
+ * Return a pointer to struct enet_statistics.
+ */
+static struct enet_statistics* if_stats (struct device* dev)
+{
+	fr_channel_t* chan = dev->priv;
+
+	return &chan->ifstats;
+}
+
+/****** Interrupt Handlers **************************************************/
+
+/*============================================================================
+ * S502 frame relay interrupt service routine.
+ */
+static void fr502_isr (sdla_t* card)
+{
+	fr502_flags_t* flags = card->flags;
+
+	switch (flags->iflag)
+	{
+	case 0x01:	/* receive interrupt */
+		fr502_rx_intr(card);
+		break;
+
+	case 0x02:	/* transmit interrupt */
+		flags->imask &= ~0x02;
+		tx_intr(card);
+		break;
+
+	default:
+		spur_intr(card);
+	}
+	flags->iflag = 0;
+}
+
+/*============================================================================
+ * S508 frame relay interrupt service routine.
+ */
+static void fr508_isr (sdla_t* card)
+{
+	fr508_flags_t* flags = card->flags;
+	fr_buf_ctl_t* bctl;
+
+	switch (flags->iflag)
+	{
+	case 0x01:	/* receive interrupt */
+		fr508_rx_intr(card);
+		break;
+
+	case 0x02:	/* transmit interrupt */
+		bctl = (void*)(flags->tse_offs - FR_MB_VECTOR +
+			card->hw.dpmbase)
+		;
+		bctl->flag = 0x90;	/* disable further Tx interrupts */
+		tx_intr(card);
+		break;
+
+	default:
+		spur_intr(card);
+	}
+	flags->iflag = 0;
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ */
+static void fr502_rx_intr (sdla_t* card)
+{
+	fr_mbox_t* mbox = card->rxmb;
+	struct sk_buff* skb;
+	struct device* dev;
+	fr_channel_t* chan;
+	unsigned dlci, len;
+	void* buf;
+
+	sdla_mapmem(&card->hw, FR502_RX_VECTOR);
+	dlci = mbox->cmd.dlci;
+	len  = mbox->cmd.length;
+
+	/* Find network interface for this packet */
+	dev = find_channel(card, dlci);
+	if (dev == NULL)
+	{
+		/* Invalid channel, discard packet */
+		printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n",
+			card->devname, dlci)
+		;
+		goto rx_done;
+	}
+	chan = dev->priv;
+	if (!dev->start)
+	{
+		++chan->ifstats.rx_dropped;
+		goto rx_done;
+	}
+
+	/* Allocate socket buffer */
+	skb = dev_alloc_skb(len);
+	if (skb == NULL)
+	{
+		printk(KERN_INFO "%s: no socket buffers available!\n",
+			card->devname)
+		;
+		++chan->ifstats.rx_dropped;
+		goto rx_done;
+	}
+
+	/* Copy data to the socket buffer */
+	buf = skb_put(skb, len);
+	memcpy(buf, mbox->data, len);
+	sdla_mapmem(&card->hw, FR_MB_VECTOR);
+
+	/* Decapsulate packet and pass it up the protocol stack */
+	skb->dev = dev;
+	buf = skb_pull(skb, 1);	/* remove hardware header */
+	if (!wan_type_trans(skb, dev))
+	{
+		/* can't decapsulate packet */
+		dev_kfree_skb(skb, FREE_READ);
+		++chan->ifstats.rx_errors;
+	}
+	else
+	{
+		netif_rx(skb);
+		++chan->ifstats.rx_packets;
+	}
+
+rx_done:
+	sdla_mapmem(&card->hw, FR_MB_VECTOR);
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ */
+static void fr508_rx_intr (sdla_t* card)
+{
+	fr_buf_ctl_t* frbuf = card->rxmb;
+	struct sk_buff* skb;
+	struct device* dev;
+	fr_channel_t* chan;
+	unsigned dlci, len, offs;
+	void* buf;
+
+	if (frbuf->flag != 0x01)
+	{
+		printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n",
+			card->devname, (unsigned)frbuf)
+		;
+		return;
+	}
+	len  = frbuf->length;
+	dlci = frbuf->dlci;
+	offs = frbuf->offset;
+
+	/* Find network interface for this packet */
+	dev = find_channel(card, dlci);
+	if (dev == NULL)
+	{
+		/* Invalid channel, discard packet */
+		printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n",
+			card->devname, dlci)
+		;
+		goto rx_done;
+	}
+	chan = dev->priv;
+	if (!dev->start)
+	{
+		++chan->ifstats.rx_dropped;
+		goto rx_done;
+	}
+
+	/* Allocate socket buffer */
+	skb = dev_alloc_skb(len);
+	if (skb == NULL)
+	{
+		printk(KERN_INFO "%s: no socket buffers available!\n",
+			card->devname)
+		;
+		++chan->ifstats.rx_dropped;
+		goto rx_done;
+	}
+
+	/* Copy data to the socket buffer */
+	if ((offs + len) > card->u.f.rx_top)
+	{
+		unsigned tmp = card->u.f.rx_top - offs;
+
+		buf = skb_put(skb, tmp);
+		sdla_peek(&card->hw, offs, buf, tmp);
+		offs = card->u.f.rx_base;
+		len -= tmp;
+	}
+	buf = skb_put(skb, len);
+	sdla_peek(&card->hw, offs, buf, len);
+
+	/* Decapsulate packet and pass it up the protocol stack */
+	skb->dev = dev;
+	buf = skb_pull(skb, 1);	/* remove hardware header */
+	if (!wan_type_trans(skb, dev))
+	{
+		/* can't decapsulate packet */
+		dev_kfree_skb(skb, FREE_READ);
+		++chan->ifstats.rx_errors;
+	}
+	else
+	{
+		netif_rx(skb);
+		++chan->ifstats.rx_packets;
+	}
+
+rx_done:
+	/* Release buffer element and calculate a pointer to the next one */
+	frbuf->flag = 0;
+	card->rxmb = ++frbuf;
+	if ((void*)frbuf > card->u.f.rxmb_last)
+		card->rxmb = card->u.f.rxmb_base
+	;
+}
+
+/*============================================================================
+ * Transmit interrupt handler.
+ * o print a warning
+ * o 
+ * If number of spurious interrupts exceeded some limit, then ???
+ */
+static void tx_intr (sdla_t* card)
+{
+	printk(KERN_INFO "%s: transmit interrupt!\n", card->devname);
+}
+
+/*============================================================================
+ * Spurious interrupt handler.
+ * o print a warning
+ * o 
+ * If number of spurious interrupts exceeded some limit, then ???
+ */
+static void spur_intr (sdla_t* card)
+{
+	printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
+}
+
+/****** Background Polling Routines  ****************************************/
+
+/*============================================================================
+ * Main polling routine.
+ * This routine is repeatedly called by the WANPIPE 'thead' to allow for
+ * time-dependent housekeeping work.
+ *
+ * o fetch asynchronous network events.
+ *
+ * Notes:
+ * 1. This routine may be called on interrupt context with all interrupts
+ *    enabled. Beware!
+ */
+static void wpf_poll (sdla_t* card)
+{
+	fr502_flags_t* flags = card->flags;
+
+	if (flags->event)
+	{
+		fr_mbox_t* mbox = card->mbox;
+		int err;
+
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_READ_STATUS;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+		if (err) fr_event(card, err, mbox);
+	}
+}
+
+/****** Frame Relay Firmware-Specific Functions *****************************/
+
+/*============================================================================
+ * Read firmware code version.
+ * o fill string str with firmware version info. 
+ */
+static int fr_read_version (sdla_t* card, char* str)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_READ_CODE_VERSION;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	if (!err && str)
+	{
+		int len = mbox->cmd.length;
+
+		memcpy(str, mbox->data, len);
+	        str[len] = '\0';
+	}
+	return err;
+}
+
+/*============================================================================
+ * Set global configuration.
+ */
+static int fr_configure (sdla_t* card, fr_conf_t *conf)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int dlci = card->u.f.node_dlci;
+	int dlci_num = card->u.f.dlci_num;
+	int err, i;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		memcpy(mbox->data, conf, sizeof(fr_conf_t));
+		if (dlci_num) for (i = 0; i < dlci_num; ++i)
+			((fr_conf_t*)mbox->data)->dlci[i] = dlci + i
+		;
+		mbox->cmd.command = FR_SET_CONFIG;
+		mbox->cmd.length =
+			sizeof(fr_conf_t) + dlci_num * sizeof(short)
+		;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	return err;
+}
+
+/*============================================================================
+ * Set interrupt mode.
+ */
+static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		if (card->hw.fwid == SFID_FR502)
+		{
+			fr502_intr_ctl_t* ictl = (void*)mbox->data;
+
+			memset(ictl, 0, sizeof(fr502_intr_ctl_t));
+			ictl->mode   = mode;
+			ictl->tx_len = mtu;
+			mbox->cmd.length = sizeof(fr502_intr_ctl_t);
+		}
+		else
+		{
+			fr508_intr_ctl_t* ictl = (void*)mbox->data;
+
+			memset(ictl, 0, sizeof(fr508_intr_ctl_t));
+			ictl->mode   = mode;
+			ictl->tx_len = mtu;
+			ictl->irq    = card->hw.irq;
+			mbox->cmd.length = sizeof(fr508_intr_ctl_t);
+		}
+		mbox->cmd.command = FR_SET_INTR_MODE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	return err;
+}
+
+/*============================================================================
+ * Enable communications.
+ */
+static int fr_comm_enable (sdla_t* card)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_COMM_ENABLE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	return err;
+}
+
+/*============================================================================
+ * Disable communications. 
+ */
+static int fr_comm_disable (sdla_t* card)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_COMM_DISABLE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	return err;
+}
+
+/*============================================================================
+ * Add DLCI(s) (Access Node only!). 
+ */
+static int fr_add_dlci (sdla_t* card, int dlci, int num)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err, i;
+
+	do
+	{
+		unsigned short* dlci_list = (void*)mbox->data;
+
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		for (i = 0; i < num; ++i)
+			dlci_list[i] = dlci + i
+		;
+		mbox->cmd.length  = num * sizeof(short);
+		mbox->cmd.command = FR_ADD_DLCI;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	return err;
+}
+
+/*============================================================================
+ * Activate DLCI(s) (Access Node only!). 
+ */
+static int fr_activate_dlci (sdla_t* card, int dlci, int num)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err, i;
+
+	do
+	{
+		unsigned short* dlci_list = (void*)mbox->data;
+
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		for (i = 0; i < num; ++i)
+			dlci_list[i] = dlci + i
+		;
+		mbox->cmd.length  = num * sizeof(short);
+		mbox->cmd.command = FR_ACTIVATE_DLCI;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	return err;
+}
+
+/*============================================================================
+ * Issue in-channel signalling frame. 
+ */
+static int fr_issue_isf (sdla_t* card, int isf)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->data[0] = isf;
+		mbox->cmd.length  = 1;
+		mbox->cmd.command = FR_ISSUE_IS_FRAME;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	return err;
+}
+
+/*============================================================================
+ * Send a frame (S502 version). 
+ */
+static int fr502_send (sdla_t* card, int dlci, int attr, int len, void *buf)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		memcpy(mbox->data, buf, len);
+		mbox->cmd.dlci    = dlci;
+		mbox->cmd.attr    = attr;
+		mbox->cmd.length  = len;
+		mbox->cmd.command = FR_WRITE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+	return err;
+}
+
+/*============================================================================
+ * Send a frame (S508 version). 
+ */
+static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.dlci    = dlci;
+		mbox->cmd.attr    = attr;
+		mbox->cmd.length  = len;
+		mbox->cmd.command = FR_WRITE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+
+	if (!err)
+	{
+		fr_buf_ctl_t* frbuf = (void*)(*(unsigned long*)mbox->data -
+			FR_MB_VECTOR + card->hw.dpmbase)
+		;
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+		sdla_poke(&card->hw, frbuf->offset, buf, len);
+		frbuf->flag = 0x01;
+		restore_flags(flags);
+	}
+	return err;
+}
+
+/****** Firmware Asynchronous Event Handlers ********************************/
+
+/*============================================================================
+ * Main asyncronous event/error handler.
+ *	This routine is called whenever firmware command returns non-zero
+ *	return code.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox)
+{
+	switch (event)
+	{
+	case FRRES_MODEM_FAILURE:
+		return fr_modem_failure(card, mbox);
+
+	case FRRES_CHANNEL_DOWN:
+		wanpipe_set_state(card, WAN_DISCONNECTED);
+		return 1;
+
+	case FRRES_CHANNEL_UP:
+		wanpipe_set_state(card, WAN_CONNECTED);
+		return 1;
+
+	case FRRES_DLCI_CHANGE:
+		return fr_dlci_change(card, mbox);
+
+	case FRRES_DLCI_MISMATCH:
+		printk(KERN_INFO "%s: DLCI list mismatch!\n", card->devname);
+		return 1;
+
+	case CMD_TIMEOUT:
+		printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+			card->devname, mbox->cmd.command)
+		;
+		break;
+
+	default:
+		printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+			card->devname, mbox->cmd.command, event)
+		;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Handle modem error.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox)
+{
+	printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n",
+		card->devname, mbox->data[0])
+	;
+	switch (mbox->cmd.command)
+	{
+	case FR_WRITE:
+	case FR_READ:
+		return 0;
+	}
+	return 1;
+}
+
+/*============================================================================
+ * Handle DLCI status change.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox)
+{
+	dlci_status_t* status = (void*)mbox->data;
+	int cnt = mbox->cmd.length / sizeof(dlci_status_t);
+
+	for (; cnt; --cnt, ++status)
+	{
+		unsigned short dlci = status->dlci;
+		struct device* dev = find_channel(card, dlci);
+
+		if (status->state & 0x01)
+		{
+			printk(KERN_INFO
+				"%s: DLCI %u has been deleted!\n",
+				card->devname, dlci)
+			;
+			if (dev && dev->start)
+				set_chan_state(dev, WAN_DISCONNECTED)
+			;
+		}
+		else if (status->state & 0x02)
+		{
+			printk(KERN_INFO
+				"%s: DLCI %u becomes active!\n",
+				card->devname, dlci)
+			;
+			if (dev && dev->start)
+				set_chan_state(dev, WAN_CONNECTED)
+			;
+		}
+	}
+	return 1;
+}
+
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * Update channel state. 
+ */
+static int update_chan_state (struct device* dev)
+{
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_LIST_ACTIVE_DLCI;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+
+	if (!err)
+	{
+		unsigned short* list = (void*)mbox->data;
+		int cnt = mbox->cmd.length / sizeof(short);
+
+		for (; cnt; --cnt, ++list)
+		{
+			if (*list == chan->dlci)
+			{
+ 				set_chan_state(dev, WAN_CONNECTED);
+				break;
+			}
+		}
+	}
+	return err;
+}
+
+/*============================================================================
+ * Set channel state.
+ */
+static void set_chan_state (struct device* dev, int state)
+{
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (chan->state != state)
+	{
+		switch (state)
+		{
+		case WAN_CONNECTED:
+			printk (KERN_INFO "%s: interface %s connected!\n",
+				card->devname, dev->name)
+			;
+			break;
+
+		case WAN_CONNECTING:
+			printk (KERN_INFO "%s: interface %s connecting...\n",
+				card->devname, dev->name)
+			;
+			break;
+
+		case WAN_DISCONNECTED:
+			printk (KERN_INFO "%s: interface %s disconnected!\n",
+				card->devname, dev->name)
+			;
+			break;
+		}
+		chan->state = state;
+	}
+	chan->state_tick = jiffies;
+	restore_flags(flags);
+}
+
+/*============================================================================
+ * Find network device by its channel number.
+ */
+static struct device* find_channel (sdla_t* card, unsigned dlci)
+{
+	struct device* dev;
+
+	for (dev = card->wandev.dev; dev; dev = dev->slave)
+		if (((fr_channel_t*)dev->priv)->dlci == dlci) break
+	;
+	return dev;
+}
+
+/*============================================================================
+ * Check to see if a frame can be sent. If no transmit buffers available,
+ * enable transmit interrupts.
+ *
+ * Return:	1 - Tx buffer(s) available
+ *		0 - no buffers available
+ */
+static int is_tx_ready (sdla_t* card)
+{
+	if (card->hw.fwid == SFID_FR508)
+	{
+		fr508_flags_t* flags = card->flags;
+		unsigned char sb = inb(card->hw.port);
+
+		if (sb & 0x02) return 1;
+		flags->imask |= 0x02;
+	}
+	else
+	{
+		fr502_flags_t* flags = card->flags;
+
+		if (flags->tx_ready) return 1;
+		flags->imask |= 0x02;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Convert decimal string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are converted.
+ */
+static unsigned int dec_to_uint (unsigned char* str, int len)
+{
+	unsigned val;
+
+	if (!len) len = strlen(str);
+	for (val = 0; len && is_digit(*str); ++str, --len)
+		val = (val * 10) + (*str - (unsigned)'0')
+	;
+	return val;
+}
+
+/*============================================================================
+ * Convert hex string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are conferted.
+ */
+static unsigned int hex_to_uint (unsigned char* str, int len)
+{
+	unsigned val, ch;
+
+	if (!len) len = strlen(str);
+	for (val = 0; len; ++str, --len)
+	{
+		ch = *str;
+		if (is_digit(ch))
+			val = (val << 4) + (ch - (unsigned)'0')
+		;
+		else if (is_hex_digit(ch))
+			val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10)
+		;
+		else break;
+	}
+	return val;
+}
+
+/****** End *****************************************************************/
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c
--- v2.1.24/linux/drivers/net/sdla_ppp.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/sdla_ppp.c	Sun Feb  2 16:43:08 1997
@@ -0,0 +1,1025 @@
+/*****************************************************************************
+* sdla_ppp.c	WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Jan 06, 1997	Gene Kozin	Initial version.
+*****************************************************************************/
+
+#if	!defined(__KERNEL__) || !defined(MODULE)
+#error	This code MUST be compiled as a kernel module!
+#endif
+
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/router.h>	/* WAN router definitions */
+#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
+#include <linux/if_arp.h>	/* ARPHRD_* defines */
+#include <asm/byteorder.h>	/* htons(), etc. */
+
+#define	_GNUC_
+#include <linux/sdla_ppp.h>		/* PPP firmware API definitions */
+
+/****** Defines & Macros ****************************************************/
+
+#ifdef	_DEBUG_
+#define	STATIC
+#else
+#define	STATIC		static
+#endif
+
+#define	CMD_OK		0		/* normal firmware return code */
+#define	CMD_TIMEOUT	0xFF		/* firmware command timed out */
+
+#define	PPP_DFLT_MTU	1500		/* default MTU */
+#define	PPP_MAX_MTU	4000		/* maximum MTU */
+#define PPP_HDR_LEN	1
+
+#define	CONNECT_TIMEOUT	(90*HZ)		/* link connection timeout */
+#define	HOLD_DOWN_TIME	(30*HZ)		/* link hold down time */
+
+/****** Function Prototypes *************************************************/
+
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int update (wan_device_t* wandev);
+static int new_if (wan_device_t* wandev, struct device* dev,
+	wanif_conf_t* conf);
+static int del_if (wan_device_t* wandev, struct device* dev);
+
+/* Network device interface */
+static int if_init   (struct device* dev);
+static int if_open   (struct device* dev);
+static int if_close  (struct device* dev);
+static int if_header (struct sk_buff* skb, struct device* dev,
+	unsigned short type, void* daddr, void* saddr, unsigned len);
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+	struct sk_buff* skb);
+static int if_send (struct sk_buff* skb, struct device* dev);
+static struct enet_statistics* if_stats (struct device* dev);
+
+/* PPP firmware interface functions */
+static int ppp_read_version (sdla_t* card, char* str);
+static int ppp_configure (sdla_t* card, void* data);
+static int ppp_set_intr_mode (sdla_t* card, unsigned mode);
+static int ppp_comm_enable (sdla_t* card);
+static int ppp_comm_disable (sdla_t* card);
+static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto);
+static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb);
+
+/* Interrupt handlers */
+STATIC void wpp_isr (sdla_t* card);
+static void rx_intr (sdla_t* card);
+static void tx_intr (sdla_t* card);
+
+/* Background polling routines */
+static void wpp_poll (sdla_t* card);
+static void poll_active (sdla_t* card);
+static void poll_connecting (sdla_t* card);
+static void poll_disconnected (sdla_t* card);
+
+/* Miscellaneous functions */
+static int config502 (sdla_t* card);
+static int config508 (sdla_t* card);
+static void show_disc_cause (sdla_t* card, unsigned cause);
+static unsigned char bps_to_speed_code (unsigned long bps);
+
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * PPP protocol initialization routine.
+ *
+ * This routine is called by the main WANPIPE module during setup.  At this
+ * point adapter is completely initialized and firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure.
+ */
+int wpp_init (sdla_t* card, wandev_conf_t* conf)
+{
+	union
+	{
+		char str[80];
+	} u;
+
+	/* Verify configuration ID */
+	if (conf->config_id != WANCONFIG_PPP)
+	{
+		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+			card->devname, conf->config_id)
+		;
+		return -EINVAL;
+	}
+
+	/* Initialize protocol-specific fields */
+	switch (card->hw.fwid)
+	{
+	case SFID_PPP502:
+		card->mbox  = (void*)(card->hw.dpmbase + PPP502_MB_OFFS);
+		card->flags = (void*)(card->hw.dpmbase + PPP502_FLG_OFFS);
+		break;
+
+	case SFID_PPP508:
+		card->mbox  = (void*)(card->hw.dpmbase + PPP508_MB_OFFS);
+		card->flags = (void*)(card->hw.dpmbase + PPP508_FLG_OFFS);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Read firmware version.  Note that when adapter initializes, it
+	 * clears the mailbox, so it may appear that the first command was
+	 * executed successfully when in fact it was merely erased. To work
+	 * around this, we execute the first command twice.
+	 */
+	if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str))
+		return -EIO
+	;
+	printk(KERN_INFO "%s: running PPP firmware v%s\n",
+		card->devname, u.str)
+	;
+
+	/* Adjust configuration and set defaults */
+	card->wandev.mtu = (conf->mtu) ?
+		min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU
+	;
+	card->wandev.bps	= conf->bps;
+	card->wandev.interface	= conf->interface;
+	card->wandev.clocking	= conf->clocking;
+	card->wandev.station	= conf->station;
+	card->isr		= &wpp_isr;
+	card->poll		= &wpp_poll;
+	card->wandev.update	= &update;
+	card->wandev.new_if	= &new_if;
+	card->wandev.del_if	= &del_if;
+	card->wandev.state	= WAN_DISCONNECTED;
+	return 0;
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Update device status & statistics.
+ */
+static int update (wan_device_t* wandev)
+{
+/*
+	sdla_t* card = wandev->private;
+*/
+	return 0;
+}
+
+/*============================================================================
+ * Create new logical channel.
+ * This routine is called by the router when ROUTER_IFNEW IOCTL is being
+ * handled.
+ * o parse media- and hardware-specific configuration
+ * o make sure that a new channel can be created
+ * o allocate resources, if necessary
+ * o prepare network device structure for registaration.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure (channel will not be created)
+ */
+static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
+{
+	sdla_t* card = wandev->private;
+
+	if (wandev->ndev)
+		return -EEXIST
+	;
+	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ))
+	{
+		printk(KERN_INFO "%s: invalid interface name!\n",
+			card->devname)
+		;
+		return -EINVAL;
+	}
+
+	/* initialize data */
+	strcpy(card->u.p.if_name, conf->name);
+
+	/* prepare network device data space for registration */
+	dev->name = card->u.p.if_name;
+	dev->init = &if_init;
+	dev->priv = card;
+	return 0;
+}
+
+/*============================================================================
+ * Delete logical channel.
+ */
+static int del_if (wan_device_t* wandev, struct device* dev)
+{
+	return 0;
+}
+
+/****** Network Device Interface ********************************************/
+
+/*============================================================================
+ * Initialize Linux network interface.
+ *
+ * This routine is called only once for each interface, during Linux network
+ * interface registration.  Returning anything but zero will fail interface
+ * registration.
+ */
+static int if_init (struct device* dev)
+{
+	sdla_t* card = dev->priv;
+	wan_device_t* wandev = &card->wandev;
+	int i;
+
+	/* Initialize device driver entry points */
+	dev->open		= &if_open;
+	dev->stop		= &if_close;
+	dev->hard_header	= &if_header;
+	dev->rebuild_header	= &if_rebuild_hdr;
+	dev->hard_start_xmit	= &if_send;
+	dev->get_stats		= &if_stats;
+
+	/* Initialize media-specific parameters */
+	dev->family		= AF_INET;	/* address family */
+	dev->type		= ARPHRD_PPP;	/* ARP h/w type */
+	dev->mtu		= wandev->mtu;
+	dev->hard_header_len	= PPP_HDR_LEN;	/* media header length */
+
+	/* Initialize hardware parameters (just for reference) */
+	dev->irq		= wandev->irq;
+	dev->dma		= wandev->dma;
+	dev->base_addr		= wandev->ioport;
+	dev->mem_start		= wandev->maddr;
+	dev->mem_end		= wandev->maddr + wandev->msize - 1;
+
+	/* Initialize socket buffers */
+	for (i = 0; i < DEV_NUMBUFFS; ++i)
+		skb_queue_head_init(&dev->buffs[i])
+	;
+	return 0;
+}
+
+/*============================================================================
+ * Open network interface.
+ * o enable communications and interrupts.
+ * o prevent module from unloading by incrementing use count
+ *
+ * Return 0 if O.k. or errno.
+ */
+static int if_open (struct device* dev)
+{
+	sdla_t* card = dev->priv;
+	int err = 0;
+
+	if (dev->start)
+		return -EBUSY		/* only one open is allowed */
+	;
+	if (set_bit(0, (void*)&card->wandev.critical))
+		return -EAGAIN;
+	;
+	if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card))
+	{
+		err = -EIO;
+		goto split;
+	}
+
+	/* Initialize Rx/Tx buffer control fields */
+	if (card->hw.fwid == SFID_PPP502)
+	{
+		ppp502_buf_info_t* info =
+			(void*)(card->hw.dpmbase + PPP502_BUF_OFFS)
+		;
+
+		card->u.p.txbuf_base = (void*)(card->hw.dpmbase +
+			info->txb_offs)
+		;
+		card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base +
+			(info->txb_num - 1)
+		;
+		card->u.p.rxbuf_base = (void*)(card->hw.dpmbase +
+			info->rxb_offs)
+		;
+		card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base +
+			(info->rxb_num - 1)
+		;
+	}
+	else
+	{
+		ppp508_buf_info_t* info =
+			(void*)(card->hw.dpmbase + PPP508_BUF_OFFS)
+		;
+
+		card->u.p.txbuf_base = (void*)(card->hw.dpmbase +
+			(info->txb_ptr - PPP508_MB_VECT))
+		;
+		card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base +
+			(info->txb_num - 1)
+		;
+		card->u.p.rxbuf_base = (void*)(card->hw.dpmbase +
+			(info->rxb_ptr - PPP508_MB_VECT))
+		;
+		card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base +
+			(info->rxb_num - 1)
+		;
+		card->u.p.rx_base = info->rxb_base;
+		card->u.p.rx_top  = info->rxb_end;
+	}
+	card->u.p.txbuf = card->u.p.txbuf_base;
+	card->rxmb = card->u.p.rxbuf_base;
+
+	if (ppp_set_intr_mode(card, 0x03) || ppp_comm_enable(card))
+	{
+		err = -EIO;
+		goto split;
+	}
+	wanpipe_set_state(card, WAN_CONNECTING);
+	wanpipe_open(card);
+	dev->mtu = min(dev->mtu, card->wandev.mtu);
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+
+split:
+	card->wandev.critical = 0;
+	return err;
+}
+
+/*============================================================================
+ * Close network interface.
+ * o if this is the last open, then disable communications and interrupts.
+ * o reset flags.
+ */
+static int if_close (struct device* dev)
+{
+	sdla_t* card = dev->priv;
+
+	if (set_bit(0, (void*)&card->wandev.critical))
+		return -EAGAIN;
+	;
+	dev->start = 0;
+	wanpipe_close(card);
+	wanpipe_set_state(card, WAN_DISCONNECTED);
+	ppp_set_intr_mode(card, 0);
+	ppp_comm_disable(card);
+	card->wandev.critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Build media header.
+ *
+ * The trick here is to put packet type (Ethertype) into 'protocol' field of
+ * the socket buffer, so that we don't forget it.  If packet type is not
+ * supported, set skb->protocol to 0 and discard packet later.
+ *
+ * Return:	media header length.
+ */
+static int if_header (struct sk_buff* skb, struct device* dev,
+	unsigned short type, void* daddr, void* saddr, unsigned len)
+{
+	switch (type)
+	{
+	case ETH_P_IP:
+	case ETH_P_IPX:
+		skb->protocol = type;
+		break;
+
+	default:
+		skb->protocol = 0;
+	}
+	return PPP_HDR_LEN;
+}
+
+/*============================================================================
+ * Re-build media header.
+ *
+ * Return:	1	physical address resolved.
+ *		0	physical address not resolved
+ */
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+			   struct sk_buff* skb)
+{
+	sdla_t* card = dev->priv;
+
+	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
+		card->devname, dev->name)
+	;
+	return 1;
+}
+
+/*============================================================================
+ * Send a packet on a network interface.
+ * o set tbusy flag (marks start of the transmission) to block a timer-based
+ *   transmit from overlapping.
+ * o check link state. If link is not up, then drop the packet.
+ * o execute adapter send command.
+ * o free socket buffer
+ *
+ * Return:	0	complete (socket buffer must be freed)
+ *		non-0	packet may be re-transmitted (tbusy must be set)
+ *
+ * Notes:
+ * 1. This routine is called either by the protocol stack or by the "net
+ *    bottom half" (with interrupts enabled).
+ * 2. Setting tbusy flag will inhibit further transmit requests from the
+ *    protocol stack and can be used for flow control with protocol layer.
+ */
+static int if_send (struct sk_buff* skb, struct device* dev)
+{
+	sdla_t* card = dev->priv;
+	int retry = 0;
+
+	if (skb == NULL)
+	{
+		/* If we get here, some higher layer thinks we've missed an
+		 * tx-done interrupt.
+		 */
+#ifdef _DEBUG_
+		printk(KERN_INFO "%s: interface %s got kicked!\n",
+			card->devname, dev->name)
+		;
+#endif
+		dev_tint(dev);
+		return 0;
+	}
+
+	if (set_bit(0, (void*)&card->wandev.critical))
+	{
+#ifdef _DEBUG_
+		printk(KERN_INFO "%s: if_send() hit critical section!\n",
+			card->devname)
+		;
+#endif
+		return 1;
+	}
+
+	if (set_bit(0, (void*)&dev->tbusy))
+	{
+#ifdef _DEBUG_
+		printk(KERN_INFO "%s: Tx collision on interface %s!\n",
+			card->devname, dev->name)
+		;
+#endif
+		++card->wandev.stats.collisions;
+		retry = 1;
+	}
+	else if (card->wandev.state != WAN_CONNECTED)
+		++card->wandev.stats.tx_dropped
+	;
+	else if (!skb->protocol)
+		++card->wandev.stats.tx_errors
+	;
+	else if (ppp_send(card, skb->data, skb->len, skb->protocol))
+	{
+		ppp_flags_t* flags = card->flags;
+
+		flags->imask |= 0x02;	/* unmask Tx interrupts */
+		retry = 1;
+	}
+	else ++card->wandev.stats.tx_packets;
+
+	if (!retry)
+	{
+		dev_kfree_skb(skb, FREE_WRITE);
+		dev->tbusy = 0;
+	}
+	card->wandev.critical = 0;
+	return retry;
+}
+
+/*============================================================================
+ * Get ethernet-style interface statistics.
+ * Return a pointer to struct enet_statistics.
+ */
+static struct enet_statistics* if_stats (struct device* dev)
+{
+	sdla_t* card = dev->priv;
+
+	return &card->wandev.stats;
+}
+
+/****** PPP Firmware Interface Functions ************************************/
+
+/*============================================================================
+ * Read firmware code version.
+ *	Put code version as ASCII string in str. 
+ */
+static int ppp_read_version (sdla_t* card, char* str)
+{
+	ppp_mbox_t* mb = card->mbox;
+	int err;
+
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->cmd.command = PPP_READ_CODE_VERSION;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err != CMD_OK) ppp_error(card, err, mb);
+	else if (str)
+	{
+		int len = mb->cmd.length;
+
+		memcpy(str, mb->data, len);
+		str[len] = '\0';
+	}
+	return err;
+}
+
+/*============================================================================
+ * Configure PPP firmware.
+ */
+static int ppp_configure (sdla_t* card, void* data)
+{
+	ppp_mbox_t* mb = card->mbox;
+	int data_len = (card->hw.fwid == SFID_PPP502) ?
+		sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t)
+	;
+	int err;
+
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	memcpy(mb->data, data, data_len);
+	mb->cmd.length  = data_len;
+	mb->cmd.command = PPP_SET_CONFIG;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err != CMD_OK) ppp_error(card, err, mb);
+	return err;
+}
+
+/*============================================================================
+ * Set interrupt mode.
+ */
+static int ppp_set_intr_mode (sdla_t* card, unsigned mode)
+{
+	ppp_mbox_t* mb = card->mbox;
+	int err;
+
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->data[0] = mode;
+	switch (card->hw.fwid)
+	{
+	case SFID_PPP502:
+		mb->cmd.length  = 1;
+		break;
+
+	case SFID_PPP508:
+	default:
+		mb->data[1] = card->hw.irq;
+		mb->cmd.length = 2;
+	}
+	mb->cmd.command = PPP_SET_INTR_FLAGS;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err != CMD_OK) ppp_error(card, err, mb);
+	return err;
+}
+
+/*============================================================================
+ * Enable communications.
+ */
+static int ppp_comm_enable (sdla_t* card)
+{
+	ppp_mbox_t* mb = card->mbox;
+	int err;
+
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->cmd.command = PPP_COMM_ENABLE;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err != CMD_OK) ppp_error(card, err, mb);
+	return err;
+}
+
+/*============================================================================
+ * Disable communications.
+ */
+static int ppp_comm_disable (sdla_t* card)
+{
+	ppp_mbox_t* mb = card->mbox;
+	int err;
+
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->cmd.command = PPP_COMM_DISABLE;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err != CMD_OK) ppp_error(card, err, mb);
+	return err;
+}
+
+/*============================================================================
+ * Send packet.
+ *	Return:	0 - o.k.
+ *		1 - no transmit buffers available
+ */
+static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto)
+{
+	ppp_buf_ctl_t* txbuf = card->u.p.txbuf;
+	unsigned long addr, cpu_flags;
+
+	if (txbuf->flag)
+		return 1
+	;
+	if (card->hw.fwid == SFID_PPP502)
+		addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]
+	; 
+	else addr = txbuf->buf.ptr;
+
+	save_flags(cpu_flags);
+	cli();
+	sdla_poke(&card->hw, addr, data, len);
+	restore_flags(cpu_flags);
+	txbuf->length = len;		/* frame length */
+	if (proto == ETH_P_IPX)
+		txbuf->proto = 0x01	/* protocol ID */
+	;
+	txbuf->flag = 1;		/* start transmission */
+
+	/* Update transmit buffer control fields */
+	card->u.p.txbuf = ++txbuf;
+	if ((void*)txbuf > card->u.p.txbuf_last)
+		card->u.p.txbuf = card->u.p.txbuf_base
+	;
+	return 0;
+}
+
+/****** Firmware Error Handler **********************************************/
+
+/*============================================================================
+ * Firmware error handler.
+ *	This routine is called whenever firmware command returns non-zero
+ *	return code.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb)
+{
+	unsigned cmd = mb->cmd.command;
+
+	switch (err)
+	{
+	case CMD_TIMEOUT:
+		printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+			card->devname, cmd)
+		;
+		break;
+
+	default:
+		printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+			card->devname, cmd, err)
+		;
+	}
+	return 0;
+}
+
+/****** Interrupt Handlers **************************************************/
+
+/*============================================================================
+ * PPP interrupt service routine.
+ */
+STATIC void wpp_isr (sdla_t* card)
+{
+	ppp_flags_t* flags = card->flags;
+
+	switch (flags->iflag)
+	{
+	case 0x01:	/* receive interrupt */
+		rx_intr(card);
+		break;
+
+	case 0x02:	/* transmit interrupt */
+		flags->imask &= ~0x02;
+		tx_intr(card);
+		break;
+
+	default:	/* unexpected interrupt */
+		printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
+			card->devname, flags->iflag)
+		;
+	}
+	flags->iflag = 0;
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ */
+static void rx_intr (sdla_t* card)
+{
+	ppp_buf_ctl_t* rxbuf = card->rxmb;
+	struct device* dev = card->wandev.dev;
+	struct sk_buff* skb;
+	unsigned len;
+	void* buf;
+
+	if (rxbuf->flag != 0x01)
+	{
+		printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n",
+			card->devname, (unsigned)rxbuf)
+		;
+		return;
+	}
+
+	if (!dev || !dev->start)
+		goto rx_done
+	;
+	len  = rxbuf->length;
+
+	/* Allocate socket buffer */
+	skb = dev_alloc_skb(len);
+	if (skb == NULL)
+	{
+		printk(KERN_INFO "%s: no socket buffers available!\n",
+			card->devname)
+		;
+		++card->wandev.stats.rx_dropped;
+		goto rx_done;
+	}
+
+	/* Copy data to the socket buffer */
+	if (card->hw.fwid == SFID_PPP502)
+	{
+		unsigned addr = (rxbuf->buf.o_p[1] << 8) + rxbuf->buf.o_p[0]; 
+
+		buf = skb_put(skb, len);
+		sdla_peek(&card->hw, addr, buf, len);
+	}
+	else
+	{
+		unsigned addr = rxbuf->buf.ptr;
+
+		if ((addr + len) > card->u.p.rx_top)
+		{
+			unsigned tmp = card->u.p.rx_top - addr;
+
+			buf = skb_put(skb, tmp);
+			sdla_peek(&card->hw, addr, buf, tmp);
+			addr = card->u.p.rx_base;
+			len -= tmp;
+		}
+		buf = skb_put(skb, len);
+		sdla_peek(&card->hw, addr, buf, len);
+	}
+
+	/* Decapsulate packet and pass it up the protocol stack */
+	switch (rxbuf->proto)
+	{
+	case 0x00:
+		skb->protocol = htons(ETH_P_IP);
+		break;
+
+	case 0x01:
+		skb->protocol = htons(ETH_P_IPX);
+		break;
+	}
+	skb->dev = dev;
+	netif_rx(skb);
+	++card->wandev.stats.rx_packets;
+
+rx_done:
+	/* Release buffer element and calculate a pointer to the next one */
+	rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00;
+	card->rxmb = ++rxbuf;
+	if ((void*)rxbuf > card->u.p.rxbuf_last)
+		card->rxmb = card->u.p.rxbuf_base
+	;
+}
+
+/*============================================================================
+ * Transmit interrupt handler.
+ */
+static void tx_intr (sdla_t* card)
+{
+	struct device* dev = card->wandev.dev;
+
+	if (!dev || !dev->start)
+		return
+	;
+	dev->tbusy = 0;
+	dev_tint(dev);
+}
+
+/****** Background Polling Routines  ****************************************/
+
+/*============================================================================
+ * Main polling routine.
+ * This routine is repeatedly called by the WANPIPE 'thread' to allow for
+ * time-dependent housekeeping work.
+ *
+ * Notes:
+ * 1. This routine may be called on interrupt context with all interrupts
+ *    enabled. Beware!
+ */
+static void wpp_poll (sdla_t* card)
+{
+	switch(card->wandev.state)
+	{
+	case WAN_CONNECTED:
+		poll_active(card);
+		break;
+
+	case WAN_CONNECTING:
+		poll_connecting(card);
+		break;
+
+	case WAN_DISCONNECTED:
+		poll_disconnected(card);
+		break;
+	}
+}
+
+/*============================================================================
+ * Monitor active link phase.
+ */
+static void poll_active (sdla_t* card)
+{
+	ppp_flags_t* flags = card->flags;
+
+	if (flags->disc_cause & 0x03)
+	{
+		wanpipe_set_state(card, WAN_DISCONNECTED);
+		show_disc_cause(card, flags->disc_cause);
+	}
+}
+
+/*============================================================================
+ * Monitor link establishment phase.
+ * o if connection timed out, disconnect the link.
+ */
+static void poll_connecting (sdla_t* card)
+{
+	ppp_flags_t* flags = card->flags;
+
+	if (flags->lcp_state == 0x09)
+	{
+		wanpipe_set_state(card, WAN_CONNECTED);
+	}
+	else if (flags->disc_cause & 0x03)
+	{
+		wanpipe_set_state(card, WAN_DISCONNECTED);
+		show_disc_cause(card, flags->disc_cause);
+	}
+}
+
+/*============================================================================
+ * Monitor physical link disconnected phase.
+ *  o if interface is up and the hold-down timeout has expired, then retry
+ *    connection.
+ */
+static void poll_disconnected (sdla_t* card)
+{
+	struct device* dev = card->wandev.dev;
+
+	if (dev && dev->start &&
+	    ((jiffies - card->state_tick) > HOLD_DOWN_TIME))
+	{
+		wanpipe_set_state(card, WAN_CONNECTING);
+		ppp_comm_enable(card);
+	}
+}
+
+/****** Miscellaneous Functions *********************************************/
+
+/*============================================================================
+ * Configure S502 adapter.
+ */
+static int config502 (sdla_t* card)
+{
+	ppp502_conf_t cfg;
+
+	/* Prepare PPP configuration structure */
+	memset(&cfg, 0, sizeof(ppp502_conf_t));
+
+	if (card->wandev.clocking)
+		cfg.line_speed = bps_to_speed_code(card->wandev.bps)
+	;
+	cfg.txbuf_num		= 4;
+	cfg.mtu_local		= card->wandev.mtu;
+	cfg.mtu_remote		= card->wandev.mtu;
+	cfg.restart_tmr		= 30;
+	cfg.auth_rsrt_tmr	= 30;
+	cfg.auth_wait_tmr	= 300;
+	cfg.mdm_fail_tmr	= 5;
+	cfg.dtr_drop_tmr	= 1;
+	cfg.connect_tmout	= 900;
+	cfg.conf_retry		= 10;
+	cfg.term_retry		= 2;
+	cfg.fail_retry		= 5;
+	cfg.auth_retry		= 10;
+	cfg.ip_options		= 0x80;
+	cfg.ipx_options		= 0xA0;
+/*
+	cfg.ip_local		= dev->pa_addr;
+	cfg.ip_remote		= dev->pa_dstaddr;
+*/
+	return ppp_configure(card, &cfg);
+}
+
+/*============================================================================
+ * Configure S508 adapter.
+ */
+static int config508 (sdla_t* card)
+{
+	ppp508_conf_t cfg;
+
+	/* Prepare PPP configuration structure */
+	memset(&cfg, 0, sizeof(ppp508_conf_t));
+
+	if (card->wandev.clocking)
+		cfg.line_speed = card->wandev.bps
+	;
+	if (card->wandev.interface == WANOPT_RS232)
+		cfg.conf_flags |= 0x0020;
+	;
+	cfg.txbuf_percent	= 60;	/* % of Tx bufs */
+	cfg.mtu_local		= card->wandev.mtu;
+	cfg.mtu_remote		= card->wandev.mtu;
+	cfg.restart_tmr		= 30;
+	cfg.auth_rsrt_tmr	= 30;
+	cfg.auth_wait_tmr	= 300;
+	cfg.mdm_fail_tmr	= 5;
+	cfg.dtr_drop_tmr	= 1;
+	cfg.connect_tmout	= 900;
+	cfg.conf_retry		= 10;
+	cfg.term_retry		= 2;
+	cfg.fail_retry		= 5;
+	cfg.auth_retry		= 10;
+	cfg.ip_options		= 0x80;
+	cfg.ipx_options		= 0xA0;
+/*
+	cfg.ip_local		= dev->pa_addr;
+	cfg.ip_remote		= dev->pa_dstaddr;
+*/
+	return ppp_configure(card, &cfg);
+}
+
+/*============================================================================
+ * Show disconnection cause.
+ */
+static void show_disc_cause (sdla_t* card, unsigned cause)
+{
+	if (cause & 0x0002) printk(KERN_INFO
+		"%s: link terminated by peer\n", card->devname)
+	;
+	else if (cause & 0x0004) printk(KERN_INFO
+		"%s: link terminated by user\n", card->devname)
+	;
+	else if (cause & 0x0008) printk(KERN_INFO
+		"%s: authentication failed\n", card->devname)
+	;
+	else if (cause & 0x0010) printk(KERN_INFO
+		"%s: authentication protocol negotiation failed\n",
+		card->devname)
+	;
+	else if (cause & 0x0020) printk(KERN_INFO
+		"%s: peer's request for authentication rejected\n",
+		card->devname)
+	;
+	else if (cause & 0x0040) printk(KERN_INFO
+		"%s: MRU option rejected by peer\n", card->devname)
+	;
+	else if (cause & 0x0080) printk(KERN_INFO
+		"%s: peer's MRU was too small\n", card->devname)
+	;
+	else if (cause & 0x0100) printk(KERN_INFO
+		"%s: failed to negotiate peer's LCP options\n",
+		card->devname)
+	;
+	else if (cause & 0x0200) printk(KERN_INFO
+		"%s: failed to negotiate peer's IPCP options\n",
+		card->devname)
+	;
+	else if (cause & 0x0400) printk(KERN_INFO
+		"%s: failed to negotiate peer's IPXCP options\n",
+		card->devname)
+	;
+}
+
+/*============================================================================
+ * Convert line speed in bps to a number used by S502 code.
+ */
+static unsigned char bps_to_speed_code (unsigned long bps)
+{
+	unsigned char	number;
+
+	if (bps <= 1200)        number = 0x01 ;
+	else if (bps <= 2400)   number = 0x02;
+	else if (bps <= 4800)   number = 0x03;
+	else if (bps <= 9600)   number = 0x04;
+	else if (bps <= 19200)  number = 0x05;
+	else if (bps <= 38400)  number = 0x06;
+	else if (bps <= 45000)  number = 0x07;
+	else if (bps <= 56000)  number = 0x08;
+	else if (bps <= 64000)  number = 0x09;
+	else if (bps <= 74000)  number = 0x0A;
+	else if (bps <= 112000) number = 0x0B;
+	else if (bps <= 128000) number = 0x0C;
+	else number = 0x0D;
+
+	return number;
+}
+
+/****** End *****************************************************************/
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c
--- v2.1.24/linux/drivers/net/sdla_x25.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/sdla_x25.c	Sun Feb  2 16:43:19 1997
@@ -0,0 +1,1961 @@
+/*****************************************************************************
+* sdla_x25.c	WANPIPE(tm) Multiprotocol WAN Link Driver.  X.25 module.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Jan 07, 1997	Gene Kozin	Initial version.
+*****************************************************************************/
+
+#if	!defined(__KERNEL__) || !defined(MODULE)
+#error	This code MUST be compiled as a kernel module!
+#endif
+
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/router.h>	/* WAN router definitions */
+#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
+#include <asm/byteorder.h>	/* htons(), etc. */
+
+#define	_GNUC_
+#include <linux/sdla_x25.h>	/* X.25 firmware API definitions */
+
+/****** Defines & Macros ****************************************************/
+
+#define	CMD_OK		0		/* normal firmware return code */
+#define	CMD_TIMEOUT	0xFF		/* firmware command timed out */
+#define	MAX_CMD_RETRY	10		/* max number of firmware retries */
+
+#define	X25_CHAN_MTU	4096		/* unfragmented logical channel MTU */
+#define	X25_HRDHDR_SZ	6		/* max encapsulation header size */
+#define	X25_CONCT_TMOUT	(90*HZ)		/* link connection timeout */
+#define	X25_RECON_TMOUT	(10*HZ)		/* link connection timeout */
+#define	CONNECT_TIMEOUT	(90*HZ)		/* link connection timeout */
+#define	HOLD_DOWN_TIME	(30*HZ)		/* link hold down time */
+
+/****** Data Structures *****************************************************/
+
+/* This is an extention of the 'struct device' we create for each network
+ * interface to keep the rest of X.25 channel-specific data.
+ */
+typedef struct x25_channel
+{
+	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
+	char addr[WAN_ADDRESS_SZ+1];	/* media address, ASCIIZ */
+	unsigned lcn;			/* logical channel number */
+	unsigned tx_pkt_size;
+	unsigned short protocol;	/* ethertype, 0 - multiplexed */
+	char svc;			/* 0 - permanent, 1 - switched */
+	char state;			/* channel state */
+	char drop_sequence;		/* mark sequence for dropping */
+	unsigned long state_tick;	/* time of the last state change */
+	unsigned idle_timeout;		/* sec, before disconnecting */
+	unsigned hold_timeout;		/* sec, before re-connecting */
+	struct sk_buff* rx_skb;		/* receive socket buffer */
+	struct sk_buff* tx_skb;		/* transmit socket buffer */
+	sdla_t* card;			/* -> owner */
+	int ch_idx;
+	struct enet_statistics ifstats;	/* interface statistics */
+} x25_channel_t;
+
+typedef struct x25_call_info
+{
+	char dest[17];			/* ASCIIZ destination address */
+	char src[17];			/* ASCIIZ source address */
+	char nuser;			/* number of user data bytes */
+	unsigned char user[127];	/* user data */
+	char nfacil;			/* number of facilities */
+	struct
+	{
+		unsigned char code;
+		unsigned char parm;
+	} facil[64];			/* facilities */
+} x25_call_info_t;
+
+/****** Function Prototypes *************************************************/
+
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int update (wan_device_t* wandev);
+static int new_if (wan_device_t* wandev, struct device* dev,
+	wanif_conf_t* conf);
+static int del_if (wan_device_t* wandev, struct device* dev);
+
+/* Network device interface */
+static int if_init   (struct device* dev);
+static int if_open   (struct device* dev);
+static int if_close  (struct device* dev);
+static int if_header (struct sk_buff* skb, struct device* dev,
+	unsigned short type, void* daddr, void* saddr, unsigned len);
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+	struct sk_buff* skb);
+static int if_send (struct sk_buff* skb, struct device* dev);
+static struct enet_statistics* if_stats (struct device* dev);
+
+/* Interrupt handlers */
+static void wpx_isr	(sdla_t* card);
+static void rx_intr	(sdla_t* card);
+static void tx_intr	(sdla_t* card);
+static void status_intr	(sdla_t* card);
+static void event_intr	(sdla_t* card);
+static void spur_intr	(sdla_t* card);
+
+/* Background polling routines */
+static void wpx_poll (sdla_t* card);
+static void poll_disconnected (sdla_t* card);
+static void poll_connecting (sdla_t* card);
+static void poll_active (sdla_t* card);
+
+/* X.25 firmware interface functions */
+static int x25_get_version (sdla_t* card, char* str);
+static int x25_configure (sdla_t* card, TX25Config* conf);
+static int x25_set_intr_mode (sdla_t* card, int mode);
+static int x25_close_hdlc (sdla_t* card);
+static int x25_open_hdlc (sdla_t* card);
+static int x25_setup_hdlc (sdla_t* card);
+static int x25_set_dtr (sdla_t* card, int dtr);
+static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan);
+static int x25_place_call (sdla_t* card, x25_channel_t* chan);
+static int x25_accept_call (sdla_t* card, int lcn, int qdm);
+static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn);
+static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf);
+static int x25_fetch_events (sdla_t* card);
+static int x25_error (sdla_t* card, int err, int cmd, int lcn);
+
+/* X.25 asynchronous event handlers */
+static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
+
+/* Miscellaneous functions */
+static int connect (sdla_t* card);
+static int disconnect (sdla_t* card);
+static struct device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn);
+static int chan_connect (struct device* dev);
+static int chan_disc (struct device* dev);
+static void set_chan_state (struct device* dev, int state);
+static int chan_send (struct device* dev, struct sk_buff* skb);
+static unsigned char bps_to_speed_code (unsigned long bps);
+static unsigned int dec_to_uint (unsigned char* str, int len);
+static unsigned int hex_to_uint (unsigned char* str, int len);
+static void parse_call_info (unsigned char* str, x25_call_info_t* info);
+
+/****** Global Data **********************************************************
+ * Note: All data must be explicitly initialized!!!
+ */
+
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * X.25 Protocol Initialization routine.
+ *
+ * This routine is called by the main WANPIPE module during setup.  At this
+ * point adapter is completely initialized and X.25 firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure.
+ */
+int wpx_init (sdla_t* card, wandev_conf_t* conf)
+{
+	union
+	{
+		char str[80];
+		TX25Config cfg;
+	} u;
+
+	/* Verify configuration ID */
+	if (conf->config_id != WANCONFIG_X25)
+	{
+		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+			card->devname, conf->config_id)
+		;
+		return -EINVAL;
+	}
+
+	/* Initialize protocol-specific fields */
+	card->mbox  = (void*)(card->hw.dpmbase + X25_MBOX_OFFS);
+	card->rxmb  = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS);
+	card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS);
+
+	/* Read firmware version.  Note that when adapter initializes, it
+	 * clears the mailbox, so it may appear that the first command was
+	 * executed successfully when in fact it was merely erased. To work
+	 * around this, we execute the first command twice.
+	 */
+	if (x25_get_version(card, NULL) || x25_get_version(card, u.str))
+		return -EIO
+	;
+	printk(KERN_INFO "%s: running X.25 firmware v%s\n",
+		card->devname, u.str)
+	;
+
+	/* Configure adapter. Here we set resonable defaults, then parse
+	 * device configuration structure and set configuration options.
+	 * Most configuration options are verified and corrected (if
+	 * necessary) since we can't rely on the adapter to do so and don't
+	 * want it to fail either.
+	 */
+	memset(&u.cfg, 0, sizeof(u.cfg));
+	u.cfg.t1		= 3;
+	u.cfg.n2		= 10;
+	u.cfg.autoHdlc		= 1;		/* automatic HDLC connection */
+	u.cfg.hdlcWindow	= 7;
+	u.cfg.pktWindow		= 2;
+	u.cfg.station		= 1;		/* DTE */
+	u.cfg.options		= 0x0010;	/* disable D-bit pragmatics */
+	u.cfg.ccittCompat	= 1988;
+	u.cfg.t10t20		= 30;
+	u.cfg.t11t21		= 30;
+	u.cfg.t12t22		= 30;
+	u.cfg.t13t23		= 30;
+	u.cfg.t16t26		= 30;
+	u.cfg.t28		= 30;
+	u.cfg.r10r20		= 5;
+	u.cfg.r12r22		= 5;
+	u.cfg.r13r23		= 5;
+
+	if (conf->clocking != WANOPT_EXTERNAL)
+		u.cfg.baudRate = bps_to_speed_code(conf->bps)
+	;
+	if (conf->station != WANOPT_DTE)
+	{
+		u.cfg.station = 0;		/* DCE mode */
+	}
+
+	/* adjust MTU */
+	if (!conf->mtu || (conf->mtu >= 1024))
+		card->wandev.mtu = 1024
+	;
+	else if (conf->mtu >= 512)
+		card->wandev.mtu = 512
+	;
+	else if (conf->mtu >= 256)
+		card->wandev.mtu = 256
+	;
+	else if (conf->mtu >= 128)
+		card->wandev.mtu = 128
+	;
+	else conf->mtu = 64;
+	u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu;
+
+	if (conf->u.x25.hi_pvc)
+	{
+		card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095);
+		card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc);
+	}
+	if (conf->u.x25.hi_svc)
+	{
+		card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095);
+		card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc);
+	}
+	u.cfg.loPVC	  = card->u.x.lo_pvc;
+	u.cfg.hiPVC	  = card->u.x.hi_pvc;
+	u.cfg.loTwoWaySVC = card->u.x.lo_svc;
+	u.cfg.hiTwoWaySVC = card->u.x.hi_svc;
+
+	if (conf->u.x25.hdlc_window)
+		u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7)
+	;
+	if (conf->u.x25.pkt_window)
+		u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7)
+	;
+	if (conf->u.x25.t1)
+		u.cfg.t1 = min(conf->u.x25.t1, 30)
+	;
+	u.cfg.t2 = min(conf->u.x25.t2, 29);
+	u.cfg.t4 = min(conf->u.x25.t4, 240);
+	if (conf->u.x25.n2)
+		u.cfg.n2 = min(conf->u.x25.n2, 30)
+	;
+	if (conf->u.x25.ccitt_compat)
+		u.cfg.ccittCompat = conf->u.x25.ccitt_compat
+	;
+
+	/* initialize adapter */
+	if ((x25_configure(card, &u.cfg) != CMD_OK) ||
+	    (x25_close_hdlc(card) != CMD_OK) ||		/* close HDLC link */
+	    (x25_set_dtr(card, 0) != CMD_OK))		/* drop DTR */
+		return -EIO
+	;
+
+	/* Initialize protocol-specific fields of adapter data space */
+	card->wandev.bps	= conf->bps;
+	card->wandev.interface	= conf->interface;
+	card->wandev.clocking	= conf->clocking;
+	card->wandev.station	= conf->station;
+	card->isr		= &wpx_isr;
+	card->poll		= &wpx_poll;
+	card->wandev.update	= &update;
+	card->wandev.new_if	= &new_if;
+	card->wandev.del_if	= &del_if;
+	card->wandev.state	= WAN_DISCONNECTED;
+	return 0;
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Update device status & statistics.
+ */
+static int update (wan_device_t* wandev)
+{
+/*
+	sdla_t* card = wandev->private;
+*/
+	return 0;
+}
+
+/*============================================================================
+ * Create new logical channel.
+ * This routine is called by the router when ROUTER_IFNEW IOCTL is being
+ * handled.
+ * o parse media- and hardware-specific configuration
+ * o make sure that a new channel can be created
+ * o allocate resources, if necessary
+ * o prepare network device structure for registaration.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure (channel will not be created)
+ */
+static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
+{
+	sdla_t* card = wandev->private;
+	x25_channel_t* chan;
+	int err = 0;
+
+	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ))
+	{
+		printk(KERN_INFO "%s: invalid interface name!\n",
+			card->devname)
+		;
+		return -EINVAL;
+	}
+
+	/* allocate and initialize private data */
+	chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL);
+	if (chan == NULL)
+		return -ENOMEM
+	;
+	memset(chan, 0, sizeof(x25_channel_t));
+	strcpy(chan->name, conf->name);
+	chan->card = card;
+
+	/* verify media address */
+	if (conf->addr[0] == '@')		/* SVC */
+	{
+		chan->svc = 1;
+		chan->protocol = ETH_P_IP;
+		strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
+	}
+	else if (is_digit(conf->addr[0]))	/* PVC */
+	{
+		int lcn = dec_to_uint(conf->addr, 0);
+
+		if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc))
+		{
+			chan->lcn = lcn;
+		}
+		else
+		{
+			printk(KERN_ERR
+				"%s: PVC %u is out of range on interface %s!\n",
+				wandev->name, lcn, chan->name)
+			;
+			err = -EINVAL;
+		}
+	}
+	else
+	{
+		printk(KERN_ERR
+			"%s: invalid media address on interface %s!\n",
+			wandev->name, chan->name)
+		;
+		err = -EINVAL;
+	}
+	if (err)
+	{
+		kfree(chan);
+		return err;
+	}
+
+	/* prepare network device data space for registration */
+	dev->name = chan->name;
+	dev->init = &if_init;
+	dev->priv = chan;
+	return 0;
+}
+
+/*============================================================================
+ * Delete logical channel.
+ */
+static int del_if (wan_device_t* wandev, struct device* dev)
+{
+	if (dev->priv)
+	{
+		kfree(dev->priv);
+		dev->priv = NULL;
+	}
+	return 0;
+}
+
+/****** Network Device Interface ********************************************/
+
+/*============================================================================
+ * Initialize Linux network interface.
+ *
+ * This routine is called only once for each interface, during Linux network
+ * interface registration.  Returning anything but zero will fail interface
+ * registration.
+ */
+static int if_init (struct device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	wan_device_t* wandev = &card->wandev;
+	int i;
+
+	/* Initialize device driver entry points */
+	dev->open		= &if_open;
+	dev->stop		= &if_close;
+	dev->hard_header	= &if_header;
+	dev->rebuild_header	= &if_rebuild_hdr;
+	dev->hard_start_xmit	= &if_send;
+	dev->get_stats		= &if_stats;
+
+	/* Initialize media-specific parameters */
+	dev->family		= AF_INET;	/* address family */
+	dev->type		= 30;		/* ARP h/w type */
+	dev->mtu		= X25_CHAN_MTU;
+	dev->hard_header_len	= X25_HRDHDR_SZ; /* media header length */
+	dev->addr_len		= 2;		/* hardware address length */
+	if (!chan->svc)
+		*(unsigned short*)dev->dev_addr = htons(chan->lcn)
+	;
+
+	/* Initialize hardware parameters (just for reference) */
+	dev->irq	= wandev->irq;
+	dev->dma	= wandev->dma;
+	dev->base_addr	= wandev->ioport;
+	dev->mem_start	= wandev->maddr;
+	dev->mem_end	= wandev->maddr + wandev->msize - 1;
+
+	/* Initialize socket buffers */
+	for (i = 0; i < DEV_NUMBUFFS; ++i)
+		skb_queue_head_init(&dev->buffs[i])
+	;
+	set_chan_state(dev, WAN_DISCONNECTED);
+	return 0;
+}
+
+/*============================================================================
+ * Open network interface.
+ * o prevent module from unloading by incrementing use count
+ * o if link is disconnected then initiate connection
+ *
+ * Return 0 if O.k. or errno.
+ */
+static int if_open (struct device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+
+	if (dev->start)
+		return -EBUSY		/* only one open is allowed */
+	;
+	if (set_bit(0, (void*)&card->wandev.critical))
+		return -EAGAIN;
+	;
+
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+	wanpipe_open(card);
+
+	/* If this is the first open, initiate physical connection */
+	if (card->open_cnt == 1)
+		connect(card)
+	;
+	card->wandev.critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Close network interface.
+ * o reset flags.
+ * o if there's no more open channels then disconnect physical link.
+ */
+static int if_close (struct device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+
+	if (set_bit(0, (void*)&card->wandev.critical))
+		return -EAGAIN;
+	;
+	dev->start = 0;
+	if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING))
+		chan_disc(dev)
+	;
+	wanpipe_close(card);
+
+	/* If this is the last close, disconnect physical link */
+	if (!card->open_cnt)
+		disconnect(card)
+	;
+	card->wandev.critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Build media header.
+ * o encapsulate packet according to encapsulation type.
+ *
+ * The trick here is to put packet type (Ethertype) into 'protocol' field of
+ * the socket buffer, so that we don't forget it.  If encapsulation fails,
+ * set skb->protocol to 0 and discard packet later.
+ *
+ * Return:	media header length.
+ */
+static int if_header (struct sk_buff* skb, struct device* dev,
+	unsigned short type, void* daddr, void* saddr, unsigned len)
+{
+	x25_channel_t* chan = dev->priv;
+	int hdr_len = dev->hard_header_len;
+
+	skb->protocol = type;
+	if (!chan->protocol)
+	{
+		hdr_len = wan_encapsulate(skb, dev);
+		if (hdr_len < 0)
+		{
+			hdr_len = 0;
+			skb->protocol = 0;
+		}
+	}
+	return hdr_len;
+}
+
+/*============================================================================
+ * Re-build media header.
+ *
+ * Return:	1	physical address resolved.
+ *		0	physical address not resolved
+ */
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+			   struct sk_buff* skb)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+
+	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
+		card->devname, dev->name)
+	;
+	return 1;
+}
+
+/*============================================================================
+ * Send a packet on a network interface.
+ * o set tbusy flag (marks start of the transmission).
+ * o check link state. If link is not up, then drop the packet.
+ * o check channel status. If it's down then initiate a call.
+ * o pass a packet to corresponding WAN device.
+ * o free socket buffer
+ *
+ * Return:	0	complete (socket buffer must be freed)
+ *		non-0	packet may be re-transmitted (tbusy must be set)
+ *
+ * Notes:
+ * 1. This routine is called either by the protocol stack or by the "net
+ *    bottom half" (with interrupts enabled).
+ * 2. Setting tbusy flag will inhibit further transmit requests from the
+ *    protocol stack and can be used for flow control with protocol layer.
+ */
+static int if_send (struct sk_buff* skb, struct device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	int retry = 0, queued = 0;
+
+	if (skb == NULL)
+	{
+		/* If we get here, some higher layer thinks we've missed a
+		 * tx-done interrupt.
+		 */
+#ifdef _DEBUG_
+		printk(KERN_INFO "%s: interface %s got kicked!\n",
+			card->devname, dev->name)
+		;
+#endif
+		dev_tint(dev);
+		return 0;
+	}
+
+	if (set_bit(0, (void*)&card->wandev.critical))
+	{
+#ifdef _DEBUG_
+		printk(KERN_INFO "%s: if_send() hit critical section!\n",
+			card->devname)
+		;
+#endif
+		return 1;
+	}
+
+	if (set_bit(0, (void*)&dev->tbusy))
+	{
+#ifdef _DEBUG_
+		printk(KERN_INFO "%s: Tx collision on interface %s!\n",
+			card->devname, dev->name)
+		;
+#endif
+		++chan->ifstats.collisions;
+		retry = 1;
+	}
+	else if (chan->protocol && (chan->protocol != skb->protocol))
+	{
+		printk(KERN_INFO
+			"%s: unsupported Ethertype 0x%04X on interface %s!\n",
+			card->devname, skb->protocol, dev->name)
+		;
+		++chan->ifstats.tx_errors;
+	}
+	else if (card->wandev.state != WAN_CONNECTED)
+		++chan->ifstats.tx_dropped
+	;
+	else switch (chan->state)
+	{
+	case WAN_CONNECTED:
+		dev->trans_start = jiffies;
+		queued = chan_send(dev, skb);
+		if (queued) chan->tx_skb = skb;
+		break;
+
+	case WAN_DISCONNECTED:
+		/* Try to establish connection. If succeded, then start
+		 * transmission, else drop a packet.
+		 */
+		if (chan_connect(dev) == 0)
+		{
+			dev->trans_start = jiffies;
+			queued = chan_send(dev, skb);
+			if (queued) chan->tx_skb = skb;
+			break;
+		}
+		/* else fall through */
+
+	default:
+		++chan->ifstats.tx_dropped;
+	}
+
+	if (!retry && !queued)
+	{
+		dev_kfree_skb(skb, FREE_WRITE);
+		dev->tbusy = 0;
+	}
+	card->wandev.critical = 0;
+	return retry;
+}
+
+/*============================================================================
+ * Get ethernet-style interface statistics.
+ * Return a pointer to struct enet_statistics.
+ */
+static struct enet_statistics* if_stats (struct device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+
+	return &chan->ifstats;
+}
+
+/****** Interrupt Handlers **************************************************/
+
+/*============================================================================
+ * X.25 Interrupt Service Routine.
+ */
+static void wpx_isr (sdla_t* card)
+{
+	TX25Status* status = card->flags;
+
+	switch (status->iflags)
+	{
+	case 0x01:		/* receive interrupt */
+		rx_intr(card);
+		break;
+
+	case 0x02:		/* transmit interrupt */
+		tx_intr(card);
+		break;
+
+	case 0x04:		/* modem status interrupt */
+		status_intr(card);
+		break;
+
+	case 0x10:		/* network event interrupt */
+		event_intr(card);
+		break;
+
+	default:		/* unwanter interrupt */
+		spur_intr(card);
+	}
+	status->iflags = 0;	/* clear interrupt condition */
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ * This routine handles fragmented IP packets using M-bit according to the
+ * RFC1356.
+ * o map ligical channel number to network interface.
+ * o allocate socket buffer or append received packet to the existing one.
+ * o if M-bit is reset (i.e. it's the last packet in a sequence) then 
+ *   decapsulate packet and pass socket buffer to the protocol stack.
+ *
+ * Notes:
+ * 1. When allocating a socket buffer, if M-bit is set then more data is
+ *    comming and we have to allocate buffer for the maximum IP packet size
+ *    expected on this channel.
+ * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
+ *    socket buffers available) the whole packet sequence must be discarded.
+ */
+static void rx_intr (sdla_t* card)
+{
+	TX25Mbox* rxmb = card->rxmb;
+	unsigned lcn = rxmb->cmd.lcn;		/* logical channel number */
+	unsigned len = rxmb->cmd.length;	/* packet length */
+	unsigned qdm = rxmb->cmd.qdm;		/* Q,D and M bits */
+	wan_device_t* wandev = &card->wandev;
+	struct device* dev = get_dev_by_lcn(wandev, lcn);
+	x25_channel_t* chan;
+	struct sk_buff* skb;
+	void* bufptr;
+
+	if (dev == NULL)
+	{
+		/* Invalid channel, discard packet */
+		printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",
+			card->devname, lcn)
+		;
+		return;
+	}
+
+	chan = dev->priv;
+	if (chan->drop_sequence)
+	{
+		if (!(qdm & 0x01)) chan->drop_sequence = 0;
+		return;
+	}
+
+	skb = chan->rx_skb;
+	if (skb == NULL)
+	{
+		/* Allocate new socket buffer */
+		int bufsize = (qdm & 0x01) ? dev->mtu : len;
+
+		skb = dev_alloc_skb(bufsize + dev->hard_header_len);
+		if (skb == NULL)
+		{
+			printk(KERN_INFO "%s: no socket buffers available!\n",
+				card->devname)
+			;
+			chan->drop_sequence = 1;	/* set flag */
+			++chan->ifstats.rx_dropped;
+			return;
+		}
+		skb->dev = dev;
+		skb->protocol = htons(chan->protocol);
+		chan->rx_skb = skb;
+	}
+
+	if (skb_tailroom(skb) < len)
+	{
+		/* No room for the packet. Call off the whole thing! */
+		dev_kfree_skb(skb, FREE_READ);
+		chan->rx_skb = NULL;
+		if (qdm & 0x01) chan->drop_sequence = 1;
+
+		printk(KERN_INFO "%s: unexpectedly long packet sequence "
+			"on interface %s!\n", card->devname, dev->name)
+		;
+		++chan->ifstats.rx_length_errors;
+		return;
+	}
+
+	/* Append packet to the socket buffer */
+	bufptr = skb_put(skb, len);
+	memcpy(bufptr, rxmb->data, len);
+	if (qdm & 0x01) return;		/* more data is comming */
+
+	dev->last_rx = jiffies;		/* timestamp */
+	chan->rx_skb = NULL;		/* dequeue packet */
+
+	/* Decapsulate packet, if necessary */
+	if (!skb->protocol && !wan_type_trans(skb, dev))
+	{
+		/* can't decapsulate packet */
+		dev_kfree_skb(skb, FREE_READ);
+		++chan->ifstats.rx_errors;
+	}
+	else
+	{
+		netif_rx(skb);
+		++chan->ifstats.rx_packets;
+	}
+}
+
+/*============================================================================
+ * Transmit interrupt handler.
+ *	o Release socket buffer
+ *	o Clear 'tbusy' flag
+ */
+static void tx_intr (sdla_t* card)
+{
+}
+
+/*============================================================================
+ * Modem status interrupt handler.
+ */
+static void status_intr (sdla_t* card)
+{
+}
+
+/*============================================================================
+ * Network event interrupt handler.
+ */
+static void event_intr (sdla_t* card)
+{
+}
+
+/*============================================================================
+ * Spurious interrupt handler.
+ * o print a warning
+ * o 
+ * If number of spurious interrupts exceeded some limit, then ???
+ */
+static void spur_intr (sdla_t* card)
+{
+	printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
+}
+
+/****** Background Polling Routines  ****************************************/
+
+/*============================================================================
+ * Main polling routine.
+ * This routine is repeatedly called by the WANPIPE 'thead' to allow for
+ * time-dependent housekeeping work.
+ *
+ * Notes:
+ * 1. This routine may be called on interrupt context with all interrupts
+ *    enabled. Beware!
+ */
+static void wpx_poll (sdla_t* card)
+{
+	switch(card->wandev.state)
+	{
+	case WAN_CONNECTED:
+		poll_active(card);
+		break;
+
+	case WAN_CONNECTING:
+		poll_connecting(card);
+		break;
+
+	case WAN_DISCONNECTED:
+		poll_disconnected(card);
+	}
+}
+
+/*============================================================================
+ * Handle physical link establishment phase.
+ * o if connection timed out, disconnect the link.
+ */
+static void poll_connecting (sdla_t* card)
+{
+	TX25Status* status = card->flags;
+
+	if (status->gflags & X25_HDLC_ABM)
+	{
+		wanpipe_set_state(card, WAN_CONNECTED);
+		x25_set_intr_mode(card, 0x81);	/* enable Rx interrupts */
+	}
+	else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT)
+	    disconnect(card)
+	;
+}
+
+/*============================================================================
+ * Handle physical link disconnected phase.
+ * o if hold-down timeout has expired and there are open interfaces, connect
+ *   link.
+ */
+static void poll_disconnected (sdla_t* card)
+{
+	if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME))
+		connect(card)
+	;
+}
+
+/*============================================================================
+ * Handle active link phase.
+ * o fetch X.25 asynchronous events.
+ * o kick off transmission on all interfaces.
+ */
+static void poll_active (sdla_t* card)
+{
+	struct device* dev;
+
+	/* Fetch X.25 asynchronous events */
+	x25_fetch_events(card);
+
+	for (dev = card->wandev.dev; dev; dev = dev->slave)
+	{
+		x25_channel_t* chan = dev->priv;
+		struct sk_buff* skb = chan->tx_skb;
+
+		/* If there is a packet queued for transmission then kick
+		 * the channel's send routine. When transmission is complete
+		 * or if error has occured, release socket buffer and reset
+		 * 'tbusy' flag.
+		 */
+		if (skb && (chan_send(dev, skb) == 0))
+		{
+			chan->tx_skb = NULL;
+			dev->tbusy = 0;
+			dev_kfree_skb(skb, FREE_WRITE);
+		}
+
+		/* If SVC has been idle long enough, close virtual circuit */
+
+/*
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+
+		restore_flags(flags);
+*/
+	}
+}
+
+/****** SDLA Firmware-Specific Functions *************************************
+ * Almost all X.25 commands can unexpetedly fail due to so called 'X.25
+ * asynchronous events' such as restart, interrupt, incomming call request,
+ * call clear request, etc.  They can't be ignored and have to be delt with
+ * immediately.  To tackle with this problem we execute each interface command
+ * in a loop until good return code is received or maximum number of retries
+ * is reached.  Each interface command returns non-zero return code, an
+ * asynchronous event/error handler x25_error() is called.
+ */
+
+/*============================================================================
+ * Read X.25 firmware version.
+ *	Put code version as ASCII string in str. 
+ */
+static int x25_get_version (sdla_t* card, char* str)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_READ_CODE_VERSION;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_READ_CODE_VERSION, 0))
+	;
+
+	if (!err && str)
+	{
+		int len = mbox->cmd.length;
+
+		memcpy(str, mbox->data, len);
+		str[len] = '\0';
+	}
+	return err;
+}
+
+/*============================================================================
+ * Configure adapter.
+ */
+static int x25_configure (sdla_t* card, TX25Config* conf)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		memcpy(mbox->data, (void*)conf, sizeof(TX25Config));
+		mbox->cmd.length  = sizeof(TX25Config);
+		mbox->cmd.command = X25_SET_CONFIGURATION;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_SET_CONFIGURATION, 0))
+	;
+	return err;
+}
+
+/*============================================================================
+ * Close HDLC link.
+ */
+static int x25_close_hdlc (sdla_t* card)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_HDLC_LINK_CLOSE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_HDLC_LINK_CLOSE, 0))
+	;
+	return err;
+}
+
+/*============================================================================
+ * Open HDLC link.
+ */
+static int x25_open_hdlc (sdla_t* card)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_HDLC_LINK_OPEN;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_HDLC_LINK_OPEN, 0))
+	;
+	return err;
+}
+
+/*============================================================================
+ * Setup HDLC link.
+ */
+static int x25_setup_hdlc (sdla_t* card)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_HDLC_LINK_SETUP;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_HDLC_LINK_SETUP, 0))
+	;
+	return err;
+}
+
+/*============================================================================
+ * Set (raise/drop) DTR.
+ */
+static int x25_set_dtr (sdla_t* card, int dtr)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->data[0] = 0;
+		mbox->data[2] = 0;
+		mbox->data[1] = dtr ? 0x02 : 0x01;
+		mbox->cmd.length  = 3;
+		mbox->cmd.command = X25_SET_GLOBAL_VARS;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_SET_GLOBAL_VARS, 0))
+	;
+	return err;
+}
+
+/*============================================================================
+ * Set interrupt mode.
+ */
+static int x25_set_intr_mode (sdla_t* card, int mode)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->data[0] = mode;
+		if (card->hw.fwid == SFID_X25_508)
+		{
+			mbox->data[1] = card->hw.irq;
+			mbox->cmd.length = 2;
+		}
+		else mbox->cmd.length  = 1;
+		mbox->cmd.command = X25_SET_INTERRUPT_MODE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_SET_INTERRUPT_MODE, 0))
+	;
+	return err;
+}
+
+/*============================================================================
+ * Read X.25 channel configuration.
+ */
+static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int lcn = chan->lcn;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.lcn     = lcn;
+		mbox->cmd.command = X25_READ_CHANNEL_CONFIG;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn))
+	;
+
+	if (!err)
+	{
+		TX25Status* status = card->flags;
+
+		/* calculate an offset into the array of status bytes */
+		if (card->u.x.hi_svc <= 255) 
+			chan->ch_idx = lcn - 1
+		;
+		else
+		{
+			int offset;
+
+			switch (mbox->data[0] && 0x1F)
+			{
+			case 0x01: offset = status->pvc_map; break;
+			case 0x03: offset = status->icc_map; break;
+			case 0x07: offset = status->twc_map; break;
+			case 0x0B: offset = status->ogc_map; break;
+			default: offset = 0;
+			}
+			chan->ch_idx = lcn - 1 - offset;
+		}
+
+		/* get actual transmit packet size on this channel */
+		switch(mbox->data[1] & 0x38)
+		{
+		case 0x00: chan->tx_pkt_size = 16; break;
+		case 0x08: chan->tx_pkt_size = 32; break;
+		case 0x10: chan->tx_pkt_size = 64; break;
+		case 0x18: chan->tx_pkt_size = 128; break;
+		case 0x20: chan->tx_pkt_size = 256; break;
+		case 0x28: chan->tx_pkt_size = 512; break;
+		case 0x30: chan->tx_pkt_size = 1024; break;
+		}
+		printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n",
+			card->devname, lcn, chan->tx_pkt_size)
+		;
+	}
+	return err;
+}
+
+/*============================================================================
+ * Place X.25 call.
+ */
+static int x25_place_call (sdla_t* card, x25_channel_t* chan)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+	char str[64];
+
+	sprintf(str, "-d%s -uCC", chan->addr);
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		strcpy(mbox->data, str);
+		mbox->cmd.length  = strlen(str);
+		mbox->cmd.command = X25_PLACE_CALL;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_PLACE_CALL, 0))
+	;
+	if (!err)
+	{
+		chan->lcn = mbox->cmd.lcn;
+		chan->protocol = ETH_P_IP;
+	}
+	return err;
+}
+
+/*============================================================================
+ * Accept X.25 call.
+ */
+static int x25_accept_call (sdla_t* card, int lcn, int qdm)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.lcn     = lcn;
+		mbox->cmd.qdm     = qdm;
+		mbox->cmd.command = X25_ACCEPT_CALL;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_ACCEPT_CALL, lcn))
+	;
+	return err;
+}
+
+/*============================================================================
+ * Clear X.25 call.
+ */
+static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.lcn     = lcn;
+		mbox->cmd.cause   = cause;
+		mbox->cmd.diagn   = diagn;
+		mbox->cmd.command = X25_CLEAR_CALL;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_CLEAR_CALL, lcn))
+	;
+	return err;
+}
+
+/*============================================================================
+ * Send X.25 data packet.
+ */
+static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		memcpy(mbox->data, buf, len);
+		mbox->cmd.length  = len;
+		mbox->cmd.lcn     = lcn;
+		mbox->cmd.qdm     = qdm;
+		mbox->cmd.command = X25_WRITE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_WRITE, lcn));
+	return err;
+}
+
+/*============================================================================
+ * Fetch X.25 asynchronous events.
+ */
+static int x25_fetch_events (sdla_t* card)
+{
+	TX25Status* status = card->flags;
+	TX25Mbox* mbox = card->mbox;
+	int err = 0;
+
+	if (status->gflags & 0x20)
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_IS_DATA_AVAILABLE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+ 		if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0);
+	}
+	return err;
+}
+
+/*============================================================================
+ * X.25 asynchronous event/error handler.
+ *	This routine is called each time interface command returns non-zero
+ *	return code to handle X.25 asynchronous events and common errors.
+ *	Return non-zero to repeat command or zero to cancel it.
+ *
+ * Notes:
+ * 1. This function may be called recursively, as handling some of the
+ *    asynchronous events (e.g. call request) requires execution of the
+ *    interface command(s) that, in turn, may also return asynchronous
+ *    events.  To avoid re-entrancy problems we copy mailbox to dynamically
+ *    allocated memory before processing events.
+ */
+static int x25_error (sdla_t* card, int err, int cmd, int lcn)
+{
+	int retry = 1;
+	unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length;
+	TX25Mbox* mb;
+
+	mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC);
+	if (mb == NULL)
+	{
+		printk(KERN_ERR "%s: x25_error() out of memory!\n",
+			card->devname)
+		;
+		return 0;
+	}
+	memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen);
+	switch (err)
+	{
+	case 0x40:	/* X.25 asynchronous packet was received */
+		mb->data[dlen] = '\0';
+		switch (mb->cmd.pktType & 0x7F)
+		{
+		case 0x30:		/* incomming call */
+			retry = incomming_call(card, cmd, lcn, mb);
+			break;
+
+		case 0x31:		/* connected */
+			retry = call_accepted(card, cmd, lcn, mb);
+			break;
+
+		case 0x02:		/* call clear request */
+			retry = call_cleared(card, cmd, lcn, mb);
+			break;
+
+		case 0x04:		/* reset request */
+			printk(KERN_INFO "%s: X.25 reset request on LCN %d! "
+				"Cause:0x%02X Diagn:0x%02X\n",
+				card->devname, mb->cmd.lcn, mb->cmd.cause,
+				mb->cmd.diagn)
+			;
+			break;
+
+		case 0x08:		/* restart request */
+			retry = restart_event(card, cmd, lcn, mb);
+			break;
+
+		default:
+			printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! "
+				"Cause:0x%02X Diagn:0x%02X\n",
+				card->devname, mb->cmd.pktType,
+				mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn)
+			;
+		}
+		break;
+
+	case 0x41:	/* X.25 protocol violation indication */
+		printk(KERN_INFO
+			"%s: X.25 protocol violation on LCN %d! "
+			"Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n",
+			card->devname, mb->cmd.lcn,
+			mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn)
+		;
+		break;
+
+	case 0x42:	/* X.25 timeout */
+		retry = timeout_event(card, cmd, lcn, mb);
+		break;
+
+	case 0x43:	/* X.25 retry limit exceeded */
+		printk(KERN_INFO
+			"%s: exceeded X.25 retry limit on LCN %d! "
+			"Packet:0x%02X Diagn:0x%02X\n", card->devname,
+			mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn)
+		;
+		break;
+
+	case 0x08:	/* modem failure */
+		printk(KERN_INFO "%s: modem failure!\n", card->devname);
+		break;
+
+	case 0x09:	/* N2 retry limit */
+		printk(KERN_INFO "%s: exceeded HDLC retry limit!\n",
+			card->devname)
+		;
+		break;
+
+	case 0x06:	/* unnumbered frame was received while in ABM */
+		printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n",
+			card->devname, mb->data[0])
+		;
+		break;
+
+	case CMD_TIMEOUT:
+		printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+			card->devname, cmd)
+		;
+		retry = 0;	/* abort command */
+		break;
+
+	default:
+		printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+			card->devname, cmd, err)
+		;
+		retry = 0;	/* abort command */
+	}
+	kfree(mb);
+	return retry;
+}
+
+/****** X.25 Asynchronous Event Handlers *************************************
+ * These functions are called by the x25_error() and should return 0, if
+ * the command resulting in the asynchronous event must be aborted.
+ */
+
+/*============================================================================
+ * Handle X.25 incomming call request.
+ *	RFC 1356 establishes the following rules:
+ *	1. The first octet in the Call User Data (CUD) field of the call
+ *	   request packet contains NLPID identifying protocol encapsulation.
+ *	2. Calls MUST NOT be accepted unless router supports requested
+ *	   protocol encapsulation.
+ *	3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when
+ *	   clearing a call because protocol encapsulation is not supported.
+ *	4. If an incomming call is received while a call request is pending
+ *	   (i.e. call collision has occured), the incomming call shall be
+ *	   rejected and call request shall be retried.
+ */
+static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+	wan_device_t* wandev = &card->wandev;
+	int new_lcn = mb->cmd.lcn;
+	struct device* dev = get_dev_by_lcn(wandev, new_lcn);
+	x25_channel_t* chan = NULL;
+	int accept = 0;		/* set to '1' if o.k. to accept call */
+	x25_call_info_t* info;
+
+	/* Make sure there is no call collision */
+	if (dev != NULL)
+	{
+		printk(KERN_INFO
+			"%s: X.25 incomming call collision on LCN %d!\n",
+			card->devname, new_lcn)
+		;
+		x25_clear_call(card, new_lcn, 0, 0);
+		return 1;
+	}
+
+	/* Make sure D bit is not set in call request */
+	if (mb->cmd.qdm & 0x02)
+	{
+		printk(KERN_INFO
+			"%s: X.25 incomming call on LCN %d with D-bit set!\n",
+			card->devname, new_lcn)
+		;
+		x25_clear_call(card, new_lcn, 0, 0);
+		return 1;
+	}
+
+	/* Parse call request data */
+	info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC);
+	if (info == NULL)
+	{
+		printk(KERN_ERR
+			"%s: not enough memory to parse X.25 incomming call "
+			"on LCN %d!\n", card->devname, new_lcn);
+		x25_clear_call(card, new_lcn, 0, 0);
+		return 1;
+	}
+	parse_call_info(mb->data, info);
+	printk(KERN_INFO "%s: X.25 incomming call on LCN %d! Call data: %s\n",
+		card->devname, new_lcn, mb->data)
+	;
+
+	/* Find available channel */
+	for (dev = wandev->dev; dev; dev = dev->slave)
+	{
+		chan = dev->priv;
+
+		if (!chan->svc || (chan->state != WAN_DISCONNECTED))
+			continue
+		;
+		if (strcmp(info->src, chan->addr) == 0)
+			break
+		;
+	}
+
+	if (dev == NULL)
+	{
+		printk(KERN_INFO "%s: no channels available!\n",
+			card->devname)
+		;
+		x25_clear_call(card, new_lcn, 0, 0);
+	}
+
+	/* Check requested protocol encapsulation */
+	else if (info->nuser == 0)
+	{
+		printk(KERN_INFO
+			"%s: no user data in incomming call on LCN %d!\n",
+			card->devname, new_lcn)
+		;
+		x25_clear_call(card, new_lcn, 0, 0);
+	}
+	else switch (info->user[0])
+	{
+	case 0:		/* multiplexed */
+		chan->protocol = 0;
+		accept = 1;
+		break;
+
+	case NLPID_IP:	/* IP datagrams */
+		chan->protocol = ETH_P_IP;
+		accept = 1;
+		break;
+
+	case NLPID_SNAP:
+	default:
+		printk(KERN_INFO
+			"%s: unsupported NLPID 0x%02X in incomming call "
+			"on LCN %d!\n", card->devname, info->user[0], new_lcn)
+		;
+		x25_clear_call(card, new_lcn, 0, 249);
+	}
+
+	if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK))
+	{
+		chan->lcn = new_lcn;
+		if (x25_get_chan_conf(card, chan) == CMD_OK)
+			set_chan_state(dev, WAN_CONNECTED)
+		;
+		else x25_clear_call(card, new_lcn, 0, 0);
+	}
+	kfree(info);
+	return 1;
+}
+
+/*============================================================================
+ * Handle accepted call.
+ */
+static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+	unsigned new_lcn = mb->cmd.lcn;
+	struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+	x25_channel_t* chan;
+
+	printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n",
+		card->devname, new_lcn)
+	;
+	if (dev == NULL)
+	{
+		printk(KERN_INFO
+			"%s: clearing orphaned connection on LCN %d!\n",
+			card->devname, new_lcn)
+		;
+		x25_clear_call(card, new_lcn, 0, 0);
+		return 1;
+	}
+
+	/* Get channel configuration and notify router */
+	chan = dev->priv;
+	if (x25_get_chan_conf(card, chan) != CMD_OK)
+	{
+		x25_clear_call(card, new_lcn, 0, 0);
+		return 1;
+	}
+	set_chan_state(dev, WAN_CONNECTED);
+	return 1;
+}
+
+/*============================================================================
+ * Handle cleared call.
+ */
+static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+	unsigned new_lcn = mb->cmd.lcn;
+	struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+
+	printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X "
+		"Diagn:0x%02X\n",
+		card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn)
+	;
+	if (dev == NULL) return 1;
+	set_chan_state(dev, WAN_DISCONNECTED);
+
+	return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1;
+}
+
+/*============================================================================
+ * Handle X.25 restart event.
+ */
+static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+	wan_device_t* wandev = &card->wandev;
+	struct device* dev;
+
+	printk(KERN_INFO
+		"%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n",
+		card->devname, mb->cmd.cause, mb->cmd.diagn)
+	;
+
+	/* down all logical channels */
+	for (dev = wandev->dev; dev; dev = dev->slave)
+		set_chan_state(dev, WAN_DISCONNECTED)
+	;
+	return (cmd == X25_WRITE) ? 0 : 1;
+}
+
+/*============================================================================
+ * Handle timeout event.
+ */
+static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
+{
+	unsigned new_lcn = mb->cmd.lcn;
+
+	if (mb->cmd.pktType == 0x05)	/* call request time out */
+	{
+		struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+
+		printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n",
+			card->devname, new_lcn)
+		;
+		if (dev) set_chan_state(dev, WAN_DISCONNECTED);
+	}
+	else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n",
+		card->devname, mb->cmd.pktType, new_lcn)
+	;
+	return 1;
+}
+
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * Establish physical connection.
+ * o open HDLC and raise DTR
+ *
+ * Return:	0	connection established
+ *		1	connection is in progress
+ *		<0	error
+ */
+static int connect (sdla_t* card)
+{
+	if (x25_open_hdlc(card) || x25_setup_hdlc(card))
+		return -EIO
+	;
+	wanpipe_set_state(card, WAN_CONNECTING);
+	return 1;
+}
+
+/*============================================================================
+ * Tear down physical connection.
+ * o close HDLC link
+ * o drop DTR
+ *
+ * Return:	0
+ *		<0	error
+ */
+static int disconnect (sdla_t* card)
+{
+	wanpipe_set_state(card, WAN_DISCONNECTED);
+	x25_set_intr_mode(card, 0);	/* disable interrupt generation */
+	x25_close_hdlc(card);		/* close HDLC link */
+	x25_set_dtr(card, 0);		/* drop DTR */
+	return 0;
+}
+
+/*============================================================================
+ * Find network device by its channel number.
+ */
+static struct device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn)
+{
+	struct device* dev;
+
+	for (dev = wandev->dev; dev; dev = dev->slave)
+		if (((x25_channel_t*)dev->priv)->lcn == lcn) break
+	;
+	return dev;
+}
+
+/*============================================================================
+ * Initiate connection on the logical channel.
+ * o for PVC we just get channel configuration
+ * o for SVCs place an X.25 call
+ *
+ * Return:	0	connected
+ *		>0	connection in progress
+ *		<0	failure
+ */
+static int chan_connect (struct device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+
+	if (chan->svc)
+	{
+		if (!chan->addr[0])
+			return -EINVAL	/* no destination address */
+		;
+		printk(KERN_INFO "%s: placing X.25 call to %s ...\n",
+			card->devname, chan->addr)
+		;
+		if (x25_place_call(card, chan) != CMD_OK)
+			return -EIO
+		;
+		set_chan_state(dev, WAN_CONNECTING);
+		return 1;
+	}
+	else
+	{
+		if (x25_get_chan_conf(card, chan) != CMD_OK)
+			return -EIO
+		;
+		set_chan_state(dev, WAN_CONNECTED);
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Disconnect logical channel.
+ * o if SVC then clear X.25 call
+ */
+static int chan_disc (struct device* dev)
+{
+	x25_channel_t* chan = dev->priv;
+
+	set_chan_state(dev, WAN_DISCONNECTED);
+	if (chan->svc) x25_clear_call(chan->card, chan->lcn, 0, 0);
+	return 0;
+}
+
+/*============================================================================
+ * Set logical channel state.
+ */
+static void set_chan_state (struct device* dev, int state)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (chan->state != state)
+	{
+		switch (state)
+		{
+		case WAN_CONNECTED:
+			printk (KERN_INFO "%s: interface %s connected!\n",
+			card->devname, dev->name)
+			;
+			*(unsigned short*)dev->dev_addr = htons(chan->lcn);
+			break;
+
+		case WAN_CONNECTING:
+			printk (KERN_INFO "%s: interface %s connecting...\n",
+				card->devname, dev->name)
+			;
+			break;
+
+		case WAN_DISCONNECTED:
+			printk (KERN_INFO "%s: interface %s disconnected!\n",
+				card->devname, dev->name)
+			;
+			if (chan->svc)
+				*(unsigned short*)dev->dev_addr = 0
+			;
+			break;
+		}
+		chan->state = state;
+	}
+	chan->state_tick = jiffies;
+	restore_flags(flags);
+}
+
+/*============================================================================
+ * Send packet on a logical channel.
+ *	When this function is called, tx_skb field of the channel data space
+ *	points to the transmit socket buffer.  When transmission is complete,
+ *	release socket buffer and reset 'tbusy' flag.
+ *
+ * Return:	0	- transmission complete
+ *		1	- busy
+ *
+ * Notes:
+ * 1. If packet length is greater than MTU for this channel, we'll fragment
+ *    the packet into 'complete sequence' using M-bit.
+ * 2. When transmission is complete, an event notification should be issued
+ *    to the router.
+ */
+static int chan_send (struct device* dev, struct sk_buff* skb)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	TX25Status* status = card->flags;
+	unsigned len, qdm;
+
+	/* Check to see if channel is ready */
+	if (!(status->cflags[chan->ch_idx] & 0x40))
+		return 1
+	;
+	if (skb->len > chan->tx_pkt_size)
+	{
+		len = chan->tx_pkt_size;
+		qdm = 0x01;		/* set M-bit (more data) */
+	}
+	else	/* final packet */
+	{
+		len = skb->len;
+		qdm = 0;
+	}
+	switch(x25_send(card, chan->lcn, qdm, len, skb->data))
+	{
+	case 0x00:	/* success */
+		if (qdm)
+		{
+			skb_pull(skb, len);
+			return 1;
+		}
+		++chan->ifstats.tx_packets;
+		break;
+
+	case 0x33:	/* Tx busy */
+		return 1;
+
+	default:	/* failure */
+		++chan->ifstats.tx_errors;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Parse X.25 call request data and fill x25_call_info_t structure.
+ */
+static void parse_call_info (unsigned char* str, x25_call_info_t* info)
+{
+	memset(info, 0, sizeof(x25_call_info_t));
+	for (; *str; ++str)
+	{
+		int i;
+		unsigned ch;
+
+		if (*str == '-') switch (str[1])
+		{
+		case 'd':	/* destination address */
+			for (i = 0; i < 16; ++i)
+			{
+				ch = str[2+i];
+				if (!is_digit(ch)) break;
+				info->dest[i] = ch;
+			}
+			break;
+
+		case 's':	/* source address */
+			for (i = 0; i < 16; ++i)
+			{
+				ch = str[2+i];
+				if (!is_digit(ch)) break;
+				info->src[i] = ch;
+			}
+			break;
+
+		case 'u':	/* user data */
+			for (i = 0; i < 127; ++i)
+			{
+				ch = str[2+2*i];
+				if (!is_hex_digit(ch)) break;
+				info->user[i] = hex_to_uint(&str[2+2*i], 2);
+			}
+			info->nuser = i;
+			break;
+
+		case 'f':	/* facilities */
+			for (i = 0; i < 64; ++i)
+			{
+				ch = str[2+4*i];
+				if (!is_hex_digit(ch)) break;
+				info->facil[i].code =
+					hex_to_uint(&str[2+4*i], 2)
+				;
+				ch = str[4+4*i];
+				if (!is_hex_digit(ch)) break;
+				info->facil[i].parm =
+					hex_to_uint(&str[4+4*i], 2)
+				;
+			}
+			info->nfacil = i;
+			break;
+		}
+	}
+}
+
+/*============================================================================
+ * Convert line speed in bps to a number used by S502 code.
+ */
+static unsigned char bps_to_speed_code (unsigned long bps)
+{
+	unsigned char	number;
+
+	if (bps <= 1200)        number = 0x01 ;
+	else if (bps <= 2400)   number = 0x02;
+	else if (bps <= 4800)   number = 0x03;
+	else if (bps <= 9600)   number = 0x04;
+	else if (bps <= 19200)  number = 0x05;
+	else if (bps <= 38400)  number = 0x06;
+	else if (bps <= 45000)  number = 0x07;
+	else if (bps <= 56000)  number = 0x08;
+	else if (bps <= 64000)  number = 0x09;
+	else if (bps <= 74000)  number = 0x0A;
+	else if (bps <= 112000) number = 0x0B;
+	else if (bps <= 128000) number = 0x0C;
+	else number = 0x0D;
+
+	return number;
+}
+
+/*============================================================================
+ * Convert decimal string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are converted.
+ */
+static unsigned int dec_to_uint (unsigned char* str, int len)
+{
+	unsigned val;
+
+	if (!len) len = strlen(str);
+	for (val = 0; len && is_digit(*str); ++str, --len)
+		val = (val * 10) + (*str - (unsigned)'0')
+	;
+	return val;
+}
+
+/*============================================================================
+ * Convert hex string to unsigned integer.
+ * If len != 0 then only 'len' characters of the string are conferted.
+ */
+static unsigned int hex_to_uint (unsigned char* str, int len)
+{
+	unsigned val, ch;
+
+	if (!len) len = strlen(str);
+	for (val = 0; len; ++str, --len)
+	{
+		ch = *str;
+		if (is_digit(ch))
+			val = (val << 4) + (ch - (unsigned)'0')
+		;
+		else if (is_hex_digit(ch))
+			val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10)
+		;
+		else break;
+	}
+	return val;
+}
+
+/****** End *****************************************************************/
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdladrv.c linux/drivers/net/sdladrv.c
--- v2.1.24/linux/drivers/net/sdladrv.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/sdladrv.c	Sun Feb  2 15:18:41 1997
@@ -0,0 +1,1829 @@
+/*****************************************************************************
+* sdladrv.c	SDLA Support Module.  Main module.
+*
+*		This module is a library of common hardware-specific functions
+*		used by all Sangoma drivers.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*
+* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Dec 20, 1996	Gene Kozin	Version 3.0.0. Complete overhaul.
+* Jul 12, 1996	Gene Kozin	Changes for Linux 2.0 compatibility.
+* Jun 12, 1996	Gene Kozin 	Added support for S503 card.
+* Apr 30, 1996	Gene Kozin	SDLA hardware interrupt is acknowledged before
+*				calling protocolspecific ISR.
+*				Register I/O ports with Linux kernel.
+*				Miscellaneous bug fixes.
+* Dec 20, 1995	Gene Kozin	Fixed a bug in interrupt routine.
+* Oct 14, 1995	Gene Kozin	Initial version.
+*****************************************************************************/
+
+/*****************************************************************************
+ * Notes:
+ * ------
+ * 1. This code is ment to be system-independent (as much as possible).  To
+ *    achive this, various macros are used to hide system-specific interfaces.
+ *    To compile this code, one of the following constants must be defined:
+ *
+ *	Platform	Define
+ *	--------	------
+ *	Linux		_LINUX_
+ *	SCO Unix	_SCO_UNIX_
+ *
+ * 2. Supported adapter types:
+ *
+ *	S502A
+ *	ES502A (S502E)
+ *	S503
+ *	S507
+ *	S508 (S509)
+ *
+ * 3. S502A Notes:
+ *
+ *	There is no separate DPM window enable/disable control in S502A.  It
+ *	opens immediately after a window number it written to the HMCR
+ *	register.  To close the window, HMCR has to be written a value
+ *	????1111b (e.g. 0x0F or 0xFF).
+ *
+ *	S502A DPM window cannot be located at offset E000 (e.g. 0xAE000).
+ *
+ *	There should be a delay of ??? before reading back S502A status
+ *	register.
+ *
+ * 4. S502E Notes:
+ *
+ *	S502E has a h/w bug: although default IRQ line state is HIGH, enabling
+ *	interrupts by setting bit 1 of the control register (BASE) to '1'
+ *	causes it to go LOW! Therefore, disabling interrupts by setting that
+ *	bit to '0' causes low-to-high transition on IRQ line (ghosty
+ *	interrupt). The same occurs when disabling CPU by resetting bit 0 of
+ *	CPU control register (BASE+3) - see the next note.
+ *
+ *	S502E CPU and DPM control is limited:
+ *
+ *	o CPU cannot be stopped independently. Resetting bit 0 of the CPUi
+ *	  control register (BASE+3) shuts the board down entirely, including
+ *	  DPM;
+ *
+ *	o DPM access cannot be controlled dynamically. Ones CPU is started,
+ *	  bit 1 of the control register (BASE) is used to enable/disable IRQ,
+ *	  so that access to shared memory cannot be disabled while CPU is
+ *	  running.
+ ****************************************************************************/
+
+#define	_LINUX_
+
+#if	defined(_LINUX_)	/****** Linux *******************************/
+
+#include <linux/config.h>	/* OS configuration options */
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/module.h>	/* support for loadable modules */
+#include <linux/sched.h>	/* for jiffies, HZ, etc. */
+#include <linux/sdladrv.h>	/* API definitions */
+#include <linux/sdlasfm.h>	/* SDLA firmware module definitions */
+#include <asm/io.h>		/* for inb(), outb(), etc. */
+#define _INB(port)		(inb(port))
+#define _OUTB(port, byte)	(outb((byte),(port)))
+#define	SYSTEM_TICK		jiffies
+
+#elif	defined(_SCO_UNIX_)	/****** SCO Unix ****************************/
+#if	!defined(INKERNEL)
+#error	This code MUST be compiled in kernel mode!
+#endif
+#include <sys/sdladrv.h>	/* API definitions */
+#include <sys/sdlasfm.h>	/* SDLA firmware module definitions */
+#include <sys/inline.h>		/* for inb(), outb(), etc. */
+#define _INB(port)		(inb(port))
+#define _OUTB(port, byte)	(outb((port),(byte)))
+#define	SYSTEM_TICK		lbolt
+
+#else
+#error	Unknown system type!
+#endif
+
+#define	MOD_VERSION	3
+#define	MOD_RELEASE	0
+
+#define	SDLA_IODELAY	100	/* I/O Rd/Wr delay, 10 works for 486DX2-66 */
+#define	EXEC_DELAY	20	/* shared memory access delay, mks */
+#define	EXEC_TIMEOUT	(HZ*2)	/* command timeout, in ticks */
+
+/* I/O port address range */
+#define S502A_IORANGE	3
+#define S502E_IORANGE	4
+#define S503_IORANGE	3
+#define S507_IORANGE	4
+#define S508_IORANGE	4
+
+/* Maximum amount of memory */
+#define S502_MAXMEM	0x10000L
+#define S503_MAXMEM	0x10000L
+#define S507_MAXMEM	0x40000L
+#define S508_MAXMEM	0x40000L
+
+/* Minimum amount of memory */
+#define S502_MINMEM	0x8000L
+#define S503_MINMEM	0x8000L
+#define S507_MINMEM	0x20000L
+#define S508_MINMEM	0x20000L
+
+/****** Function Prototypes *************************************************/
+
+/* Module entry points. These are called by the OS and must be public. */
+int init_module (void);
+void cleanup_module (void);
+
+/* Hardware-specific functions */
+static int sdla_detect	(sdlahw_t* hw);
+static int sdla_autodpm	(sdlahw_t* hw);
+static int sdla_setdpm	(sdlahw_t* hw);
+static int sdla_load	(sdlahw_t* hw, sfm_t* sfm, unsigned len);
+static int sdla_init	(sdlahw_t* hw);
+static unsigned long sdla_memtest (sdlahw_t* hw);
+static int sdla_bootcfg	(sdlahw_t* hw, sfm_info_t* sfminfo);
+static unsigned char make_config_byte (sdlahw_t* hw);
+static int sdla_start	(sdlahw_t* hw, unsigned addr);
+
+static int init_s502a	(sdlahw_t* hw);
+static int init_s502e	(sdlahw_t* hw);
+static int init_s503	(sdlahw_t* hw);
+static int init_s507	(sdlahw_t* hw);
+static int init_s508	(sdlahw_t* hw);
+
+static int detect_s502a	(int port);
+static int detect_s502e	(int port);
+static int detect_s503	(int port);
+static int detect_s507	(int port);
+static int detect_s508	(int port);
+
+/* Miscellaneous functions */
+static int calibrate_delay (int mks);
+static int get_option_index (unsigned* optlist, unsigned optval);
+static unsigned check_memregion (void* ptr, unsigned len);
+static unsigned	test_memregion (void* ptr, unsigned len);
+static unsigned short checksum (unsigned char* buf, unsigned len);
+
+/****** Global Data **********************************************************
+ * Note: All data must be explicitly initialized!!!
+ */
+
+/* private data */
+static char modname[]	= "sdladrv";
+static char fullname[]	= "SDLA Support Module";
+static char copyright[]	= "(c) 1995-1996 Sangoma Technologies Inc.";
+static unsigned	exec_idle;
+
+/* Hardware configuration options.
+ * These are arrays of configuration options used by verification routines.
+ * The first element of each array is its size (i.e. number of options).
+ */
+static unsigned	s502_port_options[] =
+	{ 4, 0x250, 0x300, 0x350, 0x360 }
+;
+static unsigned	s503_port_options[] =
+	{ 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 }
+;
+static unsigned	s508_port_options[] =
+	{ 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 }
+;
+
+static unsigned s502a_irq_options[] = { 0 };
+static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 };
+static unsigned s503_irq_options[]  = { 5, 2, 3, 4, 5, 7 };
+static unsigned s508_irq_options[]  = { 8, 3, 4, 5, 7, 10, 11, 12, 15 };
+
+static unsigned s502a_dpmbase_options[] =
+{
+	28,
+	0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000,
+	0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000,
+	0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000,
+	0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000,
+};
+static unsigned s507_dpmbase_options[] =
+{
+	32,
+	0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
+	0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
+	0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
+	0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000,
+};
+static unsigned s508_dpmbase_options[] =	/* incl. S502E and S503 */
+{
+	32,
+	0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
+	0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
+	0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000,
+	0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000,
+};
+
+/*
+static unsigned	s502_dpmsize_options[] = { 2, 0x2000, 0x10000 };
+static unsigned	s507_dpmsize_options[] = { 2, 0x2000, 0x4000 };
+static unsigned	s508_dpmsize_options[] = { 1, 0x2000 };
+*/
+
+static unsigned	s502a_pclk_options[] = { 2, 3600, 7200 };
+static unsigned	s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 };
+static unsigned	s503_pclk_options[]  = { 3, 7200, 8000, 10000 };
+static unsigned	s507_pclk_options[]  = { 1, 12288 };
+static unsigned	s508_pclk_options[]  = { 1, 16000 };
+
+/* Host memory control register masks */
+static unsigned char s502a_hmcr[] =
+{
+	0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C,	/* A0000 - AC000 */
+	0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C,	/* C0000 - CC000 */
+	0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C,	/* D0000 - DC000 */
+	0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C,	/* E0000 - EC000 */
+};
+static unsigned char s502e_hmcr[] =
+{
+	0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E,	/* A0000 - AE000 */
+	0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E,	/* C0000 - CE000 */
+	0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,	/* D0000 - DE000 */
+	0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E,	/* E0000 - EE000 */
+};
+static unsigned char s507_hmcr[] =
+{
+	0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,	/* A0000 - AE000 */
+	0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E,	/* B0000 - BE000 */
+	0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E,	/* C0000 - CE000 */
+	0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,	/* E0000 - EE000 */
+};
+static unsigned char s508_hmcr[] =
+{
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* A0000 - AE000 */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,	/* C0000 - CE000 */
+	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,	/* D0000 - DE000 */
+	0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,	/* E0000 - EE000 */
+};
+
+static unsigned char s507_irqmask[] =
+{
+	0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0
+};
+
+/******* Kernel Loadable Module Entry Points ********************************/
+
+/*============================================================================
+ * Module 'insert' entry point.
+ * o print announcement
+ * o initialize static data
+ * o calibrate SDLA shared memory access delay.
+ *
+ * Return:	0	Ok
+ *		< 0	error.
+ * Context:	process
+ */
+
+#ifdef MODULE
+int init_module (void)
+#else
+int wanpipe_init(void)
+{
+	printk(KERN_INFO "%s v%u.%u %s\n",
+		fullname, MOD_VERSION, MOD_RELEASE, copyright);
+	exec_idle = calibrate_delay(EXEC_DELAY);
+#ifdef WANDEBUG	
+	printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle);
+#endif	
+	return 0;
+}
+
+#ifdef MODULE
+/*============================================================================
+ * Module 'remove' entry point.
+ * o release all remaining system resources
+ */
+void cleanup_module (void)
+{
+}
+#endif
+
+/******* Kernel APIs ********************************************************/
+
+/*============================================================================
+ * Set up adapter.
+ * o detect adapter type
+ * o verify hardware configuration options
+ * o check for hardware conflicts
+ * o set up adapter shared memory
+ * o test adapter memory
+ * o load firmware
+ * Return:	0	ok.
+ *		< 0	error
+ */
+int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)
+{
+	unsigned* irq_opt	= NULL;	/* IRQ options */
+	unsigned* dpmbase_opt	= NULL;	/* DPM window base options */
+	unsigned* pclk_opt	= NULL;	/* CPU clock rate options */
+	int err;
+
+	if (sdla_detect(hw))
+	{
+		printk(KERN_ERR "%s: adapter S%04u not found at port 0x%X!\n",
+			modname, hw->type, hw->port)
+		;
+		return -EINVAL;
+	}
+	printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n",
+		modname, hw->type, hw->port)
+	;
+
+	hw->dpmsize = SDLA_WINDOWSIZE;
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		hw->io_range	= S502A_IORANGE;
+		irq_opt		= s502a_irq_options;
+		dpmbase_opt	= s502a_dpmbase_options;
+		pclk_opt	= s502a_pclk_options;
+		break;
+
+	case SDLA_S502E:
+		hw->io_range	= S502E_IORANGE;
+		irq_opt		= s502e_irq_options;
+		dpmbase_opt	= s508_dpmbase_options;
+		pclk_opt	= s502e_pclk_options;
+		break;
+
+	case SDLA_S503:
+		hw->io_range	= S503_IORANGE;
+		irq_opt		= s503_irq_options;
+		dpmbase_opt	= s508_dpmbase_options;
+		pclk_opt	= s503_pclk_options;
+		break;
+
+	case SDLA_S507:
+		hw->io_range	= S507_IORANGE;
+		irq_opt		= s508_irq_options;
+		dpmbase_opt	= s507_dpmbase_options;
+		pclk_opt	= s507_pclk_options;
+		break;
+
+	case SDLA_S508:
+		hw->io_range	= S508_IORANGE;
+		irq_opt		= s508_irq_options;
+		dpmbase_opt	= s508_dpmbase_options;
+		pclk_opt	= s508_pclk_options;
+		break;
+	}
+
+	/* Verify IRQ configuration options */
+	if (!get_option_index(irq_opt, hw->irq))
+	{
+		printk(KERN_ERR "%s: IRQ %d is illegal!\n",
+			modname, hw->irq)
+		;
+		return -EINVAL;
+	} 
+
+	/* Verify CPU clock rate configuration options */
+	if (hw->pclk == 0)
+		hw->pclk = pclk_opt[1]	/* use default */
+	;
+	else if (!get_option_index(pclk_opt, hw->pclk))
+	{
+		printk(KERN_ERR "%s: CPU clock %u is illegal!\n",
+			modname, hw->pclk)
+		;
+		return -EINVAL;
+	} 
+	printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n",
+		modname, hw->pclk)
+	;
+
+	/* Setup adapter dual-port memory window and test memory */
+	if (hw->dpmbase == 0)
+	{
+		err = sdla_autodpm(hw);
+		if (err)
+		{
+			printk(KERN_ERR
+				"%s: can't find available memory region!\n",
+				modname)
+			;
+ 			return err;
+		}
+	}
+	else if (!get_option_index(dpmbase_opt, hw->dpmbase))
+	{
+		printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n",
+			modname, hw->dpmbase)
+		;
+		return -EINVAL;
+	} 
+	else if (sdla_setdpm(hw))
+	{
+		printk(KERN_ERR
+			"%s: 8K memory region at 0x%lX is not available!\n",
+			modname, hw->dpmbase)
+		;
+		return -EINVAL;
+	} 
+	printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n",
+		modname, hw->dpmbase)
+	;
+	printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n",
+		modname, hw->memory / 1024)
+	;
+
+	/* Load firmware. If loader fails then shut down adapter */
+	err = sdla_load(hw, sfm, len);
+	if (err) sdla_down(hw);		/* shutdown adapter */
+	return err;
+} 
+
+/*============================================================================
+ * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc.
+ */
+int sdla_down (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int i;
+
+	if (!port) return -EFAULT;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		_OUTB(port, 0x08);		/* halt CPU */
+		_OUTB(port, 0x08);
+		_OUTB(port, 0x08);
+		hw->regs[0] = 0x08;
+		_OUTB(port + 1, 0xFF);		/* close memory window */
+		hw->regs[1] = 0xFF;
+		break;
+
+	case SDLA_S502E:
+		_OUTB(port + 3, 0);		/* stop CPU */
+		_OUTB(port, 0);			/* reset board */
+		for (i = 0; i < S502E_IORANGE; ++i)
+			hw->regs[i] = 0
+		;
+		break;
+
+	case SDLA_S503:
+	case SDLA_S507:
+	case SDLA_S508:
+		_OUTB(port, 0);			/* reset board logic */
+		hw->regs[0] = 0;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Map shared memory window into SDLA adress space.
+ */
+int sdla_mapmem (sdlahw_t* hw, unsigned long addr)
+{
+	unsigned port = hw->port;
+	register int tmp;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+	case SDLA_S502E:
+		if (addr < S502_MAXMEM)	/* verify parameter */
+		{
+			tmp = addr >> 13;	/* convert to register mask */
+			_OUTB(port + 2, tmp);
+			hw->regs[2] = tmp;
+		}
+		else return -EINVAL;
+		break;
+
+	case SDLA_S503:
+		if (addr < S503_MAXMEM)	/* verify parameter */
+		{
+			tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70);
+			_OUTB(port, tmp);
+			hw->regs[0] = tmp;
+		}
+		else return -EINVAL;
+		break;
+
+	case SDLA_S507:
+		if (addr < S507_MAXMEM)
+		{
+			if (!(_INB(port) & 0x02))
+				return -EIO
+			;
+			tmp = addr >> 13;	/* convert to register mask */
+			_OUTB(port + 2, tmp);
+			hw->regs[2] = tmp;
+		}
+		else return -EINVAL;
+		break;
+
+	case SDLA_S508:
+		if (addr < S508_MAXMEM)
+		{
+			tmp = addr >> 13;	/* convert to register mask */
+			_OUTB(port + 2, tmp);
+			hw->regs[2] = tmp;
+		}
+		else return -EINVAL;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	hw->vector = addr & 0xFFFFE000L;
+	return 0;
+}
+
+/*============================================================================
+ * Enable interrupt generation.
+ */
+int sdla_inten (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	switch (hw->type)
+	{
+	case SDLA_S502E:
+		/* Note thar interrupt control operations on S502E are allowed
+		 * only if CPU is enabled (bit 0 of status register is set).
+		 */
+		if (_INB(port) & 0x01)
+		{
+			_OUTB(port, 0x02);	/* bit1 = 1, bit2 = 0 */
+			_OUTB(port, 0x06);	/* bit1 = 1, bit2 = 1 */
+			hw->regs[0] = 0x06;
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S503:
+		tmp = hw->regs[0] | 0x04;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;		/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+		if (!(_INB(port) & 0x02))		/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S508:
+		tmp = hw->regs[0] | 0x10;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;		/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+		if (!(_INB(port + 1) & 0x10))		/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S502A:
+	case SDLA_S507:
+		break;
+
+	default:
+		return -EINVAL;
+
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Disable interrupt generation.
+ */
+int sdla_intde (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	switch (hw->type)
+	{
+	case SDLA_S502E:
+		/* Notes:
+		 *  1) interrupt control operations are allowed only if CPU is
+		 *     enabled (bit 0 of status register is set).
+		 *  2) disabling interrupts using bit 1 of control register
+		 *     causes IRQ line go high, therefore we are going to use
+		 *     0x04 instead: lower it to inhibit interrupts to PC.
+		 */
+		if (_INB(port) & 0x01)
+		{
+			_OUTB(port, hw->regs[0] & ~0x04);
+			hw->regs[0] &= ~0x04;
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S503:
+		tmp = hw->regs[0] & ~0x04;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;			/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+		if (_INB(port) & 0x02)			/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S508:
+		tmp = hw->regs[0] & ~0x10;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;			/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+		if (_INB(port) & 0x10)			/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S502A:
+	case SDLA_S507:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Acknowledge SDLA hardware interrupt.
+ */
+int sdla_intack (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp;
+
+	switch (hw->type)
+	{
+	case SDLA_S502E:
+		/* To acknoledge hardware interrupt we have to toggle bit 3 of
+		 * control register: \_/
+		 * Note that interrupt control operations on S502E are allowed
+		 * only if CPU is enabled (bit 1 of status register is set).
+		 */
+		if (_INB(port) & 0x01)
+		{
+			tmp = hw->regs[0] & ~0x04;
+			_OUTB(port, tmp);
+			tmp |= 0x04;
+			_OUTB(port, tmp);
+			hw->regs[0] = tmp;
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S503:
+		if (_INB(port) & 0x04)
+		{
+			tmp = hw->regs[0] & ~0x08;
+			_OUTB(port, tmp);
+			tmp |= 0x08;
+			_OUTB(port, tmp);
+			hw->regs[0] = tmp;
+		}
+		break;
+
+	case SDLA_S502A:
+	case SDLA_S507:
+	case SDLA_S508:
+	break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Generate an interrupt to adapter's CPU.
+ */
+int sdla_intr (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		if (!(_INB(port) & 0x40))
+		{
+			_OUTB(port, 0x10);		/* issue NMI to CPU */
+			hw->regs[0] = 0x10;
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S507:
+		if ((_INB(port) & 0x06) == 0x06)
+		{
+			_OUTB(port + 3, 0);
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S508:
+		if (_INB(port + 1) & 0x02)
+		{
+			_OUTB(port, 0x08);
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S502E:
+	case SDLA_S503:
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Execute Adapter Command.
+ * o Set exec flag.
+ * o Busy-wait until flag is reset.
+ * o Return number of loops made, or 0 if command timed out.
+ */
+int sdla_exec (void* opflag)
+{
+	volatile unsigned char* flag = opflag;
+	unsigned long tstop;
+	int nloops;
+
+	if (*flag) return 0;	/* ???? */
+
+	*flag = 1;
+	tstop = SYSTEM_TICK + EXEC_TIMEOUT;
+	for (nloops = 1; *flag; ++nloops)
+	{
+		unsigned delay = exec_idle;
+		while (--delay);			/* delay */
+		if (SYSTEM_TICK > tstop) return 0;	/* time is up! */
+	}
+	return nloops;
+}
+
+/*============================================================================
+ * Read absolute adapter memory.
+ * Transfer data from adapter's memory to data buffer.
+ *
+ * Note:
+ * Care should be taken when crossing dual-port memory window boundary.
+ * This function is not atomic, so caller must disable interrupt if
+ * interrupt routines are accessing adapter shared memory.
+ */
+int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
+{
+	unsigned long oldvec = hw->vector;
+	unsigned winsize = hw->dpmsize;
+	unsigned curpos, curlen;	/* current offset and block size */
+	unsigned long curvec;		/* current DPM window vector */
+	int err = 0;
+
+	if (addr + len > hw->memory)	/* verify arguments */
+		return -EINVAL
+	;
+	while (len && !err)
+	{
+		curpos = addr % winsize;	/* current window offset */
+		curvec = addr - curpos;		/* current window vector */
+		curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len;
+
+		/* Relocate window and copy block of data */
+		err = sdla_mapmem(hw, curvec);
+		memcpy((void*)buf, (void*)(hw->dpmbase + curpos), curlen);
+		addr       += curlen;
+		(char*)buf += curlen;
+		len        -= curlen;
+	}
+
+	/* Restore DPM window position */
+	sdla_mapmem(hw, oldvec);
+	return err;
+}
+
+/*============================================================================
+ * Write Absolute Adapter Memory.
+ * Transfer data from data buffer to adapter's memory.
+ *
+ * Note:
+ * Care should be taken when crossing dual-port memory window boundary.
+ * This function is not atomic, so caller must disable interrupt if
+ * interrupt routines are accessing adapter shared memory.
+ */
+int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
+{
+	unsigned long oldvec = hw->vector;
+	unsigned winsize = hw->dpmsize;
+	unsigned curpos, curlen;	/* current offset and block size */
+	unsigned long curvec;		/* current DPM window vector */
+	int err = 0;
+
+	if (addr + len > hw->memory)	/* verify arguments */
+		return -EINVAL
+	;
+	while (len && !err)
+	{
+		curpos = addr % winsize;	/* current window offset */
+		curvec = addr - curpos;		/* current window vector */
+		curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len;
+
+		/* Relocate window and copy block of data */
+		sdla_mapmem(hw, curvec);
+		memcpy((void*)(hw->dpmbase + curpos), (void*)buf, curlen);
+		addr       += curlen;
+		(char*)buf += curlen;
+		len        -= curlen;
+	}
+
+	/* Restore DPM window position */
+	sdla_mapmem(hw, oldvec);
+	return err;
+}
+
+#ifdef	DONT_COMPIPLE_THIS
+#endif	/* DONT_COMPIPLE_THIS */
+
+/****** Hardware-Specific Functions *****************************************/
+
+/*============================================================================
+ * Detect adapter type.
+ * o if adapter type is specified then call detection routine for that adapter
+ *   type.  Otherwise call detection routines for every adapter types until
+ *   adapter is detected.
+ *
+ * Notes:
+ * 1) Detection tests are destructive! Adapter will be left in shutdown state
+ *    after the test.
+ */
+static int sdla_detect (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int err = 0;
+
+	if (!port)
+		return -EFAULT
+	;
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		if (!detect_s502a(port)) err = -ENODEV;
+		break;
+
+	case SDLA_S502E:
+		if (!detect_s502e(port)) err = -ENODEV;
+		break;
+
+	case SDLA_S503:
+		if (!detect_s503(port)) err = -ENODEV;
+		break;
+
+	case SDLA_S507:
+		if (!detect_s507(port)) err = -ENODEV;
+		break;
+
+	case SDLA_S508:
+		if (!detect_s508(port)) err = -ENODEV;
+		break;
+
+	default:
+		if (detect_s502a(port))
+			hw->type = SDLA_S502A
+		;
+		else if (detect_s502e(port))
+			hw->type = SDLA_S502E
+		;
+		else if (detect_s503(port))
+			hw->type = SDLA_S503
+		;
+		else if (detect_s507(port))
+			hw->type = SDLA_S507
+		;
+		else if (detect_s508(port))
+			hw->type = SDLA_S508
+		;
+		else err = -ENODEV;
+	}
+	return err;
+}
+
+/*============================================================================
+ * Autoselect memory region. 
+ * o try all available DMP address options from the top down until success.
+ */
+static int sdla_autodpm (sdlahw_t* hw)
+{
+	int i, err = -EINVAL;
+	unsigned* opt;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		opt = s502a_dpmbase_options;
+		break;
+
+	case SDLA_S502E:
+	case SDLA_S503:
+	case SDLA_S508:
+		opt = s508_dpmbase_options;
+		break;
+
+	case SDLA_S507:
+		opt = s507_dpmbase_options;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	for (i = opt[0]; i && err; --i)
+	{
+		hw->dpmbase = opt[i];
+		err = sdla_setdpm(hw);
+	}
+	return err;
+}
+
+/*============================================================================
+ * Set up adapter dual-port memory window. 
+ * o shut down adapter
+ * o make sure that no physical memory exists in this region, i.e entire
+ *   region reads 0xFF and is not writable when adapter is shut down.
+ * o initialize adapter hardware
+ * o make sure that region is usable with SDLA card, i.e. we can write to it
+ *   when adapter is configured.
+ */
+static int sdla_setdpm (sdlahw_t* hw)
+{
+	int err;
+
+	/* Shut down card and verify memory region */
+	sdla_down(hw);
+	if (check_memregion((void*)hw->dpmbase, hw->dpmsize))
+		return -EINVAL
+	;
+
+	/* Initialize adapter and test on-board memory segment by segment.
+	 * If memory size appears to be less than shared memory window size,
+	 * assume that memory region is unusable.
+	 */
+	err = sdla_init(hw);
+	if (err) return err;
+
+	if (sdla_memtest(hw) < hw->dpmsize)	/* less than window size */
+	{
+		sdla_down(hw);
+		return -EIO;
+	}
+	sdla_mapmem(hw, 0L);	/* set window vector at bottom */
+	return 0;
+}
+
+/*============================================================================
+ * Load adapter from the memory image of the SDLA firmware module. 
+ * o verify firmware integrity and compatibility
+ * o start adapter up
+ */
+static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len)
+{
+	int i;
+
+	/* Verify firmware signature */
+	if (strcmp(sfm->signature, SFM_SIGNATURE))
+	{
+		printk(KERN_ERR "%s: not SDLA firmware!\n",
+			modname)
+		;
+		return -EINVAL;
+	}
+
+	/* Verify firmware module format version */
+	if (sfm->version != SFM_VERSION)
+	{
+		printk(KERN_ERR
+			"%s: firmware format %u rejected! Expecting %u.\n",
+			modname, sfm->version, SFM_VERSION)
+		;
+		return -EINVAL;
+	}
+
+	/* Verify firmware module length and checksum */
+	if ((len - offsetof(sfm_t, image) != sfm->info.codesize) ||
+		(checksum((void*)&sfm->info,
+		sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum))
+	{
+		printk(KERN_ERR "%s: firmware corrupted!\n", modname);
+		return -EINVAL;
+	}
+
+	/* Announce */
+	printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname,
+		(sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware",
+		sfm->info.codeid)
+	;
+
+	/* Scan through the list of compatible adapters and make sure our
+	 * adapter type is listed.
+	 */
+	for (i = 0;
+	     (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type);
+	     ++i)
+	;
+	if (i == SFM_MAX_SDLA)
+	{
+		printk(KERN_ERR "%s: firmware is not compatible with S%u!\n",
+			modname, hw->type)
+		;
+		return -EINVAL;
+	}
+
+	/* Make sure there is enough on-board memory */
+	if (hw->memory < sfm->info.memsize)
+	{
+		printk(KERN_ERR
+			"%s: firmware needs %lu bytes of on-board memory!\n",
+			modname, sfm->info.memsize)
+		;
+		return -EINVAL;
+	}
+
+	/* Move code onto adapter */
+	if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize))
+	{
+		printk(KERN_ERR "%s: failed to load code segment!\n",
+			modname)
+		;
+		return -EIO;
+	}
+
+	/* Prepare boot-time configuration data and kick-off CPU */
+	sdla_bootcfg(hw, &sfm->info);
+	if (sdla_start(hw, sfm->info.startoffs))
+	{
+		printk(KERN_ERR "%s: Damn... Adapter won't start!\n",
+			modname)
+		;
+		return -EIO;
+	}
+
+	/* position DPM window over the mailbox and enable interrupts */
+        if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw))
+	{
+		printk(KERN_ERR "%s: adapter hardware failure!\n",
+			modname)
+		;
+		return -EIO;
+	}
+	hw->fwid = sfm->info.codeid;		/* set firmware ID */
+	return 0;
+}
+
+/*============================================================================
+ * Initialize SDLA hardware: setup memory window, IRQ, etc.
+ */
+static int sdla_init (sdlahw_t* hw)
+{
+	int i;
+
+	for (i = 0; i < SDLA_MAXIORANGE; ++i)
+		hw->regs[i] = 0
+	;
+	switch (hw->type)
+	{
+	case SDLA_S502A: return init_s502a(hw);
+	case SDLA_S502E: return init_s502e(hw);
+	case SDLA_S503:  return init_s503(hw);
+	case SDLA_S507:  return init_s507(hw);
+	case SDLA_S508:  return init_s508(hw);
+	}
+	return -EINVAL;
+}
+
+/*============================================================================
+ * Test adapter on-board memory.
+ * o slide DPM window from the bottom up and test adapter memory segment by
+ *   segment.
+ * Return adapter memory size.
+ */
+static unsigned long sdla_memtest (sdlahw_t* hw)
+{
+	unsigned long memsize;
+	unsigned winsize;
+
+	for (memsize = 0, winsize = hw->dpmsize;
+	     !sdla_mapmem(hw, memsize) &&
+		(test_memregion((void*)hw->dpmbase, winsize) == winsize)
+	     ;
+	     memsize += winsize)
+	;
+	hw->memory = memsize;
+	return memsize;
+}
+
+/*============================================================================
+ * Prepare boot-time firmware configuration data.
+ * o position DPM window
+ * o initialize configuration data area
+ */
+static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo)
+{
+	unsigned char* data;
+
+	if (!sfminfo->datasize) return 0;	/* nothing to do */
+
+	if (sdla_mapmem(hw, sfminfo->dataoffs) != 0)
+		return -EIO
+	;
+	data = (void*)(hw->dpmbase + (sfminfo->dataoffs - hw->vector));
+	memset(data, 0, sfminfo->datasize);
+
+	data[0x00] = make_config_byte(hw);
+	switch (sfminfo->codeid)
+	{
+	case SFID_X25_502:
+	case SFID_X25_508:
+		data[0x01] = 3;			/* T1 timer */
+		data[0x03] = 10;		/* N2 */
+		data[0x06] = 7;			/* HDLC window size */
+		data[0x0B] = 1;			/* DTE */
+		data[0x0C] = 2;			/* X.25 packet window size */
+		*(short*)&data[0x0D] = 128;	/* default X.25 data size */
+		*(short*)&data[0x0F] = 128;	/* maximum X.25 data size */
+		break;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Prepare configuration byte identifying adapter type and CPU clock rate.
+ */
+static unsigned char make_config_byte (sdlahw_t* hw)
+{
+	unsigned char byte = 0;
+
+	switch (hw->pclk)
+	{
+		case 5000:  byte = 0x01; break;
+		case 7200:  byte = 0x02; break;
+		case 8000:  byte = 0x03; break;
+		case 10000: byte = 0x04; break;
+		case 16000: byte = 0x05; break;
+	}
+	switch (hw->type)
+	{
+		case SDLA_S502E: byte |= 0x80; break;
+		case SDLA_S503:  byte |= 0x40; break;
+	}
+	return byte;
+}
+
+/*============================================================================
+ * Start adapter's CPU.
+ * o calculate a pointer to adapter's cold boot entry point
+ * o position DPM window
+ * o place boot instruction (jp addr) at cold boot entry point
+ * o start CPU
+ */
+static int sdla_start (sdlahw_t* hw, unsigned addr)
+{
+	unsigned port = hw->port;
+	unsigned char* bootp;
+	int err, tmp, i;
+
+	if (!port) return -EFAULT;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		bootp = (void*)(hw->dpmbase + 0x66);
+		break;
+
+	case SDLA_S502E:
+	case SDLA_S503:
+	case SDLA_S507:
+	case SDLA_S508:
+		bootp = (void*)hw->dpmbase;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	err = sdla_mapmem(hw, 0);
+	if (err) return err;
+
+	*bootp = 0xC3;	 /* Z80: 'jp' opcode */
+	bootp++;
+	*((unsigned short*)(bootp)) = addr;
+
+	switch (hw->type)
+	{
+	case SDLA_S502A:
+		_OUTB(port, 0x10);		/* issue NMI to CPU */
+		hw->regs[0] = 0x10;
+		break;
+
+	case SDLA_S502E:
+		_OUTB(port + 3, 0x01);		/* start CPU */
+		hw->regs[3] = 0x01;
+		for (i = 0; i < SDLA_IODELAY; ++i);
+		if (_INB(port) & 0x01)		/* verify */
+		{
+			/*
+			 * Enabling CPU changes functionality of the
+			 * control register, so we have to reset its
+			 * mirror.
+			 */
+			_OUTB(port, 0);		/* disable interrupts */
+			hw->regs[0] = 0;
+		}
+		else return -EIO;
+		break;
+
+	case SDLA_S503:
+		tmp = hw->regs[0] | 0x09;	/* set bits 0 and 3 */
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;		/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);
+		if (!(_INB(port) & 0x01))	/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S507:
+		tmp = hw->regs[0] | 0x02;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;		/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);
+		if (!(_INB(port) & 0x04))	/* verify */
+			return -EIO
+		;
+		break;
+
+	case SDLA_S508:
+		tmp = hw->regs[0] | 0x02;
+		_OUTB(port, tmp);
+		hw->regs[0] = tmp;	/* update mirror */
+		for (i = 0; i < SDLA_IODELAY; ++i);
+		if (!(_INB(port + 1) & 0x02))	/* verify */
+			return -EIO
+		;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Initialize S502A adapter.
+ */
+static int init_s502a (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	if (!detect_s502a(port))
+		return -ENODEV
+	;
+	hw->regs[0] = 0x08;
+	hw->regs[1] = 0xFF;
+
+	/* Verify configuration options */
+	i = get_option_index(s502a_dpmbase_options, hw->dpmbase);
+	if (i == 0)
+		return -EINVAL
+	;
+
+	tmp = s502a_hmcr[i - 1];
+	switch (hw->dpmsize)
+	{
+	case 0x2000:
+		tmp |= 0x01;
+		break;
+
+	case 0x10000L:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Setup dual-port memory window (this also enables memory access) */
+	_OUTB(port + 1, tmp);
+	hw->regs[1] = tmp;
+	hw->regs[0] = 0x08;
+	return 0;
+}
+
+/*============================================================================
+ * Initialize S502E adapter.
+ */
+static int init_s502e (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	if (!detect_s502e(port))
+		return -ENODEV
+	;
+
+	/* Verify configuration options */
+	i = get_option_index(s508_dpmbase_options, hw->dpmbase);
+	if (i == 0)
+		return -EINVAL
+	;
+
+	tmp = s502e_hmcr[i - 1];
+	switch (hw->dpmsize)
+	{
+	case 0x2000:
+		tmp |= 0x01;
+		break;
+
+	case 0x10000L:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Setup dual-port memory window */
+	_OUTB(port + 1, tmp);
+	hw->regs[1] = tmp;
+
+	/* Enable memory access */
+	_OUTB(port, 0x02);
+	hw->regs[0] = 0x02;
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	return (_INB(port) & 0x02) ? 0 : -EIO;
+}
+
+/*============================================================================
+ * Initialize S503 adapter.
+ * ---------------------------------------------------------------------------
+ */
+static int init_s503 (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	if (!detect_s503(port))
+		return -ENODEV
+	;
+
+	/* Verify configuration options */
+	i = get_option_index(s508_dpmbase_options, hw->dpmbase);
+	if (i == 0)
+		return -EINVAL
+	;
+
+	tmp = s502e_hmcr[i - 1];
+	switch (hw->dpmsize)
+	{
+	case 0x2000:
+		tmp |= 0x01;
+		break;
+
+	case 0x10000L:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Setup dual-port memory window */
+	_OUTB(port + 1, tmp);
+	hw->regs[1] = tmp;
+
+	/* Enable memory access */
+	_OUTB(port, 0x02);
+	hw->regs[0] = 0x02;	/* update mirror */
+	return 0;
+}
+
+/*============================================================================
+ * Initialize S507 adapter.
+ */
+static int init_s507 (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	if (!detect_s507(port))
+		return -ENODEV
+	;
+
+	/* Verify configuration options */
+	i = get_option_index(s507_dpmbase_options, hw->dpmbase);
+	if (i == 0)
+		return -EINVAL
+	;
+
+	tmp = s507_hmcr[i - 1];
+	switch (hw->dpmsize)
+	{
+	case 0x2000:
+		tmp |= 0x01;
+		break;
+
+	case 0x10000L:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Enable adapter's logic */
+	_OUTB(port, 0x01);
+	hw->regs[0] = 0x01;
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (!(_INB(port) & 0x20))
+		return -EIO
+	;
+
+	/* Setup dual-port memory window */
+	_OUTB(port + 1, tmp);
+	hw->regs[1] = tmp;
+
+	/* Enable memory access */
+	tmp = hw->regs[0] | 0x04;
+	if (hw->irq)
+	{
+		i = get_option_index(s508_irq_options, hw->irq);
+		if (i) tmp |= s507_irqmask[i - 1];
+	}
+	_OUTB(port, tmp);
+	hw->regs[0] = tmp;		/* update mirror */
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	return (_INB(port) & 0x08) ? 0 : -EIO;
+}
+
+/*============================================================================
+ * Initialize S508 adapter.
+ */
+static int init_s508 (sdlahw_t* hw)
+{
+	unsigned port = hw->port;
+	int tmp, i;
+
+	if (!detect_s508(port))
+		return -ENODEV
+	;
+
+	/* Verify configuration options */
+	i = get_option_index(s508_dpmbase_options, hw->dpmbase);
+	if (i == 0)
+		return -EINVAL
+	;
+
+	/* Setup memory configuration */
+	tmp = s508_hmcr[i - 1];
+	_OUTB(port + 1, tmp);
+	hw->regs[1] = tmp;
+
+	/* Enable memory access */
+	_OUTB(port, 0x04);
+	hw->regs[0] = 0x04;		/* update mirror */
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	return (_INB(port + 1) & 0x04) ? 0 : -EIO;
+}
+
+/*============================================================================
+ * Detect S502A adapter.
+ *	Following tests are used to detect S502A adapter:
+ *	1. All registers other than status (BASE) should read 0xFF
+ *	2. After writing 00001000b to control register, status register should
+ *	   read 01000000b.
+ *	3. After writing 0 to control register, status register should still
+ *	   read  01000000b.
+ *	4. After writing 00000100b to control register, status register should
+ *	   read 01000100b.
+ *	Return 1 if detected o.k. or 0 if failed.
+ *	Note:	This test is destructive! Adapter will be left in shutdown
+ *		state after the test.
+ */
+static int detect_s502a (int port)
+{
+	int i, j;
+
+	if (!get_option_index(s502_port_options, port))
+		return 0
+	;
+	for (j = 1; j < SDLA_MAXIORANGE; ++j)
+	{
+		if (_INB(port + j) != 0xFF)
+			return 0
+		;
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	}
+
+	_OUTB(port, 0x08);			/* halt CPU */
+	_OUTB(port, 0x08);
+	_OUTB(port, 0x08);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0x40)
+		return 0
+	;
+	_OUTB(port, 0x00);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0x40)
+		return 0
+	;
+	_OUTB(port, 0x04);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0x44)
+		return 0
+	;
+
+	/* Reset adapter */
+	_OUTB(port, 0x08);
+	_OUTB(port, 0x08);
+	_OUTB(port, 0x08);
+	_OUTB(port + 1, 0xFF);
+	return 1;
+}
+
+/*============================================================================
+ * Detect S502E adapter.
+ *	Following tests are used to verify adapter presence:
+ *	1. All registers other than status (BASE) should read 0xFF.
+ *	2. After writing 0 to CPU control register (BASE+3), status register
+ *	   (BASE) should read 11111000b.
+ *	3. After writing 00000100b to port BASE (set bit 2), status register
+ *	   (BASE) should read 11111100b.
+ *	Return 1 if detected o.k. or 0 if failed.
+ *	Note:	This test is destructive! Adapter will be left in shutdown
+ *		state after the test.
+ */
+static int detect_s502e (int port)
+{
+	int i, j;
+
+	if (!get_option_index(s502_port_options, port))
+		return 0
+	;
+	for (j = 1; j < SDLA_MAXIORANGE; ++j)
+	{
+		if (_INB(port + j) != 0xFF)
+			return 0
+		;
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	}
+
+	_OUTB(port + 3, 0);			/* CPU control reg. */
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0xF8)			/* read status */
+		return 0
+	;
+	_OUTB(port, 0x04);			/* set bit 2 */
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0xFC)			/* verify */
+		return 0
+	;
+
+	/* Reset adapter */
+	_OUTB(port, 0);
+	return 1;
+}
+
+/*============================================================================
+ * Detect s503 adapter.
+ *	Following tests are used to verify adapter presence:
+ *	1. All registers other than status (BASE) should read 0xFF.
+ *	2. After writing 0 to control register (BASE), status register (BASE)
+ *	   should read 11110000b.
+ *	3. After writing 00000100b (set bit 2) to control register (BASE),
+ *	   status register should read 11110010b.
+ *	Return 1 if detected o.k. or 0 if failed.
+ *	Note:	This test is destructive! Adapter will be left in shutdown
+ *		state after the test.
+ */
+static int detect_s503 (int port)
+{
+	int i, j;
+
+	if (!get_option_index(s503_port_options, port))
+		return 0
+	;
+	for (j = 1; j < SDLA_MAXIORANGE; ++j)
+	{
+		if (_INB(port + j) != 0xFF)
+			return 0
+		;
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	}
+
+	_OUTB(port, 0);				/* reset control reg.*/
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0xF0)			/* read status */
+		return 0
+	;
+	_OUTB(port, 0x04);			/* set bit 2 */
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if (_INB(port) != 0xF2)			/* verify */
+		return 0
+	;
+
+	/* Reset adapter */
+	_OUTB(port, 0);
+	return 1;
+}
+
+/*============================================================================
+ * Detect s507 adapter.
+ *	Following tests are used to detect s507 adapter:
+ *	1. All ports should read the same value.
+ *	2. After writing 0x00 to control register, status register should read
+ *	   ?011000?b.
+ *	3. After writing 0x01 to control register, status register should read
+ *	   ?011001?b.
+ *	Return 1 if detected o.k. or 0 if failed.
+ *	Note:	This test is destructive! Adapter will be left in shutdown
+ *		state after the test.
+ */
+static int detect_s507 (int port)
+{
+	int tmp, i, j;
+
+	if (!get_option_index(s508_port_options, port))
+		return 0
+	;
+	tmp = _INB(port);
+	for (j = 1; j < S507_IORANGE; ++j)
+	{
+		if (_INB(port + j) != tmp)
+			return 0
+		;
+		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	}
+
+	_OUTB(port, 0x00);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if ((_INB(port) & 0x7E) != 0x30)
+		return 0
+	;
+	_OUTB(port, 0x01);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if ((_INB(port) & 0x7E) != 0x32)
+		return 0
+	;
+
+	/* Reset adapter */
+	_OUTB(port, 0x00);
+	return 1;
+}
+
+/*============================================================================
+ * Detect s508 adapter.
+ *	Following tests are used to detect s508 adapter:
+ *	1. After writing 0x00 to control register, status register should read
+ *	   ??000000b.
+ *	2. After writing 0x10 to control register, status register should read
+ *	   ??010000b
+ *	Return 1 if detected o.k. or 0 if failed.
+ *	Note:	This test is destructive! Adapter will be left in shutdown
+ *		state after the test.
+ */
+static int detect_s508 (int port)
+{
+	int i;
+
+	if (!get_option_index(s508_port_options, port))
+		return 0
+	;
+	_OUTB(port, 0x00);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if ((_INB(port + 1) & 0x3F) != 0x00)
+		return 0
+	;
+	_OUTB(port, 0x10);
+	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
+	if ((_INB(port + 1) & 0x3F) != 0x10)
+		return 0
+	;
+
+	/* Reset adapter */
+	_OUTB(port, 0x00);
+	return 1;
+}
+
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * Calibrate SDLA memory access delay.
+ * Count number of idle loops made within 1 second and then calculate the
+ * number of loops that should be made to achive desired delay.
+ */
+static int calibrate_delay (int mks)
+{
+	unsigned int delay;
+	unsigned long stop;
+
+	for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay);
+	return (delay/(1000000L/mks) + 1);
+}
+
+/*============================================================================
+ * Get option's index into the options list.
+ *	Return option's index (1 .. N) or zero if option is invalid.
+ */
+static int get_option_index (unsigned* optlist, unsigned optval)
+{
+	int i;
+
+	for (i = 1; i <= optlist[0]; ++i)
+		if (optlist[i] == optval) return i
+	;
+	return 0;
+}
+
+/*============================================================================
+ * Check memory region to see if it's available. 
+ * Return:	0	ok.
+ */
+static unsigned check_memregion (void* ptr, unsigned len)
+{
+	volatile unsigned char* p = ptr;
+
+	for (; len && (*p == 0xFF); --len, ++p)
+	{
+		*p = 0;			/* attempt to write 0 */
+		if (*p != 0xFF)		/* still has to read 0xFF */
+		{
+			*p = 0xFF;	/* restore original value */
+			break;		/* not good */
+		}
+	}
+	return len;
+}
+
+/*============================================================================
+ * Test memory region.
+ * Return:	size of the region that passed the test.
+ * Note:	Region size must be multiple of 2 !
+ */
+static unsigned test_memregion (void* ptr, unsigned len)
+{
+	volatile unsigned short* w_ptr;
+	unsigned len_w = len >> 1;	/* region len in words */
+	unsigned i;
+
+	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+		*w_ptr = 0xAA55
+	;
+	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+		if (*w_ptr != 0xAA55)
+		{
+			len_w = i;
+			break;
+		}
+	;
+	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+		*w_ptr = 0x55AA
+	;
+	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+		if (*w_ptr != 0x55AA)
+		{
+			len_w = i;
+			break;
+		}
+	;
+	for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) *w_ptr = 0;
+	return len_w << 1;
+}
+
+/*============================================================================
+ * Calculate 16-bit CRC using CCITT polynomial.
+ */
+static unsigned short checksum (unsigned char* buf, unsigned len)
+{
+	unsigned short crc = 0;
+	unsigned mask, flag;
+
+	for (; len; --len, ++buf)
+	{
+		for (mask = 0x80; mask; mask >>= 1)
+		{
+			flag = (crc & 0x8000);
+			crc <<= 1;
+			crc |= ((*buf & mask) ? 1 : 0);
+			if (flag) crc ^= 0x1021;
+		}
+	}
+	return crc;
+}
+
+/****** End *****************************************************************/
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c
--- v2.1.24/linux/drivers/net/sdlamain.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/sdlamain.c	Sun Feb  2 15:18:41 1997
@@ -0,0 +1,587 @@
+/*****************************************************************************
+* sdlamain.c	WANPIPE(tm) Multiprotocol WAN Link Driver.  Main module.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Jan 02, 1997	Gene Kozin	Initial version.
+*****************************************************************************/
+
+#if	!defined(__KERNEL__) || !defined(MODULE)
+#error	This code MUST be compiled as a kernel module!
+#endif
+
+#include <linux/config.h>	/* OS configuration options */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/module.h>	/* support for loadable modules */
+#include <linux/ioport.h>	/* request_region(), release_region() */
+#include <linux/tqueue.h>	/* for kernel task queues */
+#include <linux/router.h>	/* WAN router definitions */
+#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
+#include <asm/segment.h>	/* kernel <-> user copy */
+
+/****** Defines & Macros ****************************************************/
+
+#ifdef	_DEBUG_
+#define	STATIC
+#else
+#define	STATIC		static
+#endif
+
+#define	DRV_VERSION	3		/* version number */
+#define	DRV_RELEASE	0		/* release (minor version) number */
+#define	MAX_CARDS	8		/* max number of adapters */
+
+#ifndef	CONFIG_WANPIPE_CARDS		/* configurable option */
+#define	CONFIG_WANPIPE_CARDS 1
+#endif
+
+#define	CMD_OK		0		/* normal firmware return code */
+#define	CMD_TIMEOUT	0xFF		/* firmware command timed out */
+#define	MAX_CMD_RETRY	10		/* max number of firmware retries */
+
+/****** Function Prototypes *************************************************/
+
+/* Module entry points */
+int init_module (void);
+void cleanup_module (void);
+
+/* WAN link driver entry points */
+static int setup    (wan_device_t* wandev, wandev_conf_t* conf);
+static int shutdown (wan_device_t* wandev);
+static int ioctl    (wan_device_t* wandev, unsigned cmd, unsigned long arg);
+
+/* IOCTL hanlers */
+static int ioctl_dump	(sdla_t* card, sdla_dump_t* u_dump);
+static int ioctl_exec	(sdla_t* card, sdla_exec_t* u_exec);
+
+/* Miscellaneous functions */
+STATIC void sdla_isr	(int irq, void* dev_id, struct pt_regs *regs);
+STATIC void sdla_poll	(void* data);
+
+/****** Global Data **********************************************************
+ * Note: All data must be explicitly initialized!!!
+ */
+
+/* private data */
+static char drvname[]	= "wanpipe";
+static char fullname[]	= "WANPIPE(tm) Multiprotocol Driver";
+static char copyright[]	= "(c) 1995-1996 Sangoma Technologies Inc.";
+static int ncards = CONFIG_WANPIPE_CARDS;
+static int active = 0;			/* number of active cards */
+static sdla_t* card_array = NULL;	/* adapter data space */
+
+/* Task queue element for creating a 'thread' */
+static struct tq_struct sdla_tq =
+{
+	NULL,		/* .next */
+	0,		/* .sync */
+	&sdla_poll,	/* .routine */
+	NULL		/* .data */
+}; 
+
+/******* Kernel Loadable Module Entry Points ********************************/
+
+/*============================================================================
+ * Module 'insert' entry point.
+ * o print announcement
+ * o allocate adapter data space
+ * o initialize static data
+ * o register all cards with WAN router
+ * o calibrate SDLA shared memory access delay.
+ *
+ * Return:	0	Ok
+ *		< 0	error.
+ * Context:	process
+ */
+int init_module (void)
+{
+	int cnt, err = 0;
+
+	printk(KERN_INFO "%s v%u.%u %s\n",
+		fullname, DRV_VERSION, DRV_RELEASE, copyright)
+	;
+
+	/* Verify number of cards and allocate adapter data space */
+	ncards = min(ncards, MAX_CARDS);
+	ncards = max(ncards, 1);
+	card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL);
+	if (card_array == NULL)
+		return -ENOMEM
+	;
+	memset(card_array, 0, sizeof(sdla_t) * ncards);
+
+	/* Register adapters with WAN router */
+	for (cnt = 0; cnt < ncards; ++cnt)
+	{
+		sdla_t* card = &card_array[cnt];
+		wan_device_t* wandev = &card->wandev;
+
+		sprintf(card->devname, "%s%d", drvname, cnt + 1);
+		wandev->magic    = ROUTER_MAGIC;
+		wandev->name     = card->devname;
+		wandev->private  = card;
+		wandev->setup    = &setup;
+		wandev->shutdown = &shutdown;
+		wandev->ioctl    = &ioctl;
+		err = register_wandev(wandev);
+		if (err)
+		{
+			printk(KERN_ERR
+				"%s: %s registration failed with error %d!\n",
+				drvname, card->devname, err)
+			;
+			break;
+		}
+	}
+	if (cnt) ncards = cnt;	/* adjust actual number of cards */
+	else kfree(card_array);
+	return err;
+}
+
+/*============================================================================
+ * Module 'remove' entry point.
+ * o unregister all adapters from the WAN router
+ * o release all remaining system resources
+ */
+void cleanup_module (void)
+{
+	int i;
+
+	for (i = 0; i < ncards; ++i)
+	{
+		sdla_t* card = &card_array[i];
+		unregister_wandev(card->devname);
+	}
+	kfree(card_array);
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Setup/confugure WAN link driver.
+ * o check adapter state
+ * o make sure firmware is present in configuration
+ * o make sure I/O port and IRQ are specified
+ * o make sure I/O region is available
+ * o allocate interrupt vector
+ * o setup SDLA hardware
+ * o call appropriate routine to perform protocol-specific initialization
+ * o mark I/O region as used
+ * o if this is the first active card, then schedule background task
+ *
+ * This function is called when router handles ROUTER_SETUP IOCTL. The
+ * configuration structure is in kernel memory (including extended data, if
+ * any).
+ */
+static int setup (wan_device_t* wandev, wandev_conf_t* conf)
+{
+	sdla_t* card;
+	int err = 0;
+	int irq;
+
+	/* Sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL))
+		return -EFAULT
+	;
+	card = wandev->private;
+	if (wandev->state != WAN_UNCONFIGURED)
+		return -EBUSY		/* already configured */
+	;
+	if (!conf->data_size || (conf->data == NULL))
+	{
+		printk(KERN_ERR
+			"%s: firmware not found in configuration data!\n",
+			wandev->name)
+		;
+		return -EINVAL;
+	}
+	if (conf->ioport <= 0)
+	{
+		printk(KERN_ERR
+			"%s: can't configure without I/O port address!\n",
+			wandev->name)
+		;
+		return -EINVAL;
+	}
+	if (conf->irq <= 0)
+	{
+		printk(KERN_ERR "%s: can't configure without IRQ!\n",
+			wandev->name)
+		;
+		return -EINVAL;
+	}
+
+	/* Make sure I/O port region is available */
+	if (check_region(conf->ioport, SDLA_MAXIORANGE))
+	{
+		printk(KERN_ERR "%s: I/O region 0x%X - 0x%X is in use!\n",
+			wandev->name, conf->ioport,
+			conf->ioport + SDLA_MAXIORANGE)
+		;
+		return -EINVAL;
+	}
+
+	/* Allocate IRQ */
+	irq = (conf->irq == 2) ? 9 : conf->irq;	/* IRQ2 -> IRQ9 */
+	if (request_irq(irq, sdla_isr, 0, wandev->name, card))
+	{
+		printk(KERN_ERR "%s: can't reserve IRQ %d!\n",
+			wandev->name, irq)
+		;
+		return -EINVAL;
+	}
+
+	/* Configure hardware, load firmware, etc. */
+	memset(&card->hw, 0, sizeof(sdlahw_t));
+	card->hw.port    = conf->ioport;
+	card->hw.irq     = (conf->irq == 9) ? 2 : conf->irq;
+	card->hw.dpmbase = conf->maddr;
+	card->hw.dpmsize = SDLA_WINDOWSIZE;
+	card->hw.type    = conf->hw_opt[0];
+	card->hw.pclk    = conf->hw_opt[1];
+	err = sdla_setup(&card->hw, conf->data, conf->data_size);
+	if (err)
+	{
+		free_irq(irq, card);
+		return err;
+	}
+
+	/* Intialize WAN device data space */
+	wandev->irq       = irq;
+	wandev->dma       = 0;
+	wandev->ioport    = card->hw.port;
+	wandev->maddr     = card->hw.dpmbase;
+	wandev->msize     = card->hw.dpmsize;
+	wandev->hw_opt[0] = card->hw.type;
+	wandev->hw_opt[1] = card->hw.pclk;
+	wandev->hw_opt[2] = card->hw.memory;
+	wandev->hw_opt[3] = card->hw.fwid;
+
+	/* Protocol-specific initialization */
+	switch (card->hw.fwid)
+	{
+#ifdef	CONFIG_WANPIPE_X25
+	case SFID_X25_502:
+	case SFID_X25_508:
+		err = wpx_init(card, conf);
+		break;
+#endif
+
+#ifdef	CONFIG_WANPIPE_FR
+	case SFID_FR502:
+	case SFID_FR508:
+		err = wpf_init(card, conf);
+		break;
+#endif
+
+#ifdef	CONFIG_WANPIPE_PPP
+	case SFID_PPP502:
+	case SFID_PPP508:
+		err = wpp_init(card, conf);
+		break;
+#endif
+
+	default:
+		printk(KERN_ERR "%s: this firmware is not supported!\n",
+			wandev->name)
+		;
+		err = -EINVAL;
+	}
+	if (err)
+	{
+		sdla_down(&card->hw);
+		free_irq(irq, card);
+		return err;
+	}
+  	/* Reserve I/O region and schedule background task */
+	request_region(card->hw.port, card->hw.io_range, wandev->name);
+	if (++active == 1)
+		queue_task(&sdla_tq, &tq_scheduler)
+	;
+	wandev->critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Shut down WAN link driver. 
+ * o shut down adapter hardware
+ * o release system resources.
+ *
+ * This function is called by the router when device is being unregistered or
+ * when it handles ROUTER_DOWN IOCTL.
+ */
+static int shutdown (wan_device_t* wandev)
+{
+	sdla_t* card;
+
+	/* sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT
+	;
+	if (wandev->state == WAN_UNCONFIGURED)
+		return 0
+	;
+	if (set_bit(0, (void*)&wandev->critical))
+		return -EAGAIN
+	;
+	card = wandev->private;
+	wandev->state = WAN_UNCONFIGURED;
+	if (--active == 0) schedule();	/* stop background thread */
+	sdla_down(&card->hw);
+	free_irq(wandev->irq, card);
+	release_region(card->hw.port, card->hw.io_range);
+	wandev->critical = 0;
+	return 0;
+}
+
+/*============================================================================
+ * Driver I/O control. 
+ * o verify arguments
+ * o perform requested action
+ *
+ * This function is called when router handles one of the reserved user
+ * IOCTLs.  Note that 'arg' stil points to user address space.
+ */
+static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg)
+{
+	int err;
+
+	/* sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT
+	;
+	if (wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV
+	;
+	if (set_bit(0, (void*)&wandev->critical))
+		return -EAGAIN
+	;
+	switch (cmd)
+	{
+	case WANPIPE_DUMP:
+		err = ioctl_dump(wandev->private, (void*)arg);
+		break;
+
+	case WANPIPE_EXEC:
+		err = ioctl_exec(wandev->private, (void*)arg);
+		break;
+
+	default:
+		err = -EINVAL;
+	}
+	wandev->critical = 0;
+	return err;
+}
+
+/****** Driver IOCTL Hanlers ************************************************/
+
+/*============================================================================
+ * Dump adpater memory to user buffer.
+ * o verify request structure
+ * o copy request structure to kernel data space
+ * o verify length/offset
+ * o verify user buffer
+ * o copy adapter memory image to user buffer
+ *
+ * Note: when dumping memory, this routine switches curent dual-port memory
+ *	 vector, so care must be taken to avoid racing conditions.
+ */
+static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump)
+{
+	sdla_dump_t dump;
+	unsigned winsize;
+	unsigned long oldvec;	/* DPM window vector */
+	int err = 0;
+
+	if ((u_dump == NULL) ||
+	    verify_area(VERIFY_READ, u_dump, sizeof(sdla_dump_t)))
+		return -EFAULT
+	;
+	memcpy_fromfs((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t));
+	if ((dump.magic != WANPIPE_MAGIC) ||
+	    (dump.offset + dump.length > card->hw.memory))
+		return -EINVAL
+	;
+	if ((dump.ptr == NULL) ||
+	    verify_area(VERIFY_WRITE, dump.ptr, dump.length))
+		return -EFAULT
+	;
+
+	winsize = card->hw.dpmsize;
+        cli();				/* >>> critical section start <<< */
+	oldvec = card->hw.vector;
+	while (dump.length)
+	{
+		unsigned pos = dump.offset % winsize;	/* current offset */
+		unsigned long vec = dump.offset - pos;	/* current vector */
+		unsigned len = (dump.length > (winsize - pos)) ?
+			(winsize - pos) : dump.length
+		;
+		if (sdla_mapmem(&card->hw, vec) != 0)	/* relocate window */
+		{
+			err = -EIO;
+			break;
+		}
+		memcpy_tofs((void*)(dump.ptr),
+			(void*)(card->hw.dpmbase + pos), len)
+		;
+		dump.length     -= len;
+		dump.offset     += len;
+		(char*)dump.ptr += len;
+	}
+	sdla_mapmem(&card->hw, oldvec);	/* restore DPM window position */
+	sti();				/* >>> critical section end <<< */
+	return err;
+}
+
+/*============================================================================
+ * Execute adapter firmware command.
+ * o verify request structure
+ * o copy request structure to kernel data space
+ * o call protocol-specific 'exec' function
+ */
+static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec)
+{
+	sdla_exec_t exec;
+
+	if (card->exec == NULL)
+		return -ENODEV
+	;
+	if ((u_exec == NULL) ||
+	    verify_area(VERIFY_READ, u_exec, sizeof(sdla_exec_t)))
+		return -EFAULT
+	;
+	memcpy_fromfs((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t));
+	if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL))
+		return -EINVAL
+	;
+	return card->exec(card, exec.cmd, exec.data);
+}
+
+/******* Miscellaneous ******************************************************/
+
+/*============================================================================
+ * SDLA Interrupt Service Routine.
+ * o acknowledge SDLA hardware interrupt.
+ * o call protocol-specific interrupt service routine, if any.
+ */
+STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs)
+{
+#define	card	((sdla_t*)dev_id)
+
+	if (!card || (card->wandev.state == WAN_UNCONFIGURED))
+		return
+	;
+	if (card->in_isr)
+	{
+		printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n",
+			card->devname, card->wandev.irq)
+		;
+		return;
+	}
+	card->in_isr = 1;
+	sdla_intack(&card->hw);
+	if (card->isr) card->isr(card);
+	card->in_isr = 0;
+
+#undef	card
+}
+
+/*============================================================================
+ * SDLA polling routine.
+ * This routine simulates kernel thread to perform various housekeeping job.
+ *
+ * o for each configured device call its poll() routine
+ * o if there is at least one active card, then reschedule itself once again
+ */
+STATIC void sdla_poll (void* data)
+{
+	int i;
+
+	for (i = 0; i < ncards; ++i)
+	{
+		sdla_t* card = &card_array[i];
+
+		if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll &&
+		    !set_bit(0, (void*)&card->wandev.critical))
+		{
+			card->poll(card);
+			card->wandev.critical = 0;
+		}
+	}
+	if (active) queue_task(&sdla_tq, &tq_scheduler);
+}
+
+/*============================================================================
+ * This routine is called by the protocol-specific modules when network
+ * interface is being open.  The only reason we need this, is because we
+ * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's
+ * defined more than once into the same kernel module.
+ */
+void wanpipe_open (sdla_t* card)
+{
+	++card->open_cnt;
+	MOD_INC_USE_COUNT;
+}
+
+/*============================================================================
+ * This routine is called by the protocol-specific modules when network
+ * interface is being closed.  The only reason we need this, is because we
+ * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's
+ * defined more than once into the same kernel module.
+ */
+void wanpipe_close (sdla_t* card)
+{
+	--card->open_cnt;
+	MOD_DEC_USE_COUNT;
+}
+
+/*============================================================================
+ * Set WAN device state.
+ */
+void wanpipe_set_state (sdla_t* card, int state)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (card->wandev.state != state)
+	{
+		switch (state)
+		{
+		case WAN_CONNECTED:
+			printk (KERN_INFO "%s: link connected!\n",
+				card->devname)
+			;
+			break;
+
+		case WAN_CONNECTING:
+			printk (KERN_INFO "%s: link connecting...\n",
+				card->devname)
+			;
+			break;
+
+		case WAN_DISCONNECTED:
+			printk (KERN_INFO "%s: link disconnected!\n",
+				card->devname)
+			;
+			break;
+		}
+		card->wandev.state = state;
+	}
+	card->state_tick = jiffies;
+	restore_flags(flags);
+}
+
+/****** End *****************************************************************/
diff -u --recursive --new-file v2.1.24/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v2.1.24/linux/drivers/net/seeq8005.c	Wed Oct  9 08:55:20 1996
+++ linux/drivers/net/seeq8005.c	Sun Feb  2 15:18:41 1997
@@ -64,7 +64,7 @@
 
 /* Information that need to be kept for each board. */
 struct net_local {
-	struct enet_statistics stats;
+	struct net_driver_stats stats;
 	unsigned short receive_ptr;		/* What address in packet memory do we expect a recv_pkt_header? */
 	long open_time;				/* Useless example local info. */
 };
@@ -84,7 +84,7 @@
 static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void seeq8005_rx(struct device *dev);
 static int seeq8005_close(struct device *dev);
-static struct enet_statistics *seeq8005_get_stats(struct device *dev);
+static struct net_driver_stats *seeq8005_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 /* Example routines you must write ;->. */
@@ -593,8 +593,7 @@
 
 /* Get the current statistics.	This may be called with the card open or
    closed. */
-static struct enet_statistics *
-seeq8005_get_stats(struct device *dev)
+static struct net_driver_stats *seeq8005_get_stats(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/shaper.c linux/drivers/net/shaper.c
--- v2.1.24/linux/drivers/net/shaper.c	Thu Jan  2 15:55:19 1997
+++ linux/drivers/net/shaper.c	Sun Feb  2 15:18:41 1997
@@ -416,7 +416,7 @@
 	return shaper_qframe(sh, skb);
 }
 
-static struct enet_statistics *shaper_get_stats(struct device *dev)
+static struct net_device_stats *shaper_get_stats(struct device *dev)
 {
 	return NULL;
 }
diff -u --recursive --new-file v2.1.24/linux/drivers/net/shaper.h linux/drivers/net/shaper.h
--- v2.1.24/linux/drivers/net/shaper.h	Thu Dec 12 19:37:06 1996
+++ linux/drivers/net/shaper.h	Sun Feb  2 15:18:42 1997
@@ -36,7 +36,7 @@
 	int (*hard_header_cache)(struct dst_entry *dst, struct dst_entry *neigh,
 		struct hh_cache *hh);
 	void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char *  haddr);
-	struct enet_statistics* (*get_stats)(struct device *dev);
+	struct net_device_stats* (*get_stats)(struct device *dev);
 	struct wait_queue *wait_queue;
 	struct timer_list timer;
 };
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.1.24/linux/drivers/net/sk_g16.c	Wed Oct  9 08:55:20 1996
+++ linux/drivers/net/sk_g16.c	Sun Feb  2 15:18:42 1997
@@ -457,7 +457,7 @@
     int        tmdlast;  /* last sent descriptor used for error handling, etc */
     void       *rmdbufs[RMDNUM]; /* pointer to the receive buffers */
     void       *tmdbufs[TMDNUM]; /* pointer to the transmit buffers */
-    struct enet_statistics stats; /* Device driver statistics */
+    struct net_driver_stats stats; /* Device driver statistics */
 };
 
 /* global variable declaration */
@@ -491,7 +491,7 @@
 static void  SK_txintr(struct device *dev);
 static int   SK_close(struct device *dev);
 
-static struct enet_statistics *SK_get_stats(struct device *dev);
+static struct net_driver_stats *SK_get_stats(struct device *dev);
 
 unsigned int SK_rom_addr(void);
 
@@ -1681,14 +1681,14 @@
  *                  It is called by sprintf_stats (dev.c).
  *
  * Parameters     : I : struct device *dev   - our device structure
- * Return Value   : struct enet_statistics * - our current statistics
+ * Return Value   : struct net_driver_stats * - our current statistics
  * Errors         : None
  * Side Effects   : None
  * Update History :
  *     YY/MM/DD  uid  Description
 -*/
 
-static struct enet_statistics *SK_get_stats(struct device *dev)
+static struct net_driver_stats *SK_get_stats(struct device *dev)
 {
 
     struct priv *p = (struct priv *) dev->priv;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c
--- v2.1.24/linux/drivers/net/skeleton.c	Wed Oct  9 08:55:20 1996
+++ linux/drivers/net/skeleton.c	Sun Feb  2 15:18:42 1997
@@ -84,7 +84,7 @@
 
 /* Information that need to be kept for each board. */
 struct net_local {
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	long open_time;			/* Useless example local info. */
 };
 
@@ -97,19 +97,19 @@
 
 extern int netcard_probe(struct device *dev);
 
-static int netcard_probe1(struct device *dev, int ioaddr);
-static int net_open(struct device *dev);
+static int	netcard_probe1(struct device *dev, int ioaddr);
+static int	net_open(struct device *dev);
 static int	net_send_packet(struct sk_buff *skb, struct device *dev);
-static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void net_rx(struct device *dev);
-static int net_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
-static void set_multicast_list(struct device *dev);
+static void	net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void	net_rx(struct device *dev);
+static int	net_close(struct device *dev);
+static struct	net_device_stats *net_get_stats(struct device *dev);
+static void	set_multicast_list(struct device *dev);
 
 /* Example routines you must write ;->. */
 #define tx_done(dev) 1
 extern void	hardware_send_packet(short ioaddr, char *buf, int length);
-extern void chipset_init(struct device *dev, int startp);
+extern void 	chipset_init(struct device *dev, int startp);
 
 /*
  * Check for a network adaptor of this type, and return '0' iff one exists.
@@ -286,8 +286,8 @@
 
 	dev->open		= net_open;
 	dev->stop		= net_close;
-	dev->hard_start_xmit = net_send_packet;
-	dev->get_stats	= net_get_stats;
+	dev->hard_start_xmit	= net_send_packet;
+	dev->get_stats		= net_get_stats;
 	dev->set_multicast_list = &set_multicast_list;
 
 	/* Fill in the fields of the device structure with ethernet values. */
@@ -340,8 +340,7 @@
 	return 0;
 }
 
-static int
-net_send_packet(struct sk_buff *skb, struct device *dev)
+static int net_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int ioaddr = dev->base_addr;
@@ -361,15 +360,7 @@
 		dev->tbusy=0;
 		dev->trans_start = jiffies;
 	}
-	/*
-	 * 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.
@@ -379,7 +370,7 @@
 	else {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		unsigned char *buf = skb->data;
-
+		lp->stats.tx_bytes+=skb->len;
 		hardware_send_packet(ioaddr, buf, length);
 		dev->trans_start = jiffies;
 	}
@@ -396,8 +387,7 @@
  * The typical workload of the driver:
  *   Handle the network interface interrupts.
  */
-static void
-net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct device *dev = (struct device *)(irq2dev_map[irq]);
 	struct net_local *lp;
@@ -458,6 +448,8 @@
 			/* Malloc up new buffer. */
 			struct sk_buff *skb;
 
+			lp->stats.rx_bytes+=pkt_len;
+			
 			skb = dev_alloc_skb(pkt_len);
 			if (skb == NULL) {
 				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
@@ -522,8 +514,7 @@
  * Get the current statistics.
  * This may be called with the card open or closed.
  */
-static struct enet_statistics *
-net_get_stats(struct device *dev)
+static struct net_device_stats *net_get_stats(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	short ioaddr = dev->base_addr;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v2.1.24/linux/drivers/net/slip.c	Tue Jan 28 18:50:02 1997
+++ linux/drivers/net/slip.c	Sun Feb  2 15:18:42 1997
@@ -372,6 +372,8 @@
 	}
 #endif  /* SL_INCLUDE_CSLIP */
 
+	sl->rx_bytes+=count;
+	
 	skb = dev_alloc_skb(count);
 	if (skb == NULL)  {
 		printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);
@@ -508,8 +510,10 @@
 	}
 
 	/* We were not busy, so we are now... :-) */
-	if (skb != NULL) {
+	if (skb != NULL) 
+	{
 		sl_lock(sl);
+		sl->tx_bytes+=skb->len;
 		sl_encaps(sl, skb->data, skb->len);
 		dev_kfree_skb(skb, FREE_WRITE);
 	}
@@ -625,8 +629,7 @@
 	return 0;
 }
 
-static int
-slip_receive_room(struct tty_struct *tty)
+static int slip_receive_room(struct tty_struct *tty)
 {
 	return 65536;  /* We can handle an infinite amount of data. :-) */
 }
@@ -637,8 +640,8 @@
  * a block of SLIP data has been received, which can now be decapsulated
  * and sent on to some IP layer for further processing.
  */
-static void
-slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+ 
+static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
 {
 	struct slip *sl = (struct slip *) tty->disc_data;
 
@@ -752,19 +755,21 @@
 }
 
 
-static struct enet_statistics *
+static struct net_device_stats *
 sl_get_stats(struct device *dev)
 {
-	static struct enet_statistics stats;
+	static struct net_device_stats stats;
 	struct slip *sl = (struct slip*)(dev->priv);
 #ifdef SL_INCLUDE_CSLIP
 	struct slcompress *comp;
 #endif
 
-	memset(&stats, 0, sizeof(struct enet_statistics));
+	memset(&stats, 0, sizeof(struct net_device_stats));
 
 	stats.rx_packets     = sl->rx_packets;
 	stats.tx_packets     = sl->tx_packets;
+	stats.rx_bytes	     = sl->rx_bytes;
+	stats.tx_bytes	     = sl->tx_bytes;
 	stats.rx_dropped     = sl->rx_dropped;
 	stats.tx_dropped     = sl->tx_dropped;
 	stats.tx_errors      = sl->tx_errors;
@@ -828,8 +833,7 @@
 	return (ptr - d);
 }
 
-static void
-slip_unesc(struct slip *sl, unsigned char s)
+static void slip_unesc(struct slip *sl, unsigned char s)
 {
 
 	switch(s) {
diff -u --recursive --new-file v2.1.24/linux/drivers/net/slip.h linux/drivers/net/slip.h
--- v2.1.24/linux/drivers/net/slip.h	Wed Dec 18 15:58:47 1996
+++ linux/drivers/net/slip.h	Sun Feb  2 15:18:42 1997
@@ -68,6 +68,8 @@
   /* SLIP interface statistics. */
   unsigned long		rx_packets;	/* inbound frames counter	*/
   unsigned long         tx_packets;     /* outbound frames counter      */
+  unsigned long		rx_bytes;	/* inbound byte counte		*/
+  unsigned long         tx_bytes;       /* outbound byte counter	*/
   unsigned long         rx_errors;      /* Parity, etc. errors          */
   unsigned long         tx_errors;      /* Planned stuff                */
   unsigned long         rx_dropped;     /* No memory for skb            */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c
--- v2.1.24/linux/drivers/net/smc9194.c	Tue Dec 31 21:41:06 1996
+++ linux/drivers/net/smc9194.c	Sun Feb  2 15:18:42 1997
@@ -175,7 +175,7 @@
 	   can find out semi-useless statistics of how well the card is
 	   performing
  	*/
-	struct enet_statistics stats;
+	struct net_driver_stats stats;
 
 	/*
 	   If I have to wait until memory is available to send
@@ -234,7 +234,7 @@
  . This routine allows the proc file system to query the driver's
  . statistics.
 */
-static struct enet_statistics * smc_query_statistics( struct device *dev);
+static struct net_driver_stats * smc_query_statistics( struct device *dev);
 
 /*
  . Finally, a call to set promiscuous mode ( for TCPDUMP and related
@@ -1643,7 +1643,7 @@
  . Get the current statistics.
  . This may be called with the card open or closed.
  .-------------------------------------------------------------*/
-static struct enet_statistics * smc_query_statistics(struct device *dev) {
+static struct net_driver_stats* smc_query_statistics(struct device *dev) {
 	struct smc_local *lp = (struct smc_local *)dev->priv;
 
 	return &lp->stats;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/strip.c linux/drivers/net/strip.c
--- v2.1.24/linux/drivers/net/strip.c	Tue Jan 28 18:50:02 1997
+++ linux/drivers/net/strip.c	Sun Feb  2 15:18:42 1997
@@ -1,5 +1,3 @@
-#error "Doesn't run with 2.1.x"
-
 /*
  * Copyright 1996 The Board of Trustees of The Leland Stanford
  * Junior University. All Rights Reserved.
@@ -1623,20 +1621,12 @@
      */
     if (haddr.c[0] == 0xFF)
     {
-        /*IPaddr a;
-        a.l = strip_info->dev.pa_brdaddr;
-        printk(KERN_INFO "%s: Broadcast packet! Sending to %d.%d.%d.%d\n",
-                strip_info->dev.name, a.b[0], a.b[1], a.b[2], a.b[3]);*/
-
-        if (!arp_query(haddr.c, strip_info->dev.pa_brdaddr, &strip_info->dev))
-        {
-            /*IPaddr a;
-            a.l = strip_info->dev.pa_brdaddr;
-            printk(KERN_INFO "%s: No ARP cache entry for %d.%d.%d.%d\n",
-                strip_info->dev.name, a.b[0], a.b[1], a.b[2], a.b[3]);
-            strip_info->tx_dropped++;*/
-            return(NULL);
-        }
+	    memcpy(haddr.c, dev->broadcast, sizeof(haddr));
+	    if (haddr.c[0] == 0xFF)
+	    {
+		    strip_info->tx_dropped++;
+		    return(NULL);
+	    }
     }
 
     *ptr++ = '*';
@@ -2294,12 +2284,12 @@
     return -1;        /* You cannot override a Metricom radio's address */
 }
 
-static struct enet_statistics *strip_get_stats(struct device *dev)
+static struct net_device_stats *strip_get_stats(struct device *dev)
 {
-    static struct enet_statistics stats;
+    static struct net_device_stats stats;
     struct strip *strip_info = (struct strip *)(dev->priv);
 
-    memset(&stats, 0, sizeof(struct enet_statistics));
+    memset(&stats, 0, sizeof(struct net_device_stats));
 
     stats.rx_packets     = strip_info->rx_packets;
     stats.tx_packets     = strip_info->tx_packets;
@@ -2355,12 +2345,6 @@
     strip_info->sx_count = 0;
     strip_info->tx_left  = 0;
 
-    /*
-     * Needed because address '0' is special
-     */
-
-    if (dev->pa_addr == 0)
-        dev->pa_addr=ntohl(0xC0A80001);
     dev->tbusy  = 0;
     dev->start  = 1;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.1.24/linux/drivers/net/sunhme.c	Wed Dec 18 15:58:47 1996
+++ linux/drivers/net/sunhme.c	Sun Feb  2 15:18:42 1997
@@ -573,7 +573,7 @@
 static void happy_meal_get_counters(struct happy_meal *hp,
 				    struct hmeal_bigmacregs *bregs)
 {
-	struct enet_statistics *stats = &hp->enet_stats;
+	struct net_device_stats *stats = &hp->net_stats;
 
 	stats->rx_crc_errors += bregs->rcrce_ctr;
 	bregs->rcrce_ctr = 0;
@@ -1501,9 +1501,11 @@
 			break;
 		skb = hp->tx_skbs[elem];
 		hp->tx_skbs[elem] = NULL;
+		hp->net_stats.tx_bytes+=skb->len;
+		
 		dev_kfree_skb(skb, FREE_WRITE);
 
-		hp->enet_stats.tx_packets++;
+		hp->net_stats.tx_packets++;
 		elem = NEXT_TX(elem);
 	}
 	hp->tx_old = elem;
@@ -1525,7 +1527,7 @@
 		if(this->tx_flags & TXFLAG_OWN)
 			break;
 
-		hp->enet_stats.tx_packets++;
+		hp->net_stats.tx_packets++;
 		elem = NEXT_TX(elem);
 	}
 	hp->tx_old = elem;
@@ -1562,17 +1564,17 @@
 		/* Check for errors. */
 		if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) {
 			RXD(("ERR(%08lx)]", flags));
-			hp->enet_stats.rx_errors++;
+			hp->net_stats.rx_errors++;
 			if(len < ETH_ZLEN)
-				hp->enet_stats.rx_length_errors++;
+				hp->net_stats.rx_length_errors++;
 			if(len & (RXFLAG_OVERFLOW >> 16)) {
-				hp->enet_stats.rx_over_errors++;
-				hp->enet_stats.rx_fifo_errors++;
+				hp->net_stats.rx_over_errors++;
+				hp->net_stats.rx_fifo_errors++;
 			}
 
 			/* Return it to the Happy meal. */
 	drop_it:
-			hp->enet_stats.rx_dropped++;
+			hp->net_stats.rx_dropped++;
 			this->rx_addr = (unsigned int) hp->rx_skbs[elem]->data;
 			this->rx_flags =
 				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
@@ -1630,7 +1632,7 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
 
-		hp->enet_stats.rx_packets++;
+		hp->net_stats.rx_packets++;
 	next:
 		elem = NEXT_RX(elem);
 		this = &rxbase[elem];
@@ -1662,20 +1664,20 @@
 		/* Check for errors. */
 		if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) {
 			RXD(("ERR(%08lx)]", flags));
-			hp->enet_stats.rx_errors++;
+			hp->net_stats.rx_errors++;
 			if(len < ETH_ZLEN)
-				hp->enet_stats.rx_length_errors++;
+				hp->net_stats.rx_length_errors++;
 			if(len & (RXFLAG_OVERFLOW >> 16)) {
-				hp->enet_stats.rx_over_errors++;
-				hp->enet_stats.rx_fifo_errors++;
+				hp->net_stats.rx_over_errors++;
+				hp->net_stats.rx_fifo_errors++;
 			}
 
-			hp->enet_stats.rx_dropped++;
+			hp->net_stats.rx_dropped++;
 		} else {
 			skb = dev_alloc_skb(len + 2);
 			if(skb == 0) {
 				drops++;
-				hp->enet_stats.rx_dropped++;
+				hp->net_stats.rx_dropped++;
 			} else {
 				RXD(("len=%d]", len));
 				skb->dev = hp->dev;
@@ -1684,7 +1686,7 @@
 				eth_copy_and_sum(skb, (thisbuf+2), len, 0);
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
-				hp->enet_stats.rx_packets++;
+				hp->net_stats.rx_packets++;
 			}
 		}
 		/* Return the buffer to the Happy Meal. */
@@ -1846,7 +1848,7 @@
 			return 1;
 		} else {
 			printk ("%s: transmit timed out, resetting\n", dev->name);
-			hp->enet_stats.tx_errors++;
+			hp->net_stats.tx_errors++;
 			happy_meal_init(hp, 0);
 			dev->tbusy = 0;
 			dev->trans_start = jiffies;
@@ -1854,12 +1856,6 @@
 		}
 	}
 
-	if(skb == NULL || skb->len <= 0) {
-		printk("%s: skb is NULL\n", dev->name);
-		dev_tint(dev);
-		return 0;
-	}
-
 	if(set_bit(0, (void *) &dev->tbusy) != 0) {
 		printk("happy meal: Transmitter access conflict.\n");
 		return 1;
@@ -1902,7 +1898,7 @@
 			return 1;
 		} else {
 			printk ("%s: transmit timed out, resetting\n", dev->name);
-			hp->enet_stats.tx_errors++;
+			hp->net_stats.tx_errors++;
 			happy_meal_init(hp, 0);
 			dev->tbusy = 0;
 			dev->trans_start = jiffies;
@@ -1948,12 +1944,12 @@
 	return 0;
 }
 
-static struct enet_statistics *happy_meal_get_stats(struct device *dev)
+static struct net_device_stats *happy_meal_get_stats(struct device *dev)
 {
 	struct happy_meal *hp = (struct happy_meal *) dev->priv;
 
 	happy_meal_get_counters(hp, hp->bigmacregs);
-	return &hp->enet_stats;
+	return &hp->net_stats;
 }
 
 #define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h
--- v2.1.24/linux/drivers/net/sunhme.h	Tue Jan 28 18:50:02 1997
+++ linux/drivers/net/sunhme.h	Sun Feb  2 15:18:42 1997
@@ -540,7 +540,7 @@
 	enum happy_timer_state    timer_state;    /* State of the auto-neg timer.      */
 	unsigned int              timer_ticks;    /* Number of clicks at each state.   */
 
-	struct enet_statistics    enet_stats;     /* Statistical counters              */
+	struct net_device_stats	 enet_stats;     /* Statistical counters              */
 	struct linux_sbus_device *happy_sbus_dev; /* ;-)                               */
 	struct device            *dev;            /* Backpointer                       */
 	struct happy_meal        *next_module;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.1.24/linux/drivers/net/sunlance.c	Tue Jan 28 18:50:06 1997
+++ linux/drivers/net/sunlance.c	Sun Feb  2 15:18:42 1997
@@ -220,7 +220,7 @@
 	int rx_new, tx_new;
 	int rx_old, tx_old;
     
-	struct enet_statistics stats;
+	struct net_device_stats	stats;
 	struct Linux_SBus_DMA *ledma; /* If set this points to ledma    */
 				      /* and arch = sun4m		*/
 
@@ -786,17 +786,6 @@
 		return status;
 	}
 
-	if (skb == NULL) {
-		dev_tint (dev);
-		printk ("skb is NULL\n");
-		return 0;
-	}
-
-	if (skb->len <= 0) {
-		printk ("skb len is %d\n", skb->len);
-		return 0;
-	}
-
 	/* Block a timer-based transmit from overlapping. */
 	if (set_bit (0, (void *) &dev->tbusy) != 0) {
 		printk ("Transmitter access conflict.\n");
@@ -813,6 +802,9 @@
 	}
 
 	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+	
+	lp->stats.tx_bytes+=len;
+	
 	entry = lp->tx_new & TX_RING_MOD_MASK;
 	ib->btx_ring [entry].length = (-len) | 0xf000;
 	ib->btx_ring [entry].misc = 0;
@@ -820,6 +812,7 @@
 	memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
 
 	/* Clear the slack of the packet, do I need this? */
+	/* For a firewall its a good idea - AC */
 	if (len != skblen)
 		memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen);
     
@@ -845,7 +838,7 @@
 	return status;
 }
 
-static struct enet_statistics *lance_get_stats (struct device *dev)
+static struct net_device_stats *lance_get_stats (struct device *dev)
 {
 	struct lance_private *lp = (struct lance_private *) dev->priv;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.1.24/linux/drivers/net/sunqe.c	Wed Dec 18 15:58:48 1996
+++ linux/drivers/net/sunqe.c	Sun Feb  2 15:18:42 1997
@@ -281,31 +281,31 @@
 
 	if(qe_status & CREG_STAT_EDEFER) {
 		printk("%s: Excessive transmit defers.\n", dev->name);
-		qep->enet_stats.tx_errors++;
+		qep->net_stats.tx_errors++;
 	}
 
 	if(qe_status & CREG_STAT_CLOSS) {
 		printk("%s: Carrier lost, link down?\n", dev->name);
-		qep->enet_stats.tx_errors++;
-		qep->enet_stats.tx_carrier_errors++;
+		qep->net_stats.tx_errors++;
+		qep->net_stats.tx_carrier_errors++;
 	}
 
 	if(qe_status & CREG_STAT_ERETRIES) {
 		printk("%s: Excessive transmit retries (more than 16).\n", dev->name);
-		qep->enet_stats.tx_errors++;
+		qep->net_stats.tx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_LCOLL) {
 		printk("%s: Late transmit collision.\n", dev->name);
-		qep->enet_stats.tx_errors++;
-		qep->enet_stats.collisions++;
+		qep->net_stats.tx_errors++;
+		qep->net_stats.collisions++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_FUFLOW) {
 		printk("%s: Transmit fifo underflow, driver bug.\n", dev->name);
-		qep->enet_stats.tx_errors++;
+		qep->net_stats.tx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
@@ -318,104 +318,104 @@
 	}
 
 	if(qe_status & CREG_STAT_CCOFLOW) {
-		qep->enet_stats.tx_errors += 256;
-		qep->enet_stats.collisions += 256;
+		qep->net_stats.tx_errors += 256;
+		qep->net_stats.collisions += 256;
 	}
 
 	if(qe_status & CREG_STAT_TXDERROR) {
 		printk("%s: Transmit descriptor is bogus, driver bug.\n", dev->name);
-		qep->enet_stats.tx_errors++;
-		qep->enet_stats.tx_aborted_errors++;
+		qep->net_stats.tx_errors++;
+		qep->net_stats.tx_aborted_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_TXLERR) {
 		printk("%s: Transmit late error.\n", dev->name);
-		qep->enet_stats.tx_errors++;
+		qep->net_stats.tx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_TXPERR) {
 		printk("%s: Transmit DMA parity error.\n", dev->name);
-		qep->enet_stats.tx_errors++;
-		qep->enet_stats.tx_aborted_errors++;
+		qep->net_stats.tx_errors++;
+		qep->net_stats.tx_aborted_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_TXSERR) {
 		printk("%s: Transmit DMA sbus error ack.\n", dev->name);
-		qep->enet_stats.tx_errors++;
-		qep->enet_stats.tx_aborted_errors++;
+		qep->net_stats.tx_errors++;
+		qep->net_stats.tx_aborted_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_RCCOFLOW) {
-		qep->enet_stats.rx_errors += 256;
-		qep->enet_stats.collisions += 256;
+		qep->net_stats.rx_errors += 256;
+		qep->net_stats.collisions += 256;
 	}
 
 	if(qe_status & CREG_STAT_RUOFLOW) {
-		qep->enet_stats.rx_errors += 256;
-		qep->enet_stats.rx_over_errors += 256;
+		qep->net_stats.rx_errors += 256;
+		qep->net_stats.rx_over_errors += 256;
 	}
 
 	if(qe_status & CREG_STAT_MCOFLOW) {
-		qep->enet_stats.rx_errors += 256;
-		qep->enet_stats.rx_missed_errors += 256;
+		qep->net_stats.rx_errors += 256;
+		qep->net_stats.rx_missed_errors += 256;
 	}
 
 	if(qe_status & CREG_STAT_RXFOFLOW) {
 		printk("%s: Receive fifo overflow.\n", dev->name);
-		qep->enet_stats.rx_errors++;
-		qep->enet_stats.rx_over_errors++;
+		qep->net_stats.rx_errors++;
+		qep->net_stats.rx_over_errors++;
 	}
 
 	if(qe_status & CREG_STAT_RLCOLL) {
 		printk("%s: Late receive collision.\n", dev->name);
-		qep->enet_stats.rx_errors++;
-		qep->enet_stats.collisions++;
+		qep->net_stats.rx_errors++;
+		qep->net_stats.collisions++;
 	}
 
 	if(qe_status & CREG_STAT_FCOFLOW) {
-		qep->enet_stats.rx_errors += 256;
-		qep->enet_stats.rx_frame_errors += 256;
+		qep->net_stats.rx_errors += 256;
+		qep->net_stats.rx_frame_errors += 256;
 	}
 
 	if(qe_status & CREG_STAT_CECOFLOW) {
-		qep->enet_stats.rx_errors += 256;
-		qep->enet_stats.rx_crc_errors += 256;
+		qep->net_stats.rx_errors += 256;
+		qep->net_stats.rx_crc_errors += 256;
 	}
 
 	if(qe_status & CREG_STAT_RXDROP) {
 		printk("%s: Receive packet dropped.\n", dev->name);
-		qep->enet_stats.rx_errors++;
-		qep->enet_stats.rx_dropped++;
-		qep->enet_stats.rx_missed_errors++;
+		qep->net_stats.rx_errors++;
+		qep->net_stats.rx_dropped++;
+		qep->net_stats.rx_missed_errors++;
 	}
 
 	if(qe_status & CREG_STAT_RXSMALL) {
 		printk("%s: Receive buffer too small, driver bug.\n", dev->name);
-		qep->enet_stats.rx_errors++;
-		qep->enet_stats.rx_length_errors++;
+		qep->net_stats.rx_errors++;
+		qep->net_stats.rx_length_errors++;
 	}
 
 	if(qe_status & CREG_STAT_RXLERR) {
 		printk("%s: Receive late error.\n", dev->name);
-		qep->enet_stats.rx_errors++;
+		qep->net_stats.rx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_RXPERR) {
 		printk("%s: Receive DMA parity error.\n", dev->name);
-		qep->enet_stats.rx_errors++;
-		qep->enet_stats.rx_missed_errors++;
+		qep->net_stats.rx_errors++;
+		qep->net_stats.rx_missed_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_RXSERR) {
 		printk("%s: Receive DMA sbus error ack.\n", dev->name);
-		qep->enet_stats.rx_errors++;
-		qep->enet_stats.rx_missed_errors++;
+		qep->net_stats.rx_errors++;
+		qep->net_stats.rx_missed_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
@@ -439,9 +439,10 @@
 			break;
 		skb = qep->tx_skbs[elem];
 		qep->tx_skbs[elem] = NULL;
+		qep->net_stats.tx_bytes+=skb->len;
 		dev_kfree_skb(skb, FREE_WRITE);
 
-		qep->enet_stats.tx_packets++;
+		qep->net_stats.tx_packets++;
 		elem = NEXT_TX(elem);
 	}
 	qep->tx_old = elem;
@@ -457,7 +458,7 @@
 		this = &txbase[elem];
 		if(this->tx_flags & TXD_OWN)
 			break;
-		qep->enet_stats.tx_packets++;
+		qep->net_stats.tx_packets++;
 		elem = NEXT_TX(elem);
 	}
 	qep->tx_old = elem;
@@ -480,12 +481,12 @@
 
 		/* Check for errors. */
 		if(len < ETH_ZLEN) {
-			qep->enet_stats.rx_errors++;
-			qep->enet_stats.rx_length_errors++;
+			qep->net_stats.rx_errors++;
+			qep->net_stats.rx_length_errors++;
 
 	drop_it:
 			/* Return it to the QE. */
-			qep->enet_stats.rx_dropped++;
+			qep->net_stats.rx_dropped++;
 			this->rx_addr = (unsigned int) qep->rx_skbs[elem]->data;
 			this->rx_flags =
 				(RXD_OWN | (RX_BUF_ALLOC_SIZE & RXD_LENGTH));
@@ -536,7 +537,7 @@
 		/* No checksums are done by this card ;-( */
 		skb->protocol = eth_type_trans(skb, qep->dev);
 		netif_rx(skb);
-		qep->enet_stats.rx_packets++;
+		qep->net_stats.rx_packets++;
 	next:
 		elem = NEXT_RX(elem);
 		this = &rxbase[elem];
@@ -565,14 +566,14 @@
 
 		/* Check for errors. */
 		if(len < ETH_ZLEN) {
-			qep->enet_stats.rx_errors++;
-			qep->enet_stats.rx_length_errors++;
-			qep->enet_stats.rx_dropped++;
+			qep->net_stats.rx_errors++;
+			qep->net_stats.rx_length_errors++;
+			qep->net_stats.rx_dropped++;
 		} else {
 			skb = dev_alloc_skb(len + 2);
 			if(skb == 0) {
 				drops++;
-				qep->enet_stats.rx_dropped++;
+				qep->net_stats.rx_dropped++;
 			} else {
 				skb->dev = qep->dev;
 				skb_reserve(skb, 2);
@@ -581,7 +582,7 @@
 						 len, 0);
 				skb->protocol = eth_type_trans(skb, qep->dev);
 				netif_rx(skb);
-				qep->enet_stats.rx_packets++;
+				qep->net_stats.rx_packets++;
 			}
 		}
 		end_rxd->rx_addr = (unsigned int) this_qbuf;
@@ -710,12 +711,6 @@
 	if(dev->tbusy)
 		return 1;
 
-	if(skb == NULL || skb->len <= 0) {
-		printk("%s: skb is NULL\n", dev->name);
-		dev_tint(dev);
-		return 0;
-	}
-
 	if(set_bit(0, (void *) &dev->tbusy) != 0) {
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
@@ -756,12 +751,6 @@
 	if(dev->tbusy)
 		return 1;
 
-	if(skb == NULL || skb->len <= 0) {
-		printk("%s: skb is NULL\n", dev->name);
-		dev_tint(dev);
-		return 0;
-	}
-
 	if(set_bit(0, (void *) &dev->tbusy) != 0) {
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
@@ -788,6 +777,8 @@
 	/* Get it going. */
 	qep->qcregs->ctrl = CREG_CTRL_TWAKEUP;
 
+	qep->stats.tx_bytes+=skb->len;
+	
 	dev_kfree_skb(skb, FREE_WRITE);
 
 	if(SUN4C_TX_BUFFS_AVAIL(qep))
@@ -796,11 +787,11 @@
 	return 0;
 }
 
-static struct enet_statistics *qe_get_stats(struct device *dev)
+static struct net_device_stats *qe_get_stats(struct device *dev)
 {
 	struct sunqe *qep = (struct sunqe *) dev->priv;
 
-	return &qep->enet_stats;
+	return &qep->net_stats;
 }
 
 #define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/sunqe.h linux/drivers/net/sunqe.h
--- v2.1.24/linux/drivers/net/sunqe.h	Wed Dec 18 15:58:48 1996
+++ linux/drivers/net/sunqe.h	Sun Feb  2 15:18:42 1997
@@ -360,7 +360,7 @@
 
 	struct sunqec             *parent;
 
-	struct enet_statistics     enet_stats;   /* Statistical counters               */
+	struct net_device_stats   enet_stats;   /* Statistical counters               */
 	struct linux_sbus_device  *qe_sbusdev;   /* QE's SBUS device struct            */
 	struct device             *dev;          /* QE's netdevice struct              */
 	int                        channel;      /* Who am I?                          */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.1.24/linux/drivers/net/tulip.c	Sun Dec 22 16:37:36 1996
+++ linux/drivers/net/tulip.c	Sun Feb  2 15:18:42 1997
@@ -15,6 +15,9 @@
 
 	Subscribe to linux-tulip@cesdis.gsfc.nasa.gov and linux-tulip-bugs@cesdis.gsfc.nasa.gov
 	for late breaking news and exciting develovements.
+	
+	This has Baldur Norddahl's one liner fix for the AC/AE boards. If it
+	stops working please change TINTR_ENABLE to 0xFFFFFFFF
 */
 
 static char *version =
@@ -240,7 +243,7 @@
 #define	TCMOD_AUTO			(TCMOD_SW100TP|TCMOD_TH128|TCMOD_10TP)
 
 /* description of CSR7 interrupt mask register */
-#define	TINTR_ENABLE		0xFFFFFFFF
+#define	TINTR_ENABLE		0xFFFFBBFF
 #define	TINTR_DISABLE		0x00000000
 
 /* description of CSR11 G.P. timer (21041/21140) register */
@@ -334,7 +337,7 @@
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
 	char rx_buffs[RX_RING_SIZE][PKT_BUF_SZ];
 	/* temporary Rx buffers. */
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	int setup_frame[48];	/* Pseudo-Tx frame to init address table. */
 	void (*port_select)(struct device *dev);
 	int (*port_fail)(struct device *dev);
@@ -371,7 +374,7 @@
 static int tulip_rx(struct device *dev);
 static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int tulip_close(struct device *dev);
-static struct enet_statistics *tulip_get_stats(struct device *dev);
+static struct net_device_stats *tulip_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 #define	generic21140_fail	NULL
@@ -881,6 +884,7 @@
 	} else {
 		daddr = virt_to_bus(skb->data);
 		len = skb->len;
+		tp->stats.tx_bytes+=len;
 	}
 	tp->tx_skbuff[entry] = skb;
 	tp->tx_ring[entry].length = len |
@@ -1120,8 +1124,7 @@
 	return(0);
 }
 
-static struct enet_statistics *
-tulip_get_stats(struct device *dev)
+static struct net_device_stats *tulip_get_stats(struct device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	/*	short ioaddr = dev->base_addr;*/
diff -u --recursive --new-file v2.1.24/linux/drivers/net/tunnel.c linux/drivers/net/tunnel.c
--- v2.1.24/linux/drivers/net/tunnel.c	Thu Jan 23 21:06:49 1997
+++ linux/drivers/net/tunnel.c	Sun Feb  2 15:18:42 1997
@@ -120,13 +120,13 @@
 
 static int tunnel_xmit(struct sk_buff *skb, struct device *dev)
 {
-	struct enet_statistics *stats;		/* This device's statistics */
+	struct net_device_stats *stats;		/* This device's statistics */
 	struct rtable *rt;     			/* Route to the other host */
 	struct device *tdev;			/* Device to other host */
 	struct iphdr  *iph;			/* Our new IP header */
 	int    max_headroom;			/* The extra header space needed */
 
-	stats = (struct enet_statistics *)dev->priv;
+	stats = (struct net_device_stats *)dev->priv;
   
 	/*
 	 *  First things first.  Look up the destination address in the 
@@ -194,6 +194,8 @@
 	iph->id			=	htons(ip_id_count++);	/* Race condition here? */
 	ip_send_check(iph);
 
+	stats->tx_bytes+=skb->len;
+	
 	ip_send(skb);
 
 	/* Record statistics and return */
@@ -201,9 +203,9 @@
 	return 0;
 }
 
-static struct enet_statistics *tunnel_get_stats(struct device *dev)
+static struct net_device_stats *tunnel_get_stats(struct device *dev)
 {
-	return((struct enet_statistics*) dev->priv);
+	return((struct net_device_stats*) dev->priv);
 }
 
 /*
@@ -226,10 +228,10 @@
 	dev->stop		= tunnel_close;
 	dev->hard_start_xmit	= tunnel_xmit;
 	dev->get_stats		= tunnel_get_stats;
-	dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+	dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
 	if (dev->priv == NULL)
 		return -ENOMEM;
-	memset(dev->priv, 0, sizeof(struct enet_statistics));
+	memset(dev->priv, 0, sizeof(struct net_device_stats));
 
 	/* Initialize the tunnel device structure */
 	
@@ -302,7 +304,7 @@
 void cleanup_module(void)
 {
 	unregister_netdev(&dev_tunnel);
-	kfree_s(dev_tunnel.priv,sizeof(struct enet_statistics));
+	kfree_s(dev_tunnel.priv,sizeof(struct net_device_stats));
 	dev_tunnel.priv=NULL;
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h
--- v2.1.24/linux/drivers/net/wavelan.p.h	Sun Dec 22 16:37:36 1996
+++ linux/drivers/net/wavelan.p.h	Sun Feb  2 15:18:42 1997
@@ -367,7 +367,7 @@
 
 /* Shortcuts */
 typedef struct device		device;
-typedef struct enet_statistics	en_stats;
+typedef struct net_device_stats	en_stats;
 typedef struct iw_statistics	iw_stats;
 typedef struct iw_quality	iw_qual;
 typedef struct iw_freq		iw_freq;
diff -u --recursive --new-file v2.1.24/linux/drivers/net/wic.c linux/drivers/net/wic.c
--- v2.1.24/linux/drivers/net/wic.c	Thu Jan 23 21:06:49 1997
+++ linux/drivers/net/wic.c	Thu Jan  1 02:00:00 1970
@@ -1,1440 +0,0 @@
-/* $Id: wic.c,v 1.0 1995/02/11 10:26:05 hayes Exp $ */
-/* WIC: A parallel port "network" driver for Linux. */
-/* based on the plip network driver */
-/* Modified for Linux 1.3.x by Alan Cox <Alan.Cox@linux.org> */
-
-char *version = "NET3 WIC version 0.9 hayes@netplumbing.com";
-
-/*
-  Sources:
-	Ideas and protocols came from Russ Nelson's <nelson@crynwr.com>
-	"parallel.asm" parallel port packet driver and from the plip.c
-	parallel networking linux driver from the 1.2.13 Linux
-	distribution.
-
-  The packet is encapsulated as if it were ethernet.
-
-*/
-
-#ifdef MODULE
-#include <linux/module.h>
-#include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/if_ether.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/lp.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_wic.h>
-
-#include <linux/tqueue.h>
-#include <linux/ioport.h>
-#include <asm/bitops.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-#include <asm/uaccess.h>
-#include <linux/string.h>
-
-#define NET_DEBUG 1
-/* Use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-unsigned int net_debug = NET_DEBUG;
-
-/* Connection time out = WIC_TRIGGER_WAIT * WIC_DELAY_UNIT usec */
-#define WIC_TRIGGER_WAIT	 500
-
-/* Nibble time out = WIC_NIBBLE_WAIT * WIC_DELAY_UNIT usec */
-#define WIC_NIBBLE_WAIT        3000
-
-#define PAR_DATA(dev)		((dev)->base_addr+0)
-#define PAR_STATUS(dev)		((dev)->base_addr+1)
-#define PAR_CONTROL(dev)	((dev)->base_addr+2)
-
-/* Bottom halfs */
-void wic_kick_bh(struct device *dev);
-void wic_bh(struct device *dev);
-
-/* Interrupt handler */
-void wic_interrupt(int irq, void *dev_ptr, struct pt_regs *regs);
-
-/* Functions for DEV methods */
-int wic_rebuild_header(struct sk_buff *skb);
-int wic_tx_packet(struct sk_buff *skb, struct device *dev);
-int wic_open(struct device *dev);
-int wic_close(struct device *dev);
-struct enet_statistics *wic_get_stats(struct device *dev);
-int wic_config(struct device *dev, struct ifmap *map);
-int wic_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-int send_cmd(struct device *dev, unsigned char *cmd, char len);
-int recv_cmd_resp(struct device *dev, unsigned char *cmd);
-int send_byte(struct device *dev, unsigned char c);
-int get_byte(struct device *dev, unsigned char *c);
-int ack_resp(struct device *dev);
-int check_bfr(struct device *dev);
-void wic_reset(struct device *dev);
-void wic_set_multicast_list(struct device *dev);
-
-#define LOOPCNT 30000	
-unsigned char tog = 3;
-unsigned char save = 0;
-
-enum wic_connection_state {
-	WIC_CN_NONE=0,
-	WIC_CN_RECEIVE,
-	WIC_CN_SEND,
-	WIC_CN_CLOSING,
-	WIC_CN_ERROR
-};
-
-enum wic_packet_state {
-	WIC_PK_DONE=0,
-	WIC_PK_TRIGGER,
-	WIC_PK_LENGTH_LSB,
-	WIC_PK_LENGTH_MSB,
-	WIC_PK_DATA,
-	WIC_PK_CHECKSUM
-};
-
-enum wic_nibble_state {
-	WIC_NB_BEGIN,
-	WIC_NB_1,
-	WIC_NB_2,
-};
-
-struct wic_local {
-	enum wic_packet_state state;
-	enum wic_nibble_state nibble;
-	union {
-		struct {
-#if defined(__LITTLE_ENDIAN)
-			unsigned char lsb;
-			unsigned char msb;
-#elif defined(__BIG_ENDIAN)
-			unsigned char msb;
-			unsigned char lsb;
-#else
-#error	"Please fix the endianness defines in <asm/byteorder.h>"
-#endif						
-		} b;
-		unsigned short h;
-	} length;
-	unsigned short byte;
-	unsigned char  checksum;
-	unsigned char  data;
-	struct sk_buff *skb;
-};
-
-struct net_local {
-	struct enet_statistics enet_stats;
-	struct tq_struct immediate;
-	struct tq_struct deferred;
-	struct wic_local snd_data;
-	struct wic_local rcv_data;
-	unsigned long  trigger;
-	unsigned long  nibble;
-	enum wic_connection_state connection;
-	unsigned short timeout_count;
-	char is_deferred;
-	int (*orig_rebuild_header)(struct sk_buff *skb);
-};
-
-/* Entry point of WIC driver.
-   Probe the hardware, and register/initialize the driver. */
-
-int wic_init(struct device *dev)
-{
-	struct net_local *nl;
-	struct wicconf wc;
-	int i;
-
-	/* Check region before the probe */
-	if (check_region(PAR_DATA(dev), 3) < 0)
-		return -ENODEV;
-	
-	/* Check that there is something at base_addr. */
-	outb(0, PAR_DATA(dev));
-	udelay(1000);
-	if (inb(PAR_DATA(dev)) != 0)
-		return -ENODEV;
-
-	printk("%s\n",version);
-	printk("%s: Parallel port at %#3lx, ", dev->name, dev->base_addr);
-	if (dev->irq) {
-		printk("using assigned IRQ %d.\n", dev->irq);
-	} else {
-		int irq = 0;
-#ifdef MODULE
-		/* dev->irq==0 means autoprobe, but we don't try to do so
-		   with module.  We can change it by ifconfig */
-#else
-		unsigned int irqs = probe_irq_on();
-
-		outb(0x00, PAR_CONTROL(dev));
-		udelay(1000);
-		udelay(1000);
-		irq = probe_irq_off(irqs);
-#endif
-		if (irq > 0) {
-			dev->irq = irq;
-			printk("using probed IRQ %d.\n", dev->irq);
-		} else
-			printk("failed to detect IRQ(%d) --"
-			       " Please set IRQ by ifconfig.\n", irq);
-	}
-
-	request_region(PAR_DATA(dev), 3, dev->name);
-
-	/* Fill in the generic fields of the device structure. */
-	ether_setup(dev);
-
-	/* Then, override parts of it */
-	dev->hard_start_xmit	= wic_tx_packet;
-	dev->open		= wic_open;
-	dev->stop		= wic_close;
-	dev->get_stats 		= wic_get_stats;
-	dev->set_config		= wic_config;
-	dev->do_ioctl		= wic_ioctl;
-	dev->mtu		= 1514;
-	dev->set_multicast_list = wic_set_multicast_list;
-	dev->flags	        = IFF_BROADCAST | IFF_RUNNING | IFF_NOTRAILERS;
-
-	/* get the MAC address from the controller */
-	wc.len = 1;
-	wc.pcmd = WIC_GETNET;
-	check_bfr(dev);
-	send_cmd(dev, (unsigned char *)&wc, 1);
-	wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
-	while ((wc.len == 1) && (wc.data[0] == 0x7)) /* controller int */
-		wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
-	
-	printk("%s:MAC address: ",dev->name);	
-	for (i=0; i < ETH_ALEN ; i++) {
-		dev->dev_addr[i] = wc.data[i];
-		printk("%2x ",dev->dev_addr[i]);
-	}
-	printk("\n");
-
-	/* Set the private structure */
-	dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
-	if (dev->priv == NULL)
-		return EAGAIN;
-	memset(dev->priv, 0, sizeof(struct net_local));
-	nl = (struct net_local *) dev->priv;
-
-	nl->orig_rebuild_header = dev->rebuild_header;
-	dev->rebuild_header 	= wic_rebuild_header;
-
-	/* Initialize constants */
-	nl->trigger	= WIC_TRIGGER_WAIT;
-	nl->nibble	= WIC_NIBBLE_WAIT;
-
-	/* Initialize task queue structures */
-	nl->immediate.next = NULL;
-	nl->immediate.sync = 0;
-	nl->immediate.routine = (void *)(void *)wic_bh;
-	nl->immediate.data = dev;
-
-	nl->deferred.next = NULL;
-	nl->deferred.sync = 0;
-	nl->deferred.routine = (void *)(void *)wic_kick_bh;
-	nl->deferred.data = dev;
-
-	return 0;
-}
-
-/* Bottom half handler for the delayed request.
-   This routine is kicked by do_timer().
-   Request `wic_bh' to be invoked. */
-void wic_kick_bh(struct device *dev)
-{
-	struct net_local *nl = (struct net_local *)dev->priv;
-
-	if (nl->is_deferred) {
-		queue_task(&nl->immediate, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-	}
-}
-
-/* Forward declarations of internal routines */
-int wic_none(struct device *, struct net_local *,
-		     struct wic_local *, struct wic_local *);
-int wic_receive_packet(struct device *, struct net_local *,
-			       struct wic_local *, struct wic_local *);
-int wic_send_packet(struct device *, struct net_local *,
-			    struct wic_local *, struct wic_local *);
-int wic_connection_close(struct device *, struct net_local *,
-				 struct wic_local *, struct wic_local *);
-int wic_error(struct device *, struct net_local *,
-		      struct wic_local *, struct wic_local *);
-int wic_bh_timeout_error(struct device *dev, struct net_local *nl,
-				 struct wic_local *snd,
-				 struct wic_local *rcv,
-				 int error);
-
-#define OK        0
-#define TIMEOUT   1
-#define ERROR     2
-
-typedef int (*wic_func)(struct device *dev, struct net_local *nl,
-			 struct wic_local *snd, struct wic_local *rcv);
-
-wic_func connection_state_table[] =
-{
-	wic_none,
-	wic_receive_packet,
-	wic_send_packet,
-	wic_connection_close,
-	wic_error
-};
-
-void wic_set_multicast_list(struct device *dev)
-{
-	struct wicconf wc;
-	struct wic_net *wn;
-	
-	disable_irq(dev->irq);
-	save &= 0xef; /* disable */
-	outb(save, PAR_CONTROL(dev));
-	
-	wc.len = 1;
-	wc.pcmd = WIC_GETNET;
-	check_bfr(dev);
-	tog = 3;
-	send_cmd(dev, (unsigned char *)&wc, 1);
-	wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
-	while ((wc.len == 1) && (wc.data[0] == 0x7)) /* controller int */
-		wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
-	wn = (struct wic_net *)&wc.data;
-	if(dev->flags&IFF_PROMISC)
-	{
-		/* promiscuous mode */
-		wn->mode |= (NET_MODE_ME | NET_MODE_BCAST | 
-			NET_MODE_MCAST | NET_MODE_PROM);
-		printk("%s: Setting promiscuous mode\n", dev->name);
-	}
-	else if((dev->flags&IFF_ALLMULTI) || dev->mc_count)
-	{
-		wn->mode &= ~NET_MODE_PROM;
-		wn->mode |= (NET_MODE_MCAST | NET_MODE_ME | NET_MODE_BCAST);
-	}
-	else
-	{
-		wn->mode &= ~(NET_MODE_PROM | NET_MODE_MCAST);
-		wn->mode |= (NET_MODE_ME | NET_MODE_BCAST);
-	}
-	wc.len = 23;
-	wc.pcmd = WIC_SETNET;
-	check_bfr(dev);
-	tog = 3;
-	send_cmd(dev, (unsigned char *)&wc, wc.len);
-
-	save |= 0x10; /* enable */
-	outb(save, PAR_CONTROL(dev));
-	enable_irq(dev->irq);
-	return;
-}
-
-/* Bottom half handler of WIC. */
-void wic_bh(struct device *dev)
-{
-	struct net_local *nl = (struct net_local *)dev->priv;
-	struct wic_local *snd = &nl->snd_data;
-	struct wic_local *rcv = &nl->rcv_data;
-	wic_func f;
-	int r;
-
-	nl->is_deferred = 0;
-	f = connection_state_table[nl->connection];
-	if ((r = (*f)(dev, nl, snd, rcv)) != OK
-	    && (r = wic_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {
-		nl->is_deferred = 1;
-		queue_task(&nl->deferred, &tq_timer);
-	}
-}
-
-int wic_bh_timeout_error(struct device *dev, struct net_local *nl,
-		      struct wic_local *snd, struct wic_local *rcv,
-		      int error)
-{
-	unsigned char c0;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	if (nl->connection == WIC_CN_SEND) {
-
-		if (error != ERROR) { /* Timeout */
-			nl->timeout_count++;
-			if ((snd->state == WIC_PK_TRIGGER
-			     && nl->timeout_count <= 10)
-			    || nl->timeout_count <= 3) {
-				restore_flags(flags);
-				/* Try again later */
-				return TIMEOUT;
-			}
-			c0 = inb(PAR_STATUS(dev));
-			printk("%s: transmit timeout(%d,%02x)\n",
-			       dev->name, snd->state, c0);
-		}
-		nl->enet_stats.tx_errors++;
-		nl->enet_stats.tx_aborted_errors++;
-	} else if (nl->connection == WIC_CN_RECEIVE) {
-		if (rcv->state == WIC_PK_TRIGGER) {
-			/* Transmission was interrupted. */
-			restore_flags(flags);
-			return OK;
-		}
-		if (error != ERROR) { /* Timeout */
-			if (++nl->timeout_count <= 3) {
-				restore_flags(flags);
-				/* Try again later */
-				return TIMEOUT;
-			}
-			c0 = inb(PAR_STATUS(dev));
-			printk("%s: receive timeout(%d,%02x)\n",
-			       dev->name, rcv->state, c0);
-		}
-		nl->enet_stats.rx_dropped++;
-	}
-	rcv->state = WIC_PK_DONE;
-	if (rcv->skb) {
-		kfree_skb(rcv->skb, FREE_READ);
-		rcv->skb = NULL;
-	}
-	snd->state = WIC_PK_DONE;
-	if (snd->skb) {
-		dev_kfree_skb(snd->skb, FREE_WRITE);
-		snd->skb = NULL;
-	}
-#if (0)
-	disable_irq(dev->irq);
-	save &= 0xef; /* disable */
-	outb(save, PAR_CONTROL(dev));
-	dev->tbusy = 1;
-	outb(0x00, PAR_DATA(dev));
-#endif /* (0) */
-	nl->connection = WIC_CN_ERROR;
-	restore_flags(flags);
-
-	return TIMEOUT;
-}
-
-int wic_none(struct device *dev, struct net_local *nl,
-	  struct wic_local *snd, struct wic_local *rcv)
-{
-	return OK;
-}
-
-/* WIC_RECEIVE --- receive a byte(two nibbles)
-   Returns OK on success, TIMEOUT on timeout */
-extern inline int wic_receive(unsigned short nibble_timeout, 
-	unsigned short status_addr, enum wic_nibble_state *ns_p, unsigned char *data_p)
-{
-	unsigned int cx;
-
-	cx = LOOPCNT;
-	while ((inb(status_addr) & 0x08) != ((tog<<3) & 0x08)) {
-		if (--cx == 0) {
-			return TIMEOUT;
-		}
-	}
-	*data_p = inb(status_addr-1);
-	tog ^= 0x01;
-	outb(tog| save, status_addr+1);
-	return OK;
-}
-
-/* WIC_RECEIVE_PACKET --- receive a packet */
-
-int wic_receive_packet(struct device *dev, struct net_local *nl,
-		    struct wic_local *snd, struct wic_local *rcv)
-{
-	unsigned short status_addr = PAR_STATUS(dev);
-	unsigned short nibble_timeout = nl->nibble;
-	unsigned char *lbuf;
-	unsigned char junk;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	switch (rcv->state) {
-	case WIC_PK_TRIGGER:
-		disable_irq(dev->irq);
-		save &= 0xef; /* disable */
-		outb(save, PAR_CONTROL(dev));
-		
-		dev->interrupt = 0;
-
-		tog &= 0xfe;
-		ack_resp(dev);
-		if (net_debug > 2)
-			printk("%s: receive start\n", dev->name);
-		rcv->state = WIC_PK_LENGTH_LSB;
-		rcv->nibble = WIC_NB_BEGIN;
-
-	case WIC_PK_LENGTH_LSB:
-		if (net_debug > 2)
-			printk("%s: WIC_PK_LENGTH_LSB\n", dev->name);
-		if (snd->state != WIC_PK_DONE) {
-			if (wic_receive(nl->trigger, status_addr,
-					 &rcv->nibble, &rcv->length.b.lsb)) {
-				/* collision, here dev->tbusy == 1 */
-				rcv->state = WIC_PK_DONE;
-				nl->is_deferred = 1;
-				nl->connection = WIC_CN_SEND;
-				restore_flags(flags);
-				queue_task(&nl->deferred, &tq_timer);
-				save |= 0x10; /* enable */
-				outb(save, PAR_CONTROL(dev));
-				enable_irq(dev->irq);
-				return OK;
-			}
-		} else {
-			if (wic_receive(nibble_timeout, status_addr,
-					 &rcv->nibble, &rcv->length.b.lsb)) {
-				restore_flags(flags);
-				return TIMEOUT;
-			}
-		}
-		rcv->state = WIC_PK_LENGTH_MSB;
-
-	case WIC_PK_LENGTH_MSB:
-		if (net_debug > 2)
-			printk("%s: WIC_PK_LENGTH_MSB\n", dev->name);
-		if (wic_receive(nibble_timeout, status_addr,
-				 &rcv->nibble, &rcv->length.b.msb)) {
-			restore_flags(flags);
-			return TIMEOUT;
-		}
-		if (rcv->length.h > dev->mtu || rcv->length.h < 8) {
-			printk("%s: bad packet size %d.\n", dev->name, rcv->length.h);
-			restore_flags(flags);
-			return ERROR;
-		}
-		/* Malloc up new buffer. */
-		rcv->skb = dev_alloc_skb(rcv->length.h);
-		if (rcv->skb == NULL) {
-			printk("%s: Memory squeeze.\n", dev->name);
-			restore_flags(flags);
-			return ERROR;
-		}
-		skb_put(rcv->skb,rcv->length.h);
-		rcv->skb->dev = dev;
-		
-		rcv->state = WIC_PK_DATA;
-		rcv->byte = 0;
-		rcv->checksum = 0;
-		
-		/* sequence numbers */
-		if (net_debug > 2)
-			printk("%s: WIC_PK_SEQ\n", dev->name);
-		if (wic_receive(nibble_timeout, status_addr,
-				 &rcv->nibble, &junk)) {
-			restore_flags(flags);
-			return TIMEOUT;
-		}
-		if (wic_receive(nibble_timeout, status_addr,
-				 &rcv->nibble, &junk)) {
-			restore_flags(flags);
-			return TIMEOUT;
-		}
-
-	case WIC_PK_DATA:
-		if (net_debug > 2)
-			printk("%s: WIC_PK_DATA: length %i\n", dev->name, 
-				rcv->length.h);
-		lbuf = rcv->skb->data;
-		do {
-			if (wic_receive(nibble_timeout, status_addr, 
-					 &rcv->nibble, &lbuf[rcv->byte])) {
-				restore_flags(flags);
-				return TIMEOUT;
-			}
-		} while (++rcv->byte < (rcv->length.h - 4));
-
-		/* receive pad byte */
-		if (rcv->length.h & 0x01)
-			wic_receive(nibble_timeout, status_addr, 
-					 &rcv->nibble, &lbuf[rcv->byte]);
-		
-		do {
-			rcv->checksum += lbuf[--rcv->byte];
-		} while (rcv->byte);
-
-		rcv->state = WIC_PK_CHECKSUM;
-
-	case WIC_PK_CHECKSUM:
-		if (net_debug > 2)
-			printk("%s: WIC_PK_CHECKSUM\n", dev->name);
-		if (wic_receive(nibble_timeout, status_addr,
-				 &rcv->nibble, &junk)) {
-			restore_flags(flags);
-			return TIMEOUT;
-		}
-		outb(0, PAR_DATA(dev));
-		rcv->state = WIC_PK_DONE;
-
-	case WIC_PK_DONE:
-		if (net_debug > 2)
-			printk("%s: WIC_PK_DONE\n", dev->name);
-		/* Inform the upper layer for the arrival of a packet. */
-		netif_rx(rcv->skb);
-		nl->enet_stats.rx_packets++;
-		rcv->skb = NULL;
-		if (net_debug > 2)
-			printk("%s: receive end\n", dev->name);
-
-		/* Close the connection. */
-		if (snd->state != WIC_PK_DONE) {
-			nl->connection = WIC_CN_SEND;
-			restore_flags(flags);
-			queue_task(&nl->immediate, &tq_immediate);
-			save |= 0x10; /* enable */
-			outb(save, PAR_CONTROL(dev));
-			enable_irq(dev->irq);
-			return OK;
-		} else {
-			nl->connection = WIC_CN_NONE;
-			restore_flags(flags);
-			save |= 0x10; /* enable */
-			outb(save, PAR_CONTROL(dev));
-			enable_irq(dev->irq);
-			return OK;
-		}
-	}
-	restore_flags(flags);
-	return OK;
-}
-
-/* WIC_SEND --- send a byte (two nibbles) 
-   Returns OK on success, TIMEOUT when timeout    */
-extern inline int wic_send(unsigned short nibble_timeout, 
-	unsigned short data_addr, enum wic_nibble_state *ns_p, 
-	unsigned char data)
-{
-	unsigned int cx;
-
-	cx = LOOPCNT;
-	while ((inb(data_addr+1) & 0x80) == ((tog<<7) & 0x80)) {
-		if (--cx == 0) {
-			return -TIMEOUT;
-		}
-	}
-	outb(data, data_addr);
-	outb(tog | save, data_addr+2);
-	tog ^= 0x01;
-	return OK;
-}
-
-/* WIC_SEND_PACKET --- send a packet */
-int wic_send_packet(struct device *dev, struct net_local *nl,
-		 struct wic_local *snd, struct wic_local *rcv)
-{
-	unsigned short data_addr = PAR_DATA(dev);
-	unsigned short nibble_timeout = nl->nibble;
-	unsigned char *lbuf;
-	unsigned int cx;
-	unsigned int pad = 2;
-	unsigned long flags;
-
-	if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
-		printk("%s: send skb lost\n", dev->name);
-		snd->state = WIC_PK_DONE;
-		snd->skb = NULL;
-		save |= 0x10; /* enable */
-		outb(save, PAR_CONTROL(dev));
-		enable_irq(dev->irq);
-		return ERROR;
-	}
-
-	save_flags(flags);	
-	cli();
-	switch (snd->state) {
-	case WIC_PK_TRIGGER:
-	
-		if (nl->connection == WIC_CN_RECEIVE) {
-			/* interrupted */
-			nl->enet_stats.collisions++;
-			restore_flags(flags);
-			if (net_debug > 1)
-				printk("%s: collision.\n", dev->name);
-			save |= 0x10; /* enable */
-			outb(save, PAR_CONTROL(dev));
-			enable_irq(dev->irq);
-			return OK;
-		}
-		
-		disable_irq(dev->irq);
-		save &= 0xef; /* disable */
-		outb(save, PAR_CONTROL(dev));
-		
-		/* interrupt controller */
-		tog = 3;
-		outb(0x06 | save, PAR_CONTROL(dev));
-			
-		cx = LOOPCNT;
-		while ((inb(PAR_STATUS(dev)) & 0xe8) != 0xc0) {
-			if (--cx == 0) {
-				restore_flags(flags);
-				return TIMEOUT;
-			}
-			if (cx == 10)
-				outb(0x02, PAR_CONTROL(dev));
-		}
-		
-		if (net_debug > 2)
-			printk("%s: send start\n", dev->name);
-		snd->state = WIC_PK_LENGTH_LSB;
-		snd->nibble = WIC_NB_BEGIN;
-		nl->timeout_count = 0;
-
-	case WIC_PK_LENGTH_LSB:
-		if (snd->length.h & 0x01)
-			pad = 3;
-		else
-			pad = 2;
-		snd->length.h += (4 + pad); /* len + seq + data + pad */
-		if (net_debug > 2)
-			printk("%s: WIC_PK_LENGTH_LSB: length = %i\n", 
-				dev->name, snd->length.h);
-
-		if (wic_send(nibble_timeout, data_addr,
-			      &snd->nibble, snd->length.b.lsb)) {
-			restore_flags(flags);
-			return TIMEOUT;
-		}
-		snd->state = WIC_PK_LENGTH_MSB;
-
-	case WIC_PK_LENGTH_MSB:
-		if (net_debug > 2)
-			printk("%s: WIC_PK_LENGTH_MSB\n", dev->name);
-		if (wic_send(nibble_timeout, data_addr,
-			      &snd->nibble, snd->length.b.msb)) {
-			restore_flags(flags);
-			return TIMEOUT;
-		}
-		snd->state = WIC_PK_DATA;
-		snd->byte = 0;
-		snd->checksum = 0;
-
-	case WIC_PK_DATA:
-		/* adjust length back to data only */
-		snd->length.h -= (4 + pad); /* len + seq + data + pad */
-		/* send 2 byte sequence number */
-		if (net_debug > 2)
-			printk("%s: WIC_SEQ\n", dev->name);
-		if (wic_send(nibble_timeout, data_addr,
-			      &snd->nibble, 0)) {
-			restore_flags(flags);
-			return TIMEOUT;
-		}
-		if (wic_send(nibble_timeout, data_addr,
-			      &snd->nibble, 0)) {
-			restore_flags(flags);
-			return TIMEOUT;
-		}	
-		if (net_debug > 2)
-			printk("%s: WIC_PK_DATA\n", dev->name);
-
-		do {
-			if (wic_send(nibble_timeout, data_addr,
-				      &snd->nibble, lbuf[snd->byte])) {
-				restore_flags(flags);
-				return TIMEOUT;
-			}
-		}
-		while (++snd->byte < snd->length.h);
-		
-		do
-			snd->checksum += lbuf[--snd->byte];
-		while (snd->byte);
-
-		snd->state = WIC_PK_CHECKSUM;
-
-	case WIC_PK_CHECKSUM:
-		/* send pad bytes */
-		if (net_debug > 2)
-			printk("%s: WIC_PK_PAD: %i bytes\n", 
-				dev->name, pad);
-		while(pad--)
-			if (wic_send(nibble_timeout, data_addr,
-			      	&snd->nibble, 0)) {
-				restore_flags(flags);
-				return TIMEOUT;
-			}
-		dev_kfree_skb(snd->skb, FREE_WRITE);
-		nl->enet_stats.tx_packets++;
-		snd->state = WIC_PK_DONE;
-
-	case WIC_PK_DONE:
-		if (net_debug > 2)
-			printk("%s: WIC_PK_DONE\n", dev->name);
-		/* Close the connection */
-		outb (0x00, PAR_DATA(dev));
-		outb(save, PAR_CONTROL(dev));
-		
-		snd->skb = NULL;
-		if (net_debug > 2)
-			printk("%s: send end\n", dev->name);
-		nl->connection = WIC_CN_CLOSING;
-		nl->is_deferred = 1;
-		restore_flags(flags);
-		queue_task(&nl->deferred, &tq_timer);
-		save |= 0x10; /* enable */
-		outb(save, PAR_CONTROL(dev));
-		enable_irq(dev->irq);
-		return OK;
-	}
-	restore_flags(flags);
-	return OK;
-}
-
-int wic_connection_close(struct device *dev, struct net_local *nl,
-		      struct wic_local *snd, struct wic_local *rcv)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	if (nl->connection == WIC_CN_CLOSING) {
-		nl->connection = WIC_CN_NONE;
-		dev->tbusy = 0;
-		mark_bh(NET_BH);
-	}
-	restore_flags(flags);
-	return OK;
-}
-
-/* WIC_ERROR --- wait till other end settled */
-int wic_error(struct device *dev, struct net_local *nl,
-	   struct wic_local *snd, struct wic_local *rcv)
-{
-	unsigned char status;
-
-	status = inb(PAR_STATUS(dev));
-	if ((status & 0xf8) == 0x80) {
-		if (net_debug > 2)
-			printk("%s: reset interface.\n", dev->name);
-		nl->connection = WIC_CN_NONE;
-		dev->tbusy = 0;
-		dev->interrupt = 0;
-		save |= 0x10; /* enable */
-		outb(save, PAR_CONTROL(dev));
-		enable_irq(dev->irq);
-		mark_bh(NET_BH);
-	} else {
-		nl->is_deferred = 1;
-		queue_task(&nl->deferred, &tq_timer);
-	}
-
-	return OK;
-}
-
-/* Handle the parallel port interrupts. */
-void wic_interrupt(int irq, void *dev_ptr, struct pt_regs * regs)
-{
-	struct device *dev = (struct device *) irq2dev_map[irq];
-	struct net_local *nl = (struct net_local *)dev->priv;
-	struct wic_local *rcv = &nl->rcv_data;
-	unsigned long flags;
-
-	if (dev == NULL) {
-		printk ("wic_interrupt: irq %d for unknown device.\n", irq);
-		return;
-	}
-
-	if (dev->interrupt) {
-		return;
-	}
-
-	if (check_bfr(dev) < 0) {
-		return;
-	}
-	
-	dev->interrupt = 1;
-	if (net_debug > 3)
-		printk("%s: interrupt.\n", dev->name);
-
-	save_flags(flags);
-	cli();
-	switch (nl->connection) {
-	case WIC_CN_CLOSING:
-		dev->tbusy = 0;
-	case WIC_CN_NONE:
-	case WIC_CN_SEND:
-		dev->last_rx = jiffies;
-		rcv->state = WIC_PK_TRIGGER;
-		nl->connection = WIC_CN_RECEIVE;
-		nl->timeout_count = 0;
-		restore_flags(flags);
-		queue_task(&nl->immediate, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-		break;
-
-	case WIC_CN_RECEIVE:
-		printk("%s: receive interrupt when receiving packet\n", dev->name);
-		restore_flags(flags);
-		break;
-
-	case WIC_CN_ERROR:
-		printk("%s: receive interrupt in error state\n", dev->name);
-		restore_flags(flags);
-		break;
-	}
-}
-
-int wic_rebuild_header(struct sk_buff *skb)
-{
-	struct device *dev = skb->dev;
-	struct net_local *nl = (struct net_local *)dev->priv;
-	struct ethhdr *eth = (struct ethhdr *)skb->data;
-	int i;
-
-	if ((dev->flags & IFF_NOARP)==0)
-		return nl->orig_rebuild_header(skb);
-
-	if (eth->h_proto != htons(ETH_P_IP)) {
-		printk("wic_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
-		memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-		return 0;
-	}
-
-	for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
-		eth->h_dest[i] = 0xfc;
-	memcpy(&(eth->h_dest[i]), &skb->daddr, 4);
-	return 0;
-}
-
-int wic_tx_packet(struct sk_buff *skb, struct device *dev)
-{
-	struct net_local *nl = (struct net_local *)dev->priv;
-	struct wic_local *snd = &nl->snd_data;
-	unsigned long flags;
-
-	if (dev->tbusy)
-		return 1;
-
-	/* 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;
-	}
-
-	if (set_bit(0, (void*)&dev->tbusy) != 0) {
-		printk("%s: Transmitter access conflict.\n", dev->name);
-		return 1;
-	}
-
-	if (skb->len > dev->mtu) {
-		printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
-		dev->tbusy = 0;
-		return 0;
-	}
-
-	if (net_debug > 2)
-		printk("%s: send request\n", dev->name);
-
-	save_flags(flags);
-	cli();
-	dev->trans_start = jiffies;
-	snd->skb = skb;
-	snd->length.h = skb->len;
-	snd->state = WIC_PK_TRIGGER;
-	if (nl->connection == WIC_CN_NONE) {
-		nl->connection = WIC_CN_SEND;
-		nl->timeout_count = 0;
-	}
-	restore_flags(flags);
-	queue_task(&nl->immediate, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-
-	return 0;
-}
-
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine gets exclusive access to the parallel port by allocating
-   its IRQ line.
- */
- 
-int wic_open(struct device *dev)
-{
-	struct net_local *nl = (struct net_local *)dev->priv;
-	unsigned long flags;
-
-	if (dev->irq == 0) {
-		printk("%s: IRQ is not set.  Please set it by ifconfig.\n", dev->name);
-		return -EAGAIN;
-	}
-	save_flags(flags);
-	cli();
-	check_bfr(dev);
-	if (request_irq(dev->irq , wic_interrupt, 0, dev->name, NULL) != 0) {
-		sti();
-		printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
-		return -EAGAIN;
-	}
-	irq2dev_map[dev->irq] = dev;
-	restore_flags(flags);
-
-	save |= 0x10; /* enable */
-	outb(save, PAR_CONTROL(dev));
-	/* Initialize the state machine. */
-	nl->rcv_data.state = nl->snd_data.state = WIC_PK_DONE;
-	nl->rcv_data.skb = nl->snd_data.skb = NULL;
-	nl->connection = WIC_CN_NONE;
-	nl->is_deferred = 0;
-
-	dev->interrupt = 0;
-	dev->start = 1;
-	dev->tbusy = 0;
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-/* The inverse routine to wic_open (). */
-int wic_close(struct device *dev)
-{
-	struct net_local *nl = (struct net_local *)dev->priv;
-	struct wic_local *snd = &nl->snd_data;
-	struct wic_local *rcv = &nl->rcv_data;
-
-	dev->tbusy = 1;
-	dev->start = 0;
-	cli();
-	free_irq(dev->irq, NULL);
-	irq2dev_map[dev->irq] = NULL;
-	nl->is_deferred = 0;
-	nl->connection = WIC_CN_NONE;
-	sti();
-	outb(0x00, PAR_DATA(dev));
-
-	snd->state = WIC_PK_DONE;
-	if (snd->skb) {
-		dev_kfree_skb(snd->skb, FREE_WRITE);
-		snd->skb = NULL;
-	}
-	rcv->state = WIC_PK_DONE;
-	if (rcv->skb) {
-		kfree_skb(rcv->skb, FREE_READ);
-		rcv->skb = NULL;
-	}
-
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-struct enet_statistics *
-wic_get_stats(struct device *dev)
-{
-	struct net_local *nl = (struct net_local *)dev->priv;
-	struct enet_statistics *r = &nl->enet_stats;
-
-	return r;
-}
-
-int
-wic_config(struct device *dev, struct ifmap *map)
-{
-	if (dev->flags & IFF_UP)
-		return -EBUSY;
-
-	if (map->base_addr != (unsigned long)-1
-	    && map->base_addr != dev->base_addr)
-		printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name);
-
-	if (map->irq != (unsigned char)-1)
-		dev->irq = map->irq;
-	return 0;
-}
-
-int
-wic_ioctl(struct device *dev, struct ifreq *rq, int cmd)
-{
-	struct wicconf wc;
-	int err;
-	char len = 0;
-	unsigned long flags;
-
-	err=verify_area(VERIFY_WRITE, rq->ifr_data, sizeof(struct wicconf));
-	if (err)
-		return err;
-	copy_from_user(&wc, rq->ifr_data, sizeof(struct wicconf));
-	switch(wc.pcmd) {
-		case WIC_AYT:
-			strcpy(wc.data, version);
-			wc.len = strlen(wc.data);
-			copy_to_user(rq->ifr_data, &wc, sizeof(struct wicconf));
-			/* return 0; */
-			break;
-		case WIC_RESET:
-			wic_reset(dev);
-			return(0);
-			/* break; */
-		case WIC_SETSN:
-			len = 17;
-			break;
-		case WIC_SETPS:
-			len = 3;
-			break;
-		case WIC_SETAF:
-		case WIC_SETGPF:
-			len = 2;
-			break;
-		case WIC_SETNET:
-			len = 23;
-			break;
-		case WIC_SETSYS:
-			len = 15;
-			break;
-		case WIC_GETVERH:
-		case WIC_GETNL:
-		case WIC_GETSN:
-		case WIC_CLRSTATS:
-		case WIC_GETSTATS:
-		case WIC_GETVERM:
-		case WIC_GETNET:
-		case WIC_GETSYS:
-			len = 1;
-			break;	
-		default:
-			return -EOPNOTSUPP;
-	}
-
-	/* Wait for lock to free */
-      	while (set_bit(0, (void *)&dev->tbusy) != 0); 
-	save_flags(flags);
-	cli();
-
-	disable_irq(dev->irq);
-	save &= 0xef; /* disable */
-	outb(save, PAR_CONTROL(dev));
-	err = check_bfr(dev);
-	tog = 3;
-	err = send_cmd(dev, (unsigned char *)&wc, len);
-
-	if (wc.pcmd & 0x40) {	/* response */
-		len = (char)recv_cmd_resp(dev, wc.data);
-		while ((len == 1) && (wc.data[0] == 0x7)) { /* controller int */
-			len = (char)recv_cmd_resp(dev, wc.data);
-		}
-		save |= 0x10; /* enable */
-		outb(save, PAR_CONTROL(dev));
-		enable_irq(dev->irq);
-		wc.len = (len <0) ? 0 : len;
-		copy_to_user(rq->ifr_data, &wc, sizeof(struct wicconf));
-	} else {
-		save |= 0x10; /* enable */
-		outb(save, PAR_CONTROL(dev));
-		enable_irq(dev->irq);
-	}
-	restore_flags(flags);
-
-	outb(0, PAR_DATA(dev));
-	dev->tbusy = 0;
-	return 0;
-}
-
-int
-get_byte(struct device *dev, unsigned char *c)
-{
-unsigned int cx;
-
-	cx = LOOPCNT;
-	while ((inb(PAR_STATUS(dev)) & 0x08) != ((tog << 3)&0x08)) {
-		if (--cx == 0) {
-			return(-TIMEOUT);
-		}
-	}
-	/* receive a byte of data */
-	*c = inb(PAR_DATA(dev));
-	tog ^= 0x01;
-	/* ack reception of data */
-	outb(tog| save, PAR_CONTROL(dev));
-	return OK;
-}
-
-int
-ack_resp(struct device *dev)
-{
-unsigned int cx;
-	
-	outb(save | 0x27, PAR_CONTROL(dev));
-
-	/* wait for controller to remove interrupt [Ack(low), Busy(low)] */
-	cx = LOOPCNT;
-	while ((inb(PAR_STATUS(dev)) & 0xc0) != 0x80) {
-		if (--cx == 0) {
-			return -TIMEOUT;
-		}
-	}
-	
-	outb(save | 0x22, PAR_CONTROL(dev));
-	cx = LOOPCNT;
-	while ((inb(PAR_STATUS(dev)) & 0x08) == 0x08) {
-		if (--cx == 0) {
-			return TIMEOUT;
-		}
-	}
-	tog |= 0x20;
-	tog &= 0xfe;
-	return OK;
-}
-
-void
-wic_reset(struct device *dev)
-{
-unsigned char stat;
-
-	stat = inb(PAR_CONTROL(dev));
-	outb(0, PAR_DATA(dev));
-	outb(stat | 0x08, PAR_CONTROL(dev));
-	outb(stat & 0xf7, PAR_CONTROL(dev));
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	tog = 3;
-	save = 0;
-	return;
-}
-
-int
-check_bfr(struct device *dev)
-{
-unsigned char c0, l;
-
-	if ((inb(PAR_STATUS(dev)) & 0xc8) == 0x48) {
-		save |= 0x80;
-		outb(0x23| save, PAR_CONTROL(dev));
-		ack_resp(dev);
-		get_byte(dev, &l);	/* len */
-		while (l--) {
-			get_byte(dev, &c0);
-		}
-		get_byte(dev, &c0);
-		save &=0x7f;
-		outb(0, PAR_DATA(dev));
-		return -l;
-	} else
-	return (0);
-}
-
-
-int
-recv_cmd_resp(struct device *dev, unsigned char *buf)
-{
-unsigned char cksum = 0;
-int err;
-unsigned char c0 = 0;
-int len;
-int savelen;
-unsigned int cx;
-int i;
-
-	tog &= 0xfe;
-	cx = LOOPCNT;
-	while ((inb(PAR_STATUS(dev)) & 0xc8) != 0x48) {
-		if (--cx == 0) {
-			/* clear Busy */
-			outb(0, PAR_DATA(dev));
-			printk("rcv_cmd_resp: timeout\n");
-			return -TIMEOUT;
-		}
-	}
-	
-	/* acknowledge the interrupt */
-	i = ack_resp(dev);
-
-	/* get length */
-	err = get_byte(dev, &c0);
-	if (err < 0) {
-		printk("get_byte1: failed\n");
-		return(err);
-	}
-	len = c0;
-	savelen = len;
-
-	/* get data */
-	while(len--) {
-		err = get_byte(dev, &c0);
-		if (err < 0) {
-			printk("get_byte2: failed\n");
-			return(err);
-		}
-		outb(0, PAR_DATA(dev));	
-		*buf = c0;
-		cksum += c0;
-		buf++;
-	}	
-	/* get cksum */
-	err = get_byte(dev, &c0);
-	if (err < 0) {
-		printk("get_byte3: failed\n");
-		return(err);
-	}
-	if (cksum != c0) {
-		printk("cksum failed\n");
-		return(-3);
-	}
-	/* get trailing byte, if any... */
-	get_byte(dev, &c0);
-	return(savelen);
-}	
-
-int
-send_byte(struct device *dev, unsigned char c)
-{
-unsigned int cx;
-
-	cx = LOOPCNT;
-	while ((inb(PAR_STATUS(dev)) & 0x80) == ((tog<<7) & 0x80)) {
-		if (--cx == 0) {
-			return(-TIMEOUT);
-		}
-	}
-	outb(c, PAR_DATA(dev));
-	outb(save |tog, PAR_CONTROL(dev));
-	tog ^= 0x01;
-	return OK;
-}
-
-
-int
-send_cmd(struct device *dev, unsigned char *cmd, char len)
-{
-unsigned char cksum = 0;
-int err = 0;
-unsigned int cx;
-
-	/* interrupt controller */
-	outb(save | 0x04, PAR_CONTROL(dev));
-	/* wait for ACK */
-	cx = LOOPCNT;
-	while ((inb(PAR_STATUS(dev)) & 0xe8) != 0xc0) {
-		if (--cx == 0) 
-			return -TIMEOUT;
-		if (cx == 10)
-			outb(0x02, PAR_CONTROL(dev));
-	}
-	/* cmd coming... */
-	outb(save | 0x02, PAR_CONTROL(dev));
-	/* send length byte */
-	err = send_byte(dev, (unsigned char)len);
-	
-	/* send data */
-	while (len--) {
-		err = send_byte(dev, *cmd);	
-		if (err < 0) {
-			return err;
-		}
-		cksum += *cmd;
-		cmd++;
-	}
-	
-	/* send cksum byte */
-	err = send_byte(dev, cksum);	
-	if (err < 0)
-		return err;
-
-	cx = LOOPCNT;
-	while ((inb(PAR_STATUS(dev)) & 0x80) == ((tog <<7)&0x80)) {
-		if (--cx == 0) 
-			return -TIMEOUT;
-	}
-	save |= 0x80;
-	outb(save | 0x23, PAR_CONTROL(dev));
-	outb(0, PAR_DATA(dev));
-	return OK;	
-}
-
-#ifdef MODULE
-struct device dev_wic0 = 
-{
-	"wic0" /*"wic"*/,
-	0, 0, 0, 0,		/* memory */
-	0x3BC, 5,		/* base, irq */
-	0, 0, 0, NULL, wic_init 
-};
-
-struct device dev_wic1 = 
-{
-	"wic1" /*"wic"*/,
-	0, 0, 0, 0,		/* memory */
-	0x378, 7,		/* base, irq */
-	0, 0, 0, NULL, wic_init 
-};
-
-struct device dev_wic2 = 
-{
-	"wic2" /*"wic"*/,
-	0, 0, 0, 0,		/* memory */
-	0x278, 2,		/* base, irq */
-	0, 0, 0, NULL, wic_init 
-};
-
-int
-init_module(void)
-{
-	int devices=0;
-
-	if (register_netdev(&dev_wic0) != 0)
-		devices++;
-	if (register_netdev(&dev_wic1) != 0)
-		devices++;
-	if (register_netdev(&dev_wic2) != 0)
-		devices++;
-	if (devices == 0)
-		return -EIO;
-	return 0;
-}
-
-void
-cleanup_module(void)
-{
-	if (dev_wic0.priv) {
-		unregister_netdev(&dev_wic0);
-		release_region(PAR_DATA(&dev_wic0), 3);
-		kfree_s(dev_wic0.priv, sizeof(struct net_local));
-		dev_wic0.priv = NULL;
-	}
-	if (dev_wic1.priv) {
-		unregister_netdev(&dev_wic1);
-		release_region(PAR_DATA(&dev_wic1), 3);
-		kfree_s(dev_wic1.priv, sizeof(struct net_local));
-		dev_wic1.priv = NULL;
-	}
-	if (dev_wic2.priv) {
-		unregister_netdev(&dev_wic2);
-		release_region(PAR_DATA(&dev_wic2), 3);
-		kfree_s(dev_wic2.priv, sizeof(struct net_local));
-		dev_wic2.priv = NULL;
-	}
-}
-#endif /* MODULE */
-
-/*
- * Local variables:
- * compile-command: "gcc -DMODULE -DCONFIG_MODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c wic.c"
- * End:
- */
diff -u --recursive --new-file v2.1.24/linux/drivers/net/znet.c linux/drivers/net/znet.c
--- v2.1.24/linux/drivers/net/znet.c	Fri Mar  1 07:50:49 1996
+++ linux/drivers/net/znet.c	Sun Feb  2 15:18:43 1997
@@ -121,7 +121,7 @@
 #define net_local znet_private
 struct znet_private {
 	int rx_dma, tx_dma;
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	/* The starting, current, and end pointers for the packet buffers. */
 	ushort *rx_start, *rx_cur, *rx_end;
 	ushort *tx_start, *tx_cur, *tx_end;
@@ -185,7 +185,7 @@
 static void	znet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void	znet_rx(struct device *dev);
 static int	znet_close(struct device *dev);
-static struct enet_statistics *net_get_stats(struct device *dev);
+static struct net_device_stats *net_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 static void hardware_init(struct device *dev);
 static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
@@ -317,6 +317,7 @@
 static int znet_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	int ioaddr = dev->base_addr;
+	struct net_local *lp = (struct net_local *)dev->priv;
 
 	if (znet_debug > 4)
 		printk(KERN_DEBUG "%s: ZNet_send_packet(%ld).\n", dev->name, dev->tbusy);
@@ -340,11 +341,6 @@
 		hardware_init(dev);
 	}
 
-	if (skb == NULL) {
-		dev_tint(dev);
-		return 0;
-	}
-
 	/* Check that the part hasn't reset itself, probably from suspend. */
 	outb(CMD0_STAT0, ioaddr);
 	if (inw(ioaddr) == 0x0010
@@ -361,6 +357,8 @@
 		unsigned char *buf = (void *)skb->data;
 		ushort *tx_link = zn.tx_cur - 1;
 		ushort rnd_len = (length + 1)>>1;
+		
+		lp->stats.tx_bytes+=length;
 
 		{
 			short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE;
@@ -616,7 +614,7 @@
 
 /* Get the current statistics.	This may be called with the card open or
    closed. */
-static struct enet_statistics *net_get_stats(struct device *dev)
+static struct net_device_stats *net_get_stats(struct device *dev)
 {
 		struct net_local *lp = (struct net_local *)dev->priv;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.1.24/linux/drivers/scsi/Config.in	Wed Jan 15 19:45:41 1997
+++ linux/drivers/scsi/Config.in	Sun Feb  2 15:18:43 1997
@@ -35,7 +35,7 @@
     bool '  enable linked commands' CONFIG_SCSI_EATA_LINKED_COMMANDS
     int  '  maximum number of queued commands' CONFIG_SCSI_EATA_MAX_TAGS 16
   fi
-dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
+dep_tristate 'Future Domain 16xx SCSI/AHA 2920 support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
 dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
 if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then
 	bool '   Enable NCR53c400 extensions' CONFIG_SCSI_GENERIC_NCR53C400
diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c
--- v2.1.24/linux/drivers/scsi/qlogicfas.c	Mon Dec 30 15:39:11 1996
+++ linux/drivers/scsi/qlogicfas.c	Sun Feb  2 15:34:32 1997
@@ -18,7 +18,7 @@
    Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
    (you can reference it, but it is incomplete and inaccurate in places)
 
-   Version 0.45 6/9/96 - kernel 1.2.0+
+   Version 0.46 1/30/97 - kernel 1.2.0+
 
    Functions as standalone, loadable, and PCMCIA driver, the latter from
    Dave Hind's PCMCIA package.
@@ -130,7 +130,7 @@
 #include "qlogicfas.h"
 #include<linux/stat.h>
 
-struct proc_dir_entry proc_scsi_qlogicfas = {
+static struct proc_dir_entry proc_scsi_qlogicfas = {
     PROC_SCSI_QLOGICFAS, 6, "qlogicfas",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
@@ -620,7 +620,7 @@
 	if( qlirq != -1 )
 		hreg->irq = qlirq;
 
-	sprintf(qinfo, "Qlogicfas Driver version 0.45, chip %02X at %03X, IRQ %d, TPdma:%d",
+	sprintf(qinfo, "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
 	    qltyp, qbase, qlirq, QL_TURBO_PDMA );
 	host->name = qinfo;
 
diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.1.24/linux/drivers/scsi/qlogicisp.c	Wed Jul 10 13:11:25 1996
+++ linux/drivers/scsi/qlogicisp.c	Sun Feb  2 15:34:32 1997
@@ -2,6 +2,7 @@
  * QLogic ISP1020 Intelligent SCSI Processor Driver (PCI)
  * Written by Erik H. Moe, ehm@cris.com
  * Copyright 1995, Erik H. Moe
+ * Copyright 1996, 1997  Michael A. Griffith <grif@acm.org> 
  *
  * 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
@@ -14,32 +15,6 @@
  * General Public License for more details.
  */
 
-/* Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu> */
-
-/*
- * $Date: 1995/09/22 02:23:15 $
- * $Revision: 0.5 $
- *
- * $Log: isp1020.c,v $
- * Revision 0.5  1995/09/22  02:23:15  root
- * do auto request sense
- *
- * Revision 0.4  1995/08/07  04:44:33  root
- * supply firmware with driver.
- * numerous bug fixes/general cleanup of code.
- *
- * Revision 0.3  1995/07/16  16:15:39  root
- * added reset/abort code.
- *
- * Revision 0.2  1995/06/29  03:14:19  root
- * fixed biosparam.
- * added queue protocol.
- *
- * Revision 0.1  1995/06/25  01:55:45  root
- * Initial release.
- *
- */
-
 #include <linux/blk.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -390,7 +365,7 @@
 
 #define PACKB(a, b)			(((a)<<4)|(b))
 
-const u_char mbox_param[] = {
+static const u_char mbox_param[] = {
 	PACKB(1, 1),	/* MBOX_NO_OP */
 	PACKB(5, 5),	/* MBOX_LOAD_RAM */
 	PACKB(2, 0),	/* MBOX_EXEC_FIRMWARE */
@@ -534,7 +509,7 @@
 						    QLOGICISP_REQ_QUEUE_LEN)
 #define RES_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, RES_QUEUE_LEN)
 
-struct Scsi_Host *irq2host[NR_IRQS];
+static struct Scsi_Host *irq2host[NR_IRQS];
 
 static void	isp1020_enable_irqs(struct Scsi_Host *);
 static void	isp1020_disable_irqs(struct Scsi_Host *);
diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/qlogicisp_asm.c linux/drivers/scsi/qlogicisp_asm.c
--- v2.1.24/linux/drivers/scsi/qlogicisp_asm.c	Tue Jun  4 06:06:38 1996
+++ linux/drivers/scsi/qlogicisp_asm.c	Sun Feb  2 15:34:32 1997
@@ -2,13 +2,13 @@
  *	Version 2.10 Initiator Firmware (16:13 Oct 18, 1995)
  */
 
-unsigned short risc_code_version = 2*1024+10;
+static const unsigned short risc_code_version = 2*1024+10;
 
-unsigned short risc_code_addr01 = 0x1000 ;
+static const unsigned short risc_code_addr01 = 0x1000 ;
 
 #if RELOAD_FIRMWARE
 
-unsigned short risc_code01[] = { 
+static const unsigned short risc_code01[] = { 
 	0x0078, 0x1041, 0x0000, 0x283a, 0x0000, 0x2043, 0x4f50, 0x5952,
 	0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31,
 	0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320,
@@ -1301,4 +1301,4 @@
 
 #endif /* RELOAD_FIRMWARE */
 
-unsigned short risc_code_length01 = 0x283a;
+static const unsigned short risc_code_length01 = 0x283a;
diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.1.24/linux/drivers/scsi/scsi.c	Tue Jan 28 18:50:14 1997
+++ linux/drivers/scsi/scsi.c	Fri Jan 31 14:27:00 1997
@@ -238,6 +238,7 @@
 {"MAXTOR","XT-4170S","B5A", BLIST_NOLUN},       /* Locks-up sometimes when LUN>0 polled. */
 {"MAXTOR","XT-8760S","B7B", BLIST_NOLUN},       /* guess what? */
 {"MEDIAVIS","RENO CD-ROMX2A","2.03",BLIST_NOLUN},/*Responds to all lun */
+{"HP", "C3725S", "*", BLIST_NOTQ},		/* Buggy Tagged Queuing */
 {"MICROP", "4110", "*", BLIST_NOTQ},		/* Buggy Tagged Queuing */
 {"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
 {"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
diff -u --recursive --new-file v2.1.24/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v2.1.24/linux/drivers/scsi/wd7000.c	Mon Dec 30 15:39:11 1996
+++ linux/drivers/scsi/wd7000.c	Sun Feb  2 15:34:32 1997
@@ -143,6 +143,7 @@
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <linux/ioport.h>
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
@@ -215,7 +216,7 @@
  * Note that if SA_INTERRUPT is not used, wd7000_intr_handle must be
  * changed to pick up the IRQ level correctly.
  */
-Adapter *irq2host[16] = {NULL};	/* Possible IRQs are 0-15 */
+static Adapter *irq2host[NR_IRQS] = {NULL};
 
 /*
  * (linear) base address for ROM BIOS
diff -u --recursive --new-file v2.1.24/linux/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c
--- v2.1.24/linux/fs/proc/procfs_syms.c	Wed Jan 15 19:45:43 1997
+++ linux/fs/proc/procfs_syms.c	Sun Feb  2 15:18:43 1997
@@ -18,6 +18,7 @@
 EXPORT_SYMBOL(proc_root);
 EXPORT_SYMBOL(proc_get_inode);
 EXPORT_SYMBOL(in_group_p);
+EXPORT_SYMBOL(proc_dir_inode_operations);
 EXPORT_SYMBOL(proc_net_inode_operations);
 EXPORT_SYMBOL(proc_net);
 
diff -u --recursive --new-file v2.1.24/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.1.24/linux/fs/proc/root.c	Sun Feb  2 15:46:20 1997
+++ linux/fs/proc/root.c	Wed Jan 29 13:32:21 1997
@@ -511,7 +511,7 @@
 	S_IFREG | S_IRUGO, 1, 0, 0,
 };
 static struct proc_dir_entry proc_root_swaps = {
-	PROC_MTAB, 5, "swaps",
+	PROC_SWAP, 5, "swaps",
 	S_IFREG | S_IRUGO, 1, 0, 0,
 };
 static struct proc_dir_entry proc_root_profile = {
diff -u --recursive --new-file v2.1.24/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- v2.1.24/linux/fs/smbfs/sock.c	Wed Dec 18 15:58:51 1996
+++ linux/fs/smbfs/sock.c	Sun Feb  2 15:18:47 1997
@@ -240,6 +240,10 @@
 			       (void *) (source + already_sent),
 			       length - already_sent, 0, 0);
 
+		if (result == 0)
+		{
+			return -EIO;
+		}
 		if (result < 0)
 		{
 			DPRINTK("smb_send_raw: sendto error = %d\n",
diff -u --recursive --new-file v2.1.24/linux/include/asm-i386/checksum.h linux/include/asm-i386/checksum.h
--- v2.1.24/linux/include/asm-i386/checksum.h	Sun Nov 10 20:12:13 1996
+++ linux/include/asm-i386/checksum.h	Sun Feb  2 15:18:47 1997
@@ -17,20 +17,39 @@
 
 /*
  * the same as csum_partial, but copies from src while it
- * checksums
+ * checksums, and handles user-space pointer exceptions correctly, when needed.
  *
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  */
 
-unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
+unsigned int csum_partial_copy_from_user( int * err, const char *src, 
+						char *dst, int len, int sum);
+
+/*
+ * I hope GCC will optimize 'dummy' away ...
+ */
+
+unsigned int csum_partial_copy_nocheck_generic( int * err, const char *src, char *dst,
+						 int len, int sum);
 
+extern __inline__ unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
+                                                        int len, int sum)
+{
+        int dummy;
+
+        return csum_partial_copy_nocheck_generic ( &dummy, src, dst, len, sum);
+}
 
 /*
- * the same as csum_partial, but copies from user space (but on the x86
- * we have just one address space, so this is identical to the above)
+ * These are the 'old' way of doing checksums, a warning message will be
+ * printed if they are used and an exeption occurs.
+ *
+ * these functions should go away after some time.
  */
+
 #define csum_partial_copy_fromuser csum_partial_copy
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
 
 /*
  *	This is a version of ip_compute_csum() optimized for IP headers,
diff -u --recursive --new-file v2.1.24/linux/include/asm-i386/smp_lock.h linux/include/asm-i386/smp_lock.h
--- v2.1.24/linux/include/asm-i386/smp_lock.h	Tue Jan 28 18:50:42 1997
+++ linux/include/asm-i386/smp_lock.h	Sun Feb  2 16:39:41 1997
@@ -6,7 +6,24 @@
 #define lock_kernel()		do { } while(0)
 #define unlock_kernel()		do { } while(0)
 
+typedef struct { } spinlock_t;
+#define SPIN_LOCK_UNLOCKED
+
+#define spin_lock_init(lock)	do { } while(0)
+#define spin_lock(lock)		do { } while(0)
+#define spin_trylock(lock)	do { } while(0)
+#define spin_unlock(lock)	do { } while(0)
+
+#define spin_lock_cli(lock)		\
+({	unsigned long flags;		\
+	save_flags(flags); cli();	\
+	return flags;			\
+})
+
+#define spin_unlock_restore(lock, flags)	restore_flags(flags)
+
 #else
+#include <asm/pgtable.h>
 
 /* Locking the kernel */
 extern __inline__ void lock_kernel(void)
@@ -44,6 +61,92 @@
 	: "m" (current->lock_depth), "i" (NO_PROC_ID)
 	: "ax", "memory");
 }
+
+/* Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ *
+ *	NOT YET TESTED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+typedef unsigned char spinlock_t;
+
+/* Arse backwards is faster for us on Intel (trylock is a clock faster) */
+
+#define SPIN_LOCK_UNLOCKED	1
+
+extern __inline__ void __spinlock_waitfor(spinlock_t *lock)
+{
+	int cpu=smp_processor_id();
+	do
+	{
+		/* Spin reading and let the MESI cache do the right stuff
+		   without us thrashing the bus */
+		while(lock)
+		{
+			/*
+			 *	Not a race, the interrupt will pick up
+			 *	the exiting case that looks suspicious.
+			 *	(The test_bit is not locked so won't
+			 *	 thrash the bus either).
+			 */
+			if(test_bit(cpu,&smp_invalidate_needed))
+			{
+				local_flush_tlb();
+				clear_bit(cpu,&smp_invalidate_needed);
+			}
+		}
+	}
+	while(clear_bit(0,lock));
+}
+
+extern __inline__ void spin_lock_init(spinlock_t *lock)
+{
+	*lock = 1;	/* We assume init does not need to be itself SMP safe */
+}
+
+extern __inline__ void spin_lock(spinlock_t *lock)
+{
+	/* Returns the old value. If we get 1 then we got the lock */
+	if(clear_bit(0,lock))
+	{
+		__spinlock_waitfor(lock);
+	}
+}
+
+extern __inline__ int spin_trylock(spinlock_t *lock)
+{
+	return clear_bit(0,lock);
+}
+
+extern __inline__ void spin_unlock(spinlock_t *lock)
+{
+	set_bit(0,lock);
+}
+
+/* These variants clear interrupts and return save_flags() style flags
+ * to the caller when acquiring a lock.  To release the lock you must
+ * pass the lock pointer as well as the flags returned from the acquisition
+ * routine when releasing the lock.
+ */
+extern __inline__ unsigned long spin_lock_cli(spinlock_t *lock)
+{
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	if(clear_bit(0,lock))
+		__spinlock_waitfor(lock);
+	return flags;
+}
+
+extern __inline__ void spin_unlock_restore(spinlock_t *lock, unsigned long flags)
+{
+	set_bit(0,lock);	/* Locked operation to keep it serialized with
+				   the popfl */
+	restore_flags(flags);
+}
+
 
 #endif /* __SMP__ */
 
diff -u --recursive --new-file v2.1.24/linux/include/linux/ax25.h linux/include/linux/ax25.h
--- v2.1.24/linux/include/linux/ax25.h	Thu Jan 23 21:06:51 1997
+++ linux/include/linux/ax25.h	Sun Feb  2 15:18:47 1997
@@ -6,7 +6,6 @@
 #ifndef	AX25_KERNEL_H
 #define	AX25_KERNEL_H
 
-#define PF_AX25		AF_AX25
 #define AX25_MTU	256
 #define AX25_MAX_DIGIS	6	/* This is wrong, should be 8 */
 
diff -u --recursive --new-file v2.1.24/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v2.1.24/linux/include/linux/if_arp.h	Sun Dec 22 16:37:41 1996
+++ linux/include/linux/if_arp.h	Sun Feb  2 16:41:45 1997
@@ -57,6 +57,7 @@
 #define ARPHRD_FDDI	774		/* Fiber Distributed Data Interface */
 #define ARPHRD_BIF      775             /* AP1000 BIF                   */
 #define ARPHRD_SIT	776		/* sit0 device - IPv6-in-IPv4	*/
+#define ARPHRD_IPDDP	777		/* IP over DDP tunneller	*/
 
 /* ARP protocol opcodes. */
 #define	ARPOP_REQUEST	1		/* ARP request			*/
diff -u --recursive --new-file v2.1.24/linux/include/linux/if_ether.h linux/include/linux/if_ether.h
--- v2.1.24/linux/include/linux/if_ether.h	Fri Apr 12 09:49:46 1996
+++ linux/include/linux/if_ether.h	Sun Feb  2 15:18:47 1997
@@ -85,35 +85,11 @@
 };
 
 /*
- *	Ethernet statistics collection data. 
+ *	We Have changed the ethernet statistics collection data. This
+ *	is just for partial compatibility for now.
  */
  
-struct enet_statistics
-{
-	int	rx_packets;		/* total packets received	*/
-	int	tx_packets;		/* total packets transmitted	*/
-	int	rx_errors;		/* bad packets received		*/
-	int	tx_errors;		/* packet transmit problems	*/
-	int	rx_dropped;		/* no space in linux buffers	*/
-	int	tx_dropped;		/* no space available in linux	*/
-	int	multicast;		/* multicast packets received	*/
-	int	collisions;
-
-	/* detailed rx_errors: */
-	int	rx_length_errors;
-	int	rx_over_errors;		/* receiver ring buff overflow	*/
-	int	rx_crc_errors;		/* recved pkt with crc error	*/
-	int	rx_frame_errors;	/* recv'd frame alignment error */
-	int	rx_fifo_errors;		/* recv'r fifo overrun		*/
-	int	rx_missed_errors;	/* receiver missed packet	*/
-
-	/* detailed tx_errors */
-	int	tx_aborted_errors;
-	int	tx_carrier_errors;
-	int	tx_fifo_errors;
-	int	tx_heartbeat_errors;
-	int	tx_window_errors;
-};
-
+ 
+#define enet_statistics net_device_stats
 
 #endif	/* _LINUX_IF_ETHER_H */
diff -u --recursive --new-file v2.1.24/linux/include/linux/if_ltalk.h linux/include/linux/if_ltalk.h
--- v2.1.24/linux/include/linux/if_ltalk.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/if_ltalk.h	Sun Feb  2 15:18:47 1997
@@ -0,0 +1,12 @@
+#ifndef __LINUX_LTALK_H
+#define __LINUX_LTALK_H
+
+#define LTALK_HLEN		1
+#define LTALK_MTU		600
+#define LTALK_ALEN		1
+
+#ifdef __KERNEL__
+extern void ltalk_setup(struct device *);
+#endif
+
+#endif
diff -u --recursive --new-file v2.1.24/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.1.24/linux/include/linux/netdevice.h	Thu Jan 23 21:06:51 1997
+++ linux/include/linux/netdevice.h	Sun Feb  2 16:41:43 1997
@@ -96,6 +96,42 @@
 };
 
 /*
+ *	Network device statistics. Akin to the 2.0 ether stats but
+ *	with byte counters.
+ */
+ 
+struct net_device_stats
+{
+	unsigned long	rx_packets;		/* total packets received	*/
+	unsigned long	tx_packets;		/* total packets transmitted	*/
+	unsigned long	rx_bytes;		/* total bytes received 	*/
+	unsigned long	tx_bytes;		/* total bytes transmitted	*/
+	unsigned long	rx_errors;		/* bad packets received		*/
+	unsigned long	tx_errors;		/* packet transmit problems	*/
+	unsigned long	rx_dropped;		/* no space in linux buffers	*/
+	unsigned long	tx_dropped;		/* no space available in linux	*/
+	unsigned long	multicast;		/* multicast packets received	*/
+	unsigned long	collisions;
+
+	/* detailed rx_errors: */
+	unsigned long	rx_length_errors;
+	unsigned long	rx_over_errors;		/* receiver ring buff overflow	*/
+	unsigned long	rx_crc_errors;		/* recved pkt with crc error	*/
+	unsigned long	rx_frame_errors;	/* recv'd frame alignment error */
+	unsigned long	rx_fifo_errors;		/* recv'r fifo overrun		*/
+	unsigned long	rx_missed_errors;	/* receiver missed packet	*/
+
+	/* detailed tx_errors */
+	unsigned long	tx_aborted_errors;
+	unsigned long	tx_carrier_errors;
+	unsigned long	tx_fifo_errors;
+	unsigned long	tx_heartbeat_errors;
+	unsigned long	tx_window_errors;
+	
+};
+
+
+/*
  *	The DEVICE structure.
  *	Actually, this whole structure is a big mistake.  It mixes I/O
  *	data with strictly "high-level" data, and it has to know about
@@ -155,7 +191,7 @@
 	 *	should change this.
 	 */
 	 
-	struct enet_statistics* (*get_stats)(struct device *dev);
+	struct net_device_stats* (*get_stats)(struct device *dev);
 	struct iw_statistics*	(*get_wireless_stats)(struct device *dev);
 
 	/*
diff -u --recursive --new-file v2.1.24/linux/include/linux/rose.h linux/include/linux/rose.h
--- v2.1.24/linux/include/linux/rose.h	Thu Jan 23 21:06:52 1997
+++ linux/include/linux/rose.h	Sun Feb  2 15:18:47 1997
@@ -10,7 +10,6 @@
 #define PF_ROSE		AF_ROSE
 #define ROSE_MTU	128
 
-#define ROSE_T0		1
 #define ROSE_T1		2
 #define	ROSE_T2		3
 #define	ROSE_T3		4
diff -u --recursive --new-file v2.1.24/linux/include/linux/sdla_fr.h linux/include/linux/sdla_fr.h
--- v2.1.24/linux/include/linux/sdla_fr.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/sdla_fr.h	Sun Feb  2 15:18:47 1997
@@ -0,0 +1,416 @@
+/*****************************************************************************
+* sdla_fr.h	Sangoma frame relay firmware API definitions.
+*
+* Author:	Gene Kozin	<74604.152@compuserve.com>
+*
+* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Dec 23, 1996	Gene Kozin	v2.0
+* Apr 29, 1996	Gene Kozin	v1.0 (merged version S502 & S508 definitions).
+* Sep 26, 1995	Gene Kozin	Initial version.
+*****************************************************************************/
+#ifndef	_SDLA_FR_H
+#define	_SDLA_FR_H
+
+/*----------------------------------------------------------------------------
+ * Notes:
+ * ------
+ * 1. All structures defined in this file are byte-alined.  To ensure
+ *    portability of this code between different platforms and compilers, one
+ *    of the following defines must be defined before including this file:
+ *
+ *	Compiler	Platform	Define		Use option
+ *	--------	--------	------		----------
+ *	GNU C		Linux		_GNUC_		-
+ *	Microsoft C	DOS/Windows	_MSC_		-
+ */
+
+#ifdef		_GNUC_
+#  ifndef	PACKED
+#    define	PACKED	__attribute__((packed))
+#  endif	/* PACKED */
+#else
+#  define	PACKED
+#endif
+#ifdef		_MSC_
+#  pragma	pack(1)
+#endif
+
+/* Adapter memory layout */
+#define	FR_MB_VECTOR	0xE000	/* mailbox window vector */
+#define	FR502_RX_VECTOR	0xA000	/* S502 direct receive window vector */
+#define	FR502_MBOX_OFFS	0xF60	/* S502 mailbox offset */
+#define	FR508_MBOX_OFFS	0	/* S508 mailbox offset */
+#define	FR502_FLAG_OFFS	0x1FF0	/* S502 status flags offset */
+#define	FR508_FLAG_OFFS	0x1000	/* S508 status flags offset */
+#define	FR502_RXMB_OFFS	0x900	/* S502 direct receive mailbox offset */
+#define	FR508_TXBC_OFFS	0x1100	/* S508 Tx buffer info offset */
+#define	FR508_RXBC_OFFS	0x1120	/* S508 Rx buffer info offset */
+
+/* Important constants */
+#define FR502_MAX_DATA	4096	/* maximum data buffer length */
+#define FR508_MAX_DATA	4080	/* maximum data buffer length */
+
+/****** Data Structures *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * Frame relay command block.
+ */
+typedef struct fr_cmd
+{
+	unsigned char  command	PACKED;	/* command code */
+	unsigned short length	PACKED;	/* length of data buffer */
+	unsigned char  result	PACKED;	/* return code */
+	unsigned short dlci	PACKED;	/* DLCI number */
+	unsigned char  attr	PACKED;	/* FECN, BECN, DE and C/R bits */
+	unsigned short rxlost1	PACKED;	/* frames discarded at int. level */
+	unsigned long  rxlost2	PACKED;	/* frames discarded at app. level */
+	unsigned char  rsrv[2]	PACKED;	/* reserved for future use */
+} fr_cmd_t;
+
+/* 'command' field defines */
+#define	FR_WRITE		0x01
+#define	FR_READ			0x02
+#define	FR_ISSUE_IS_FRAME	0x03
+#define FR_SET_CONFIG		0x10
+#define FR_READ_CONFIG		0x11
+#define FR_COMM_DISABLE		0x12
+#define FR_COMM_ENABLE		0x13
+#define FR_READ_STATUS		0x14
+#define FR_READ_STATISTICS	0x15
+#define FR_FLUSH_STATISTICS	0x16
+#define	FR_LIST_ACTIVE_DLCI	0x17
+#define FR_FLUSH_DATA_BUFFERS	0x18
+#define	FR_ADD_DLCI		0x20
+#define	FR_DELETE_DLCI		0x21
+#define	FR_ACTIVATE_DLCI	0x22
+#define	FR_DEACTIVATE_DLCI	0x22
+#define FR_READ_MODEM_STATUS	0x30
+#define FR_SET_MODEM_STATUS	0x31
+#define FR_READ_ERROR_STATS	0x32
+#define FR_FLUSH_ERROR_STATS	0x33
+#define FR_READ_CODE_VERSION	0x40
+#define	FR_SET_INTR_MODE	0x50
+#define	FR_READ_INTR_MODE	0x51
+
+/* 'result' field defines */
+#define FRRES_OK		0x00	/* command executed successfully */
+#define	FRRES_DISABLED		0x01	/* communications not enabled */
+#define	FRRES_INOPERATIVE	0x02	/* channel inoperative */
+#define	FRRES_DLCI_INACTIVE	0x03	/* DLCI is inactive */
+#define	FRRES_DLCI_INVALID	0x04	/* DLCI is not configured */
+#define	FRRES_TOO_LONG		0x04
+#define	FRRES_TOO_MANY		0x05
+#define	FRRES_CIR_OVERFLOW	0x07	/* Tx throughput has exceeded CIR */
+#define	FRRES_BUFFER_OVERFLOW	0x08
+#define	FRRES_MODEM_FAILURE	0x10	/* DCD and/or CTS dropped */
+#define	FRRES_CHANNEL_DOWN	0x11	/* channel became inoperative */
+#define	FRRES_CHANNEL_UP	0x12	/* channel became operative */
+#define	FRRES_DLCI_CHANGE	0x13	/* DLCI status (or number) changed */
+#define	FRRES_DLCI_MISMATCH	0x14
+#define	FRRES_INVALID_CMD	0x1F	/* invalid command */
+
+/* 'attr' field defines */
+#define	FRATTR_
+
+/*----------------------------------------------------------------------------
+ * Frame relay mailbox.
+ *	This structure is located at offset FR50?_MBOX_OFFS into FR_MB_VECTOR.
+ *	For S502 it is also located at offset FR502_RXMB_OFFS into
+ *	FR502_RX_VECTOR.
+ */
+typedef struct fr_mbox
+{
+	unsigned char opflag	PACKED;	/* 00h: execution flag */
+	fr_cmd_t cmd		PACKED;	/* 01h: command block */
+	unsigned char data[1]	PACKED;	/* 10h: variable length data buffer */
+} fr_mbox_t;
+
+/*----------------------------------------------------------------------------
+ * S502 frame relay status flags.
+ *	This structure is located at offset FR502_FLAG_OFFS into FR_MB_VECTOR.
+ */
+typedef struct	fr502_flags
+{	
+	unsigned char rsrv1[1]	PACKED;	/* 00h: */
+	unsigned char tx_ready	PACKED;	/* 01h: Tx buffer available */
+	unsigned char rx_ready	PACKED;	/* 02h: Rx frame available */
+	unsigned char event	PACKED;	/* 03h: asynchronous event */
+	unsigned char mstatus	PACKED;	/* 04h: modem status */
+	unsigned char rsrv2[8]	PACKED;	/* 05h: */
+	unsigned char iflag	PACKED;	/* 0Dh: interrupt flag */
+	unsigned char imask	PACKED;	/* 0Eh: interrupt mask */
+} fr502_flags_t;
+
+/*----------------------------------------------------------------------------
+ * S508 frame relay status flags.
+ *	This structure is located at offset FR508_FLAG_OFFS into FR_MB_VECTOR.
+ */
+typedef struct	fr508_flags
+{
+	unsigned char rsrv1[3]	PACKED;	/* 00h: reserved */
+	unsigned char event	PACKED;	/* 03h: asynchronous event */
+	unsigned char mstatus	PACKED;	/* 04h: modem status */
+	unsigned char rsrv2[11]	PACKED;	/* 05h: reserved */
+	unsigned char iflag	PACKED;	/* 10h: interrupt flag */
+	unsigned char imask	PACKED;	/* 11h: interrupt mask */
+	unsigned long tse_offs	PACKED;	/* 12h: Tx status element */
+} fr508_flags_t;
+
+/* 'event' field defines */
+#define	FR_EVENT_STATUS		0x01	/* channel status change ??? */
+#define	FR_EVENT_DLC_STATUS	0x02	/* DLC status change */
+#define	FR_EVENT_BAD_DLCI	0x04	/* FSR included wrong DLCI */
+#define	FR_EVENT_LINK_DOWN	0x40	/* DCD or CTS low */
+
+/* 'mstatus' field defines */
+#define	FR_MDM_DCD		0x08	/* mdm_status: DCD */
+#define	FR_MDM_CTS		0x20	/* mdm_status: CTS */
+
+/* 'iflag' & 'imask' fields defines */
+#define	FR_INTR_RXRDY		0x01	/* Rx ready */
+#define	FR_INTR_TXRDY		0x02	/* Tx ready */
+#define	FR_INTR_MODEM		0x04	/* modem status change (DCD, CTS) */
+#define	FR_INTR_READY		0x08	/* interface command completed */
+#define	FR_INTR_DLC		0x10	/* DLC status change */
+#define	FR_INTR_TIMER		0x20	/* millisecond timer */
+
+/*----------------------------------------------------------------------------
+ * Receive Buffer Configuration Info. S508 only!
+ *	This structure is located at offset FR508_RXBC_OFFS into FR_MB_VECTOR.
+ */
+typedef struct	fr_buf_info
+{
+	unsigned short rse_num	PACKED;	/* 00h: number of status elements */
+	unsigned long rse_base	PACKED;	/* 02h: receive status array base */
+	unsigned long rse_next	PACKED;	/* 06h: next status element */
+	unsigned long buf_base	PACKED;	/* 0Ah: rotational buffer base */
+	unsigned short reserved	PACKED;	/* 0Eh:  */
+	unsigned long buf_top	PACKED;	/* 10h: rotational buffer top */
+} fr_buf_info_t;
+
+/*----------------------------------------------------------------------------
+ * Buffer Status Element. S508 only!
+ *	Array of structures of this type is located at offset defined by the
+ *	'rse_base' field of the frBufInfo_t structure into absolute adapter
+ *	memory address space.
+ */
+typedef struct	fr_buf_ctl
+{
+	unsigned char flag	PACKED;	/* 00h: ready flag */
+	unsigned short length	PACKED;	/* 01h: frame length */
+	unsigned short dlci	PACKED;	/* 03h: DLCI */
+	unsigned char attr	PACKED;	/* 05h: FECN/BECN/DE/CR */
+	unsigned short tmstamp	PACKED;	/* 06h: time stamp */
+	unsigned short rsrv[2]	PACKED; /* 08h:  */
+	unsigned long offset	PACKED;	/* 0Ch: buffer absolute address */
+} fr_buf_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * Global Configuration Block. Passed to FR_SET_CONFIG command when dlci == 0.
+ */
+typedef struct	fr_conf
+{
+	unsigned short station	PACKED;	/* 00h: CPE/Node */
+	unsigned short options	PACKED;	/* 02h: configuration options */
+	unsigned short kbps	PACKED;	/* 04h: baud rate in kbps */
+	unsigned short port	PACKED;	/* 06h: RS-232/V.35 */
+	unsigned short mtu	PACKED;	/* 08h: max. transmit length */
+	unsigned short t391	PACKED;	/* 0Ah:  */
+	unsigned short t392	PACKED;	/* 0Ch:  */
+	unsigned short n391	PACKED;	/* 0Eh:  */
+	unsigned short n392	PACKED;	/* 10h:  */
+	unsigned short n393	PACKED;	/* 12h:  */
+	unsigned short cir_fwd	PACKED;	/* 14h:  */
+	unsigned short bc_fwd	PACKED;	/* 16h:  */
+	unsigned short be_fwd	PACKED;	/* 18h:  */
+	unsigned short cir_bwd	PACKED;	/* 1Ah:  */
+	unsigned short bc_bwd	PACKED;	/* 1Ch:  */
+	unsigned short be_bwd	PACKED;	/* 1Eh:  */
+	unsigned short dlci[0]	PACKED;	/* 20h:  */
+} fr_conf_t;
+
+/* 'station_type' defines */
+#define	FRCFG_STATION_CPE	0
+#define	FRCFG_STATION_NODE	1
+
+/* 'conf_flags' defines */
+#define	FRCFG_IGNORE_TX_CIR	0x0001
+#define	FRCFG_IGNORE_RX_CIR	0x0002
+#define	FRCFG_DONT_RETRANSMIT	0x0004
+#define	FRCFG_IGNORE_CBS	0x0008
+#define	FRCFG_THROUGHPUT	0x0010	/* enable throughput calculation */
+#define	FRCFG_DIRECT_RX		0x0080	/* enable direct receive buffer */
+#define	FRCFG_AUTO_CONFIG	0x8000	/* enable  auto DLCI configuration */
+
+/* 'baud_rate' defines */
+#define	FRCFG_BAUD_1200		12
+#define	FRCFG_BAUD_2400		24
+#define	FRCFG_BAUD_4800		48
+#define	FRCFG_BAUD_9600		96
+#define	FRCFG_BAUD_19200	19
+#define	FRCFG_BAUD_38400	38
+#define	FRCFG_BAUD_56000	56
+#define	FRCFG_BAUD_64000	64
+#define	FRCFG_BAUD_128000	128
+
+/* 'port_mode' defines */
+#define	FRCFG_MODE_EXT_CLK	0x0000
+#define	FRCFG_MODE_INT_CLK	0x0001
+#define	FRCFG_MODE_V35		0x0000	/* S508 only */
+#define	FRCFG_MODE_RS232	0x0002	/* S508 only */
+
+/*----------------------------------------------------------------------------
+ * Channel configuration.
+ *	This structure is passed to the FR_SET_CONFIG command when dlci != 0.
+ */
+typedef struct	fr_dlc_conf
+{
+	unsigned short conf_flags	PACKED;	/* 00h: configuration bits */
+	unsigned short cir_fwd		PACKED;	/* 02h:  */
+	unsigned short bc_fwd		PACKED;	/* 04h:  */
+	unsigned short be_fwd		PACKED;	/* 06h:  */
+	unsigned short cir_bwd		PACKED;	/* 08h:  */
+	unsigned short bc_bwd		PACKED;	/* 0Ah:  */
+	unsigned short be_bwd		PACKED;	/* 0Ch:  */
+} fr_dlc_conf_t;
+
+/*----------------------------------------------------------------------------
+ * S502 Interrupt mode control block.
+ *	This structure is passed to the FR_SET_INTR_FLAGS and returned by the
+ *	FR_READ_INTR_FLAGS commands.
+ */
+typedef struct fr502_intr_ctl
+{
+	unsigned char mode	PACKED;	/* 00h: interrupt enable flags */
+	unsigned short tx_len	PACKED;	/* 01h: required Tx buffer size */
+} fr502_intr_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * S508 Interrupt mode control block.
+ *	This structure is passed to the FR_SET_INTR_FLAGS and returned by the
+ *	FR_READ_INTR_FLAGS commands.
+ */
+typedef struct fr508_intr_ctl
+{
+	unsigned char mode	PACKED;	/* 00h: interrupt enable flags */
+	unsigned short tx_len	PACKED;	/* 01h: required Tx buffer size */
+	unsigned char irq	PACKED;	/* 03h: IRQ level to activate */
+	unsigned char flags	PACKED;	/* 04h: ?? */
+	unsigned short timeout	PACKED;	/* 05h: ms, for timer interrupt */
+} fr508_intr_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * Channel Status.
+ *	This structure is returned by the FR_READ_STATUS command.
+ */
+typedef struct	frDLCStatus
+{
+	unsigned char status		PACKED;	/* 00h: link/DLCI status */
+	struct
+	{
+		unsigned short dlci	PACKED;	/* 01h: DLCI number */
+		unsigned char status	PACKED;	/* 03h: DLCI status */
+	} circuit[1]			PACKED;
+} frDLCStatus_t;
+
+/* 'status' defines */
+#define	FR_LINK_INOPER	0x00		/* for global status (DLCI == 0) */
+#define	FR_LINK_OPER	0x01
+#define	FR_DLCI_DELETED	0x01		/* for circuit status (DLCI != 0) */
+#define	FR_DLCI_ACTIVE	0x02
+#define	FR_DLCI_WAITING	0x04
+#define	FR_DLCI_NEW	0x08
+#define	FR_DLCI_REPORT	0x40
+
+/*----------------------------------------------------------------------------
+ * Global Statistics Block.
+ *	This structure is returned by the FR_READ_STATISTICS command when
+ *	dcli == 0.
+ */
+typedef struct	frLinkStat
+{
+	unsigned short rx_too_long	PACKED;	/* 00h:  */
+	unsigned short rx_dropped	PACKED;	/* 02h:  */
+	unsigned short rx_dropped2	PACKED;	/* 04h:  */
+	unsigned short rx_bad_dlci	PACKED;	/* 06h:  */
+	unsigned short rx_bad_format	PACKED;	/* 08h:  */
+	unsigned short retransmitted	PACKED;	/* 0Ah:  */
+	unsigned short cpe_tx_FSE	PACKED;	/* 0Ch:  */
+	unsigned short cpe_tx_LIV	PACKED;	/* 0Eh:  */
+	unsigned short cpe_rx_FSR	PACKED;	/* 10h:  */
+	unsigned short cpe_rx_LIV	PACKED;	/* 12h:  */
+	unsigned short node_rx_FSE	PACKED;	/* 14h:  */
+	unsigned short node_rx_LIV	PACKED;	/* 16h:  */
+	unsigned short node_tx_FSR	PACKED;	/* 18h:  */
+	unsigned short node_tx_LIV	PACKED;	/* 1Ah:  */
+	unsigned short rx_ISF_err	PACKED;	/* 1Ch:  */
+	unsigned short rx_unsolicited	PACKED;	/* 1Eh:  */
+	unsigned short rx_SSN_err	PACKED;	/* 20h:  */
+	unsigned short rx_RSN_err	PACKED;	/* 22h:  */
+	unsigned short T391_timeouts	PACKED;	/* 24h:  */
+	unsigned short T392_timeouts	PACKED;	/* 26h:  */
+	unsigned short N392_reached	PACKED;	/* 28h:  */
+	unsigned short cpe_SSN_RSN	PACKED;	/* 2Ah:  */
+	unsigned short current_SSN	PACKED;	/* 2Ch:  */
+	unsigned short current_RSN	PACKED;	/* 2Eh:  */
+	unsigned short curreny_T391	PACKED;	/* 30h:  */
+	unsigned short current_T392	PACKED;	/* 32h:  */
+	unsigned short current_N392	PACKED;	/* 34h:  */
+	unsigned short current_N393	PACKED;	/* 36h:  */
+} frLinkStat_t;
+
+/*----------------------------------------------------------------------------
+ * DLCI Statistics.
+ *	This structure is returned by the FR_READ_STATISTICS command when
+ *	dlci != 0.
+ */
+typedef struct	frDLCIStat
+{
+	unsigned long tx_frames		PACKED;	/* 00h:  */
+	unsigned long tx_bytes		PACKED;	/* 04h:  */
+	unsigned long rx_frames		PACKED;	/* 08h:  */
+	unsigned long rx_bytes		PACKED;	/* 0Ch:  */
+	unsigned long rx_dropped	PACKED;	/* 10h:  */
+	unsigned long rx_inactive	PACKED;	/* 14h:  */
+	unsigned long rx_exceed_CIR	PACKED;	/* 18h:  */
+	unsigned long rx_DE_set		PACKED;	/* 1Ch:  */
+	unsigned long tx_throughput	PACKED;	/* 20h:  */
+	unsigned long tx_calc_timer	PACKED;	/* 24h:  */
+	unsigned long rx_throughput	PACKED;	/* 28h:  */
+	unsigned long rx_calc_timer	PACKED;	/* 2Ch:  */
+} frDLCIStat_t;
+
+/*----------------------------------------------------------------------------
+ * Communications Error Statistics.
+ *	This structure is returned by the FR_READ_ERROR_STATS command.
+ */
+typedef struct	frCommStat
+{
+	unsigned char rx_overruns	PACKED;	/* 00h:  */
+	unsigned char rx_bad_crc	PACKED;	/* 01h:  */
+	unsigned char rx_aborts		PACKED;	/* 02h:  */
+	unsigned char rx_too_long	PACKED;	/* 03h:  */
+	unsigned char tx_aborts		PACKED;	/* 04h:  */
+	unsigned char tx_underruns	PACKED;	/* 05h:  */
+	unsigned char tx_missed_undr	PACKED;	/* 06h:  */
+	unsigned char dcd_dropped	PACKED;	/* 07h:  */
+	unsigned char cts_dropped	PACKED;	/* 08h:  */
+} frCommStat_t;
+
+/*----------------------------------------------------------------------------
+ * Defines for the FR_ISSUE_IS_FRAME command.
+ */
+#define	FR_ISF_LVE	2		/* issue Link Verification Enquiry */
+#define	FR_ISF_FSE	3		/* issue Full Status Enquiry */
+
+#ifdef		_MSC_
+#  pragma	pack()
+#endif
+#endif	/* _SDLA_FR_H */
+
diff -u --recursive --new-file v2.1.24/linux/include/linux/sdla_ppp.h linux/include/linux/sdla_ppp.h
--- v2.1.24/linux/include/linux/sdla_ppp.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/sdla_ppp.h	Sun Feb  2 15:18:47 1997
@@ -0,0 +1,536 @@
+/*****************************************************************************
+* sdla_ppp.h	Sangoma PPP firmware API definitions.
+*
+* Author:	Gene Kozin	<74604.152@compuserve.com>
+*
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Jan 06, 1997	Gene Kozin	v2.0
+* Apr 11, 1996	Gene Kozin	Initial version.
+*****************************************************************************/
+#ifndef	_SDLA_PPP_H
+#define	_SDLA_PPP_H
+
+/*----------------------------------------------------------------------------
+ * Notes:
+ * ------
+ * 1. All structures defined in this file are byte-alined.  To ensure
+ *    portability of this code between different platforms and compilers, one
+ *    of the following defines must be defined before including this file:
+ *
+ *	Compiler	Platform	Define		Use option
+ *	--------	--------	------		----------
+ *	GNU C		Linux		_GNUC_		-
+ *	Microsoft C	DOS/Windows	_MSC_		-
+ */
+
+#ifdef		_GNUC_
+#  ifndef	PACKED
+#    define	PACKED	__attribute__((packed))
+#  endif	/* PACKED */
+#else
+#  define	PACKED
+#endif
+#ifdef		_MSC_
+#  pragma	pack(1)
+#endif
+
+/* Adapter memory layout and important constants */
+
+#define	PPP502_MB_VECT	0xA000	/* mailbox window vector */
+#define	PPP502_MB_OFFS	0x1C00	/* mailbox offset */
+#define	PPP502_FLG_OFFS	0	/* status flags offset */
+#define	PPP502_BUF_OFFS	0x0010	/* buffer info block offset */
+
+#define	PPP508_MB_VECT	0xE000	/* mailbox window vector */
+#define	PPP508_MB_OFFS	0	/* mailbox offset */
+#define	PPP508_FLG_OFFS	0x1000	/* status flags offset */
+#define	PPP508_BUF_OFFS	0x1100	/* buffer info block offset */
+
+#define PPP_MAX_DATA	1008	/* command block data buffer length */
+
+/****** Data Structures *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * PPP Command Block.
+ */
+typedef struct ppp_cmd
+{
+	unsigned char  command	PACKED;	/* command code */
+	unsigned short length	PACKED;	/* length of data buffer */
+	unsigned char  result	PACKED;	/* return code */
+	unsigned char  rsrv[11]	PACKED;	/* reserved for future use */
+} ppp_cmd_t;
+
+/* 'command' field defines */
+#define PPP_READ_CODE_VERSION	0x10	/* configuration commands */
+#define PPP_SET_CONFIG		0x05
+#define PPP_READ_CONFIG		0x06
+#define	PPP_SET_INTR_FLAGS	0x20
+#define	PPP_READ_INTR_FLAGS	0x21
+#define	PPP_SET_INBOUND_AUTH	0x30
+#define	PPP_SET_OUTBOUND_AUTH	0x31
+#define	PPP_GET_CONNECTION_INFO	0x32
+
+#define PPP_COMM_ENABLE		0x03	/* operational commands */
+#define PPP_COMM_DISABLE	0x04
+#define	PPP_SEND_SIGN_FRAME	0x23
+#define	PPP_READ_SIGN_RESPONSE	0x24
+#define	PPP_DATALINE_MONITOR	0x33
+
+#define PPP_READ_STATISTICS	0x07	/* statistics commands */
+#define PPP_FLUSH_STATISTICS	0x08
+#define PPP_READ_ERROR_STATS	0x09
+#define PPP_FLUSH_ERROR_STATS	0x0A
+#define PPP_READ_PACKET_STATS	0x12
+#define PPP_FLUSH_PACKET_STATS	0x13
+#define PPP_READ_LCP_STATS	0x14
+#define PPP_FLUSH_LCP_STATS	0x15
+#define PPP_READ_LPBK_STATS	0x16
+#define PPP_FLUSH_LPBK_STATS	0x17
+#define PPP_READ_IPCP_STATS	0x18
+#define PPP_FLUSH_IPCP_STATS	0x19
+#define PPP_READ_IPXCP_STATS	0x1A
+#define PPP_FLUSH_IPXCP_STATS	0x1B
+#define PPP_READ_PAP_STATS	0x1C
+#define PPP_FLUSH_PAP_STATS	0x1D
+#define PPP_READ_CHAP_STATS	0x1E
+#define PPP_FLUSH_CHAP_STATS	0x1F
+
+/* 'result' field defines */
+#define PPPRES_OK		0x00	/* command executed successfully */
+#define	PPPRES_INVALID_STATE	0x09	/* invalid command in this context */
+
+/*----------------------------------------------------------------------------
+ * PPP Mailbox.
+ *	This structure is located at offset PPP???_MB_OFFS into PPP???_MB_VECT
+ */
+typedef struct ppp_mbox
+{
+	unsigned char flag	PACKED;	/* 00h: command execution flag */
+	ppp_cmd_t     cmd	PACKED; /* 01h: command block */
+	unsigned char data[1]	PACKED;	/* 10h: variable length data buffer */
+} ppp_mbox_t;
+
+/*----------------------------------------------------------------------------
+ * PPP Status Flags.
+ *	This structure is located at offset PPP???_FLG_OFFS into
+ *	PPP???_MB_VECT.
+ */
+typedef struct	ppp_flags
+{
+	unsigned char iflag		PACKED;	/* 00: interrupt flag */
+	unsigned char imask		PACKED;	/* 01: interrupt mask */
+	unsigned char resrv		PACKED;
+	unsigned char mstatus		PACKED;	/* 03: modem status */
+	unsigned char lcp_state		PACKED; /* 04: LCP state */
+	unsigned char ppp_phase		PACKED;	/* 05: PPP phase */
+	unsigned char ip_state		PACKED; /* 06: IPCP state */
+	unsigned char ipx_state		PACKED; /* 07: IPXCP state */
+	unsigned char pap_state		PACKED; /* 08: PAP state */
+	unsigned char chap_state	PACKED; /* 09: CHAP state */
+	unsigned short disc_cause	PACKED;	/* 0A: disconnection cause */
+} ppp_flags_t;
+
+/* 'iflag' defines */
+#define	PPP_INTR_RXRDY		0x01	/* Rx ready */
+#define	PPP_INTR_TXRDY		0x02	/* Tx ready */
+#define	PPP_INTR_MODEM		0x04	/* modem status change (DCD, CTS) */
+#define	PPP_INTR_CMD		0x08	/* interface command completed */
+#define	PPP_INTR_DISC		0x10	/* data link disconnected */
+#define	PPP_INTR_OPEN		0x20	/* data link open */
+#define	PPP_INTR_DROP_DTR	0x40	/* DTR drop timeout expired */
+
+/* 'mstatus' defines */
+#define	PPP_MDM_DCD		0x08	/* mdm_status: DCD */
+#define	PPP_MDM_CTS		0x20	/* mdm_status: CTS */
+
+/*----------------------------------------------------------------------------
+ * PPP Buffer Info.
+ *	This structure is located at offset PPP502_BUF_OFFS into
+ *	PPP502_MB_VECT.
+ */
+typedef struct	ppp502_buf_info
+{
+	unsigned short txb_num	PACKED;	/* 00: number of transmit buffers */
+	unsigned short txb_offs	PACKED;	/* 02: offset of the buffer ctl. */
+	unsigned char  rsrv1[4]	PACKED;
+	unsigned short rxb_num	PACKED;	/* 08: number of receive buffers */
+	unsigned short rxb_offs	PACKED;	/* 0A: offset of the buffer ctl. */
+	unsigned char  rsrv2[2]	PACKED;
+	unsigned short rxb_next	PACKED; /* 0E: index of the next buffer */
+} ppp502_buf_info_t;
+
+/*----------------------------------------------------------------------------
+ * PPP Buffer Info.
+ *	This structure is located at offset PPP508_BUF_OFFS into
+ *	PPP508_MB_VECT.
+ */
+typedef struct	ppp508_buf_info
+{
+	unsigned short txb_num	PACKED;	/* 00: number of transmit buffers */
+	unsigned long  txb_ptr	PACKED;	/* 02: pointer to the buffer ctl. */
+	unsigned char  rsrv1[26] PACKED;
+	unsigned short rxb_num	PACKED;	/* 20: number of receive buffers */
+	unsigned long  rxb_ptr	PACKED;	/* 22: pointer to the buffer ctl. */
+	unsigned long  rxb1_ptr	PACKED;	/* 26: pointer to the first buf.ctl. */
+	unsigned long  rxb_base	PACKED;	/* 2A: pointer to the buffer base */
+	unsigned char  rsrv2[2]	PACKED;
+	unsigned long  rxb_end	PACKED;	/* 30: pointer to the buffer end */
+} ppp508_buf_info_t;
+
+/*----------------------------------------------------------------------------
+ * Transmit/Receive Buffer Control Block.
+ */
+typedef struct	ppp_buf_ctl
+{
+	unsigned char  flag		PACKED;	/* 00: 'buffer ready' flag */
+	unsigned short length		PACKED;	/* 01: length of data */
+	unsigned char  reserved1[1]	PACKED;	/* 03: */
+	unsigned char  proto		PACKED;	/* 04: protocol */
+	unsigned short timestamp	PACKED;	/* 05: time stamp (Rx only) */
+	unsigned char  reserved2[5]	PACKED;	/* 07: */
+	union
+	{
+		unsigned short o_p[2];	/* 1C: buffer offset & page (S502) */
+		unsigned long  ptr;	/* 1C: buffer pointer (S508) */
+	} buf				PACKED;
+} ppp_buf_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * S502 Adapter Configuration Block (passed to the PPP_SET_CONFIG command).
+ */
+typedef struct	ppp502_conf
+{
+	unsigned char  line_speed	PACKED;	/* 00: 0 - external clk. */
+	unsigned short txbuf_num	PACKED;	/* 01: number of Tx buffers */
+	unsigned short conf_flags	PACKED;	/* 03: configuration bits */
+	unsigned short mtu_local	PACKED;	/* 05: local MTU */
+	unsigned short mtu_remote	PACKED;	/* 07: remote MTU */
+	unsigned short restart_tmr	PACKED;	/* 09: restart timer */
+	unsigned short auth_rsrt_tmr	PACKED;	/* 0B: authentication timer */
+	unsigned short auth_wait_tmr	PACKED;	/* 0D: authentication timer */
+	unsigned short mdm_fail_tmr	PACKED;	/* 0F: modem failure timer */
+	unsigned short dtr_drop_tmr	PACKED;	/* 11: DTR drop timer */
+	unsigned short connect_tmout	PACKED;	/* 13: connection timeout */
+	unsigned short conf_retry	PACKED;	/* 15: max. retry */
+	unsigned short term_retry	PACKED;	/* 17: max. retry */
+	unsigned short fail_retry	PACKED;	/* 19: max. retry */
+	unsigned short auth_retry	PACKED;	/* 1B: max. retry */
+	unsigned char  auth_options	PACKED;	/* 1D: authentication opt. */
+	unsigned char  ip_options	PACKED;	/* 1E: IP options */
+	unsigned char  ip_local[4]	PACKED;	/* 1F: local IP address */
+	unsigned char  ip_remote[4]	PACKED;	/* 23: remote IP address */
+	unsigned char  ipx_options	PACKED;	/* 27: IPX options */
+	unsigned char  ipx_netno[4]	PACKED;	/* 28: IPX net number */
+	unsigned char  ipx_local[6]	PACKED;	/* 2C: local IPX node number*/
+	unsigned char  ipx_remote[6]	PACKED;	/* 32: remote IPX node num.*/
+	unsigned char  ipx_router[48]	PACKED;	/* 38: IPX router name*/
+} ppp502_conf_t;
+
+/*----------------------------------------------------------------------------
+ * S508 Adapter Configuration Block (passed to the PPP_SET_CONFIG command).
+ */
+typedef struct	ppp508_conf
+{
+	unsigned long  line_speed	PACKED;	/* 00: baud rate, bps */
+	unsigned short txbuf_percent	PACKED;	/* 04: % of Tx buffer */
+	unsigned short conf_flags	PACKED;	/* 06: configuration bits */
+	unsigned short mtu_local	PACKED;	/* 08: local MTU */
+	unsigned short mtu_remote	PACKED;	/* 0A: remote MTU */
+	unsigned short restart_tmr	PACKED;	/* 0C: restart timer */
+	unsigned short auth_rsrt_tmr	PACKED;	/* 0E: authentication timer */
+	unsigned short auth_wait_tmr	PACKED;	/* 10: authentication timer */
+	unsigned short mdm_fail_tmr	PACKED;	/* 12: modem failure timer */
+	unsigned short dtr_drop_tmr	PACKED;	/* 14: DTR drop timer */
+	unsigned short connect_tmout	PACKED;	/* 16: connection timeout */
+	unsigned short conf_retry	PACKED;	/* 18: max. retry */
+	unsigned short term_retry	PACKED;	/* 1A: max. retry */
+	unsigned short fail_retry	PACKED;	/* 1C: max. retry */
+	unsigned short auth_retry	PACKED;	/* 1E: max. retry */
+	unsigned char  auth_options	PACKED;	/* 20: authentication opt. */
+	unsigned char  ip_options	PACKED;	/* 21: IP options */
+	unsigned char  ip_local[4]	PACKED;	/* 22: local IP address */
+	unsigned char  ip_remote[4]	PACKED;	/* 26: remote IP address */
+	unsigned char  ipx_options	PACKED;	/* 2A: IPX options */
+	unsigned char  ipx_netno[4]	PACKED;	/* 2B: IPX net number */
+	unsigned char  ipx_local[6]	PACKED;	/* 2F: local IPX node number*/
+	unsigned char  ipx_remote[6]	PACKED;	/* 35: remote IPX node num.*/
+	unsigned char  ipx_router[48]	PACKED;	/* 3B: IPX router name*/
+	unsigned long  alt_cpu_clock	PACKED;	/* 6B:  */
+} ppp508_conf_t;
+
+/* 'line_speed' field */
+#define	PPP_BITRATE_1200	0x01
+#define	PPP_BITRATE_2400	0x02
+#define	PPP_BITRATE_4800	0x03
+#define	PPP_BITRATE_9600	0x04
+#define	PPP_BITRATE_19200	0x05
+#define	PPP_BITRATE_38400	0x06
+#define	PPP_BITRATE_45000	0x07
+#define	PPP_BITRATE_56000	0x08
+#define	PPP_BITRATE_64000	0x09
+#define	PPP_BITRATE_74000	0x0A
+#define	PPP_BITRATE_112000	0x0B
+#define	PPP_BITRATE_128000	0x0C
+#define	PPP_BITRATE_156000	0x0D
+
+/* Defines for the 'conf_flags' field */
+#define	PPP_IGNORE_TX_ABORT	0x01	/* don't re-transmit aborted frames */
+#define	PPP_ENABLE_TX_STATS	0x02	/* enable Tx statistics */
+#define	PPP_ENABLE_RX_STATS	0x04	/* enable Rx statistics */
+#define	PPP_ENABLE_TIMESTAMP	0x08	/* enable timestamp */
+
+/* 'ip_options' defines */
+#define	PPP_LOCAL_IP_LOCAL	0x01
+#define	PPP_LOCAL_IP_REMOTE	0x02
+#define	PPP_REMOTE_IP_LOCAL	0x04
+#define	PPP_REMOTE_IP_REMOTE	0x08
+
+/* 'ipx_options' defines */
+#define	PPP_REMOTE_IPX_NETNO	0x01
+#define	PPP_REMOTE_IPX_LOCAL	0x02
+#define	PPP_REMOTE_IPX_REMOTE	0x04
+#define	PPP_IPX_ROUTE_RIP_SAP	0x08
+#define	PPP_IPX_ROUTE_NLSP	0x10
+#define	PPP_IPX_ROUTE_DEFAULT	0x20
+#define	PPP_IPX_CONF_COMPLETE	0x40
+#define	PPP_IPX_ENABLE		0x80
+
+/*----------------------------------------------------------------------------
+ * S502 Adapter Configuration Block (returned by the PPP_READ_CONFIG command).
+ */
+typedef struct	ppp502_get_conf
+{
+	ppp502_conf_t  conf	PACKED;	/* 00: requested config. */
+	unsigned short txb_num	PACKED;	/* 68: number of Tx buffers */
+	unsigned short rxb_num	PACKED;	/* 6A: number of Rx buffers */
+} ppp502_get_conf_t;
+
+/*----------------------------------------------------------------------------
+ * S508 Adapter Configuration Block (returned by the PPP_READ_CONFIG command).
+ */
+typedef struct	ppp508_get_conf
+{
+	unsigned long  bps	PACKED;	/* 00: baud rate, bps */
+	ppp508_conf_t  conf	PACKED;	/* 04: requested config. */
+	unsigned short txb_num	PACKED;	/* 6F: number of Tx buffers */
+	unsigned short rxb_num	PACKED;	/* 71: number of Rx buffers */
+} ppp508_get_conf_t;
+
+/*----------------------------------------------------------------------------
+ * S502 Operational Statistics (returned by the PPP_READ_STATISTIC command).
+ */
+typedef struct ppp502_Stats
+{
+	unsigned short rx_lost_intr	PACKED;	/* 00: */
+	unsigned short rx_lost_buff	PACKED;	/* 02: */
+	unsigned short tx_abort	PACKED;	/* 04: */
+	unsigned long  tx_frames	PACKED;	/* 06: */
+	unsigned long  tx_bytes	PACKED;	/* 0A: */
+	unsigned long  rx_frames	PACKED;	/* 0E: */
+	unsigned long  rx_bytes	PACKED;	/* 12: */
+} ppp502_Stats_t;
+
+/*----------------------------------------------------------------------------
+ * S508 Operational Statistics (returned by the PPP_READ_STATISTIC command).
+ */
+typedef struct ppp508_stats
+{
+	unsigned short reserved1	PACKED;	/* 00: */
+	unsigned short rx_bad_len	PACKED;	/* 02: */
+	unsigned short reserved2	PACKED;	/* 04: */
+	unsigned long  tx_frames	PACKED;	/* 06: */
+	unsigned long  tx_bytes	PACKED;	/* 0A: */
+	unsigned long  rx_frames	PACKED;	/* 0E: */
+	unsigned long  rx_bytes	PACKED;	/* 12: */
+} ppp508_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Adapter Error Statistics (returned by the PPP_READ_ERROR_STATS command).
+ */
+typedef struct	ppp_err_stats
+{
+	unsigned char	 rx_overrun	PACKED;	/* 00: Rx overrun errors */
+	unsigned char	 rx_bad_crc	PACKED;	/* 01: Rx CRC errors */
+	unsigned char	 rx_abort	PACKED;	/* 02: Rx aborted frames */
+	unsigned char	 rx_lost	PACKED;	/* 03: Rx frames lost */
+	unsigned char	 tx_abort	PACKED;	/* 04: Tx aborted frames */
+	unsigned char	 tx_underrun	PACKED;	/* 05: Tx underrun errors */
+	unsigned char	 tx_missed_intr	PACKED;	/* 06: Tx underruns missed */
+	unsigned char	 reserved	PACKED;	/* 07: Tx underruns missed */
+	unsigned char	 dcd_trans	PACKED;	/* 08: DCD transitions */
+	unsigned char	 cts_trans	PACKED;	/* 09: CTS transitions */
+} ppp_err_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Packet Statistics (returned by the PPP_READ_PACKET_STATS command).
+ */
+typedef struct	ppp_pkt_stats
+{
+	unsigned short rx_bad_header	PACKED;	/* 00: */
+	unsigned short rx_prot_unknwn	PACKED;	/* 02: */
+	unsigned short rx_too_large	PACKED;	/* 04: */
+	unsigned short rx_lcp		PACKED;	/* 06: */
+	unsigned short tx_lcp		PACKED;	/* 08: */
+	unsigned short rx_ipcp		PACKED;	/* 0A: */
+	unsigned short tx_ipcp		PACKED;	/* 0C: */
+	unsigned short rx_ipxcp		PACKED;	/* 0E: */
+	unsigned short tx_ipxcp		PACKED;	/* 10: */
+	unsigned short rx_pap		PACKED;	/* 12: */
+	unsigned short tx_pap		PACKED;	/* 14: */
+	unsigned short rx_chap		PACKED;	/* 16: */
+	unsigned short tx_chap		PACKED;	/* 18: */
+	unsigned short rx_lqr		PACKED;	/* 1A: */
+	unsigned short tx_lqr		PACKED;	/* 1C: */
+	unsigned short rx_ip		PACKED;	/* 1E: */
+	unsigned short tx_ip		PACKED;	/* 20: */
+	unsigned short rx_ipx		PACKED;	/* 22: */
+	unsigned short tx_ipx		PACKED;	/* 24: */
+} ppp_pkt_stats_t;
+
+/*----------------------------------------------------------------------------
+ * LCP Statistics (returned by the PPP_READ_LCP_STATS command).
+ */
+typedef struct	ppp_lcp_stats
+{
+	unsigned short rx_unknown	PACKED;	/* 00: unknown LCP type */
+	unsigned short rx_conf_rqst	PACKED;	/* 02: Configure-Request */
+	unsigned short rx_conf_ack	PACKED;	/* 04: Configure-Ack */
+	unsigned short rx_conf_nak	PACKED;	/* 06: Configure-Nak */
+	unsigned short rx_conf_rej	PACKED;	/* 08: Configure-Reject */
+	unsigned short rx_term_rqst	PACKED;	/* 0A: Terminate-Request */
+	unsigned short rx_term_ack	PACKED;	/* 0C: Terminate-Ack */
+	unsigned short rx_code_rej	PACKED;	/* 0E: Code-Reject */
+	unsigned short rx_proto_rej	PACKED;	/* 10: Protocol-Reject */
+	unsigned short rx_echo_rqst	PACKED;	/* 12: Echo-Request */
+	unsigned short rx_echo_reply	PACKED;	/* 14: Echo-Reply */
+	unsigned short rx_disc_rqst	PACKED;	/* 16: Discard-Request */
+	unsigned short tx_conf_rqst	PACKED;	/* 18: Configure-Request */
+	unsigned short tx_conf_ack	PACKED;	/* 1A: Configure-Ack */
+	unsigned short tx_conf_nak	PACKED;	/* 1C: Configure-Nak */
+	unsigned short tx_conf_rej	PACKED;	/* 1E: Configure-Reject */
+	unsigned short tx_term_rqst	PACKED;	/* 20: Terminate-Request */
+	unsigned short tx_term_ack	PACKED;	/* 22: Terminate-Ack */
+	unsigned short tx_code_rej	PACKED;	/* 24: Code-Reject */
+	unsigned short tx_proto_rej	PACKED;	/* 26: Protocol-Reject */
+	unsigned short tx_echo_rqst	PACKED;	/* 28: Echo-Request */
+	unsigned short tx_echo_reply	PACKED;	/* 2A: Echo-Reply */
+	unsigned short tx_disc_rqst	PACKED;	/* 2E: Discard-Request */
+	unsigned short rx_too_large	PACKED;	/* 30: packets too large */
+	unsigned short rx_ack_inval	PACKED;	/* 32: invalid Conf-Ack */
+	unsigned short rx_rej_inval	PACKED;	/* 34: invalid Conf-Reject */
+	unsigned short rx_rej_badid	PACKED;	/* 36: Conf-Reject w/bad ID */
+} ppp_lcp_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Loopback Error Statistics (returned by the PPP_READ_LPBK_STATS command).
+ */
+typedef struct	ppp_lpbk_stats
+{
+	unsigned short conf_magic	PACKED;	/* 00:  */
+	unsigned short loc_echo_rqst	PACKED;	/* 02:  */
+	unsigned short rem_echo_rqst	PACKED;	/* 04:  */
+	unsigned short loc_echo_reply	PACKED;	/* 06:  */
+	unsigned short rem_echo_reply	PACKED;	/* 08:  */
+	unsigned short loc_disc_rqst	PACKED;	/* 0A:  */
+	unsigned short rem_disc_rqst	PACKED;	/* 0C:  */
+	unsigned short echo_tx_collsn	PACKED;	/* 0E:  */
+	unsigned short echo_rx_collsn	PACKED;	/* 10:  */
+} ppp_lpbk_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Protocol Statistics (returned by the PPP_READ_IPCP_STATS and
+ * PPP_READ_IPXCP_STATS commands).
+ */
+typedef struct	ppp_prot_stats
+{
+	unsigned short rx_unknown	PACKED;	/* 00: unknown type */
+	unsigned short rx_conf_rqst	PACKED;	/* 02: Configure-Request */
+	unsigned short rx_conf_ack	PACKED;	/* 04: Configure-Ack */
+	unsigned short rx_conf_nak	PACKED;	/* 06: Configure-Nak */
+	unsigned short rx_conf_rej	PACKED;	/* 08: Configure-Reject */
+	unsigned short rx_term_rqst	PACKED;	/* 0A: Terminate-Request */
+	unsigned short rx_term_ack	PACKED;	/* 0C: Terminate-Ack */
+	unsigned short rx_code_rej	PACKED;	/* 0E: Code-Reject */
+	unsigned short reserved		PACKED;	/* 10: */
+	unsigned short tx_conf_rqst	PACKED;	/* 12: Configure-Request */
+	unsigned short tx_conf_ack	PACKED;	/* 14: Configure-Ack */
+	unsigned short tx_conf_nak	PACKED;	/* 16: Configure-Nak */
+	unsigned short tx_conf_rej	PACKED;	/* 18: Configure-Reject */
+	unsigned short tx_term_rqst	PACKED;	/* 1A: Terminate-Request */
+	unsigned short tx_term_ack	PACKED;	/* 1C: Terminate-Ack */
+	unsigned short tx_code_rej	PACKED;	/* 1E: Code-Reject */
+	unsigned short rx_too_large	PACKED;	/* 20: packets too large */
+	unsigned short rx_ack_inval	PACKED;	/* 22: invalid Conf-Ack */
+	unsigned short rx_rej_inval	PACKED;	/* 24: invalid Conf-Reject */
+	unsigned short rx_rej_badid	PACKED;	/* 26: Conf-Reject w/bad ID */
+} ppp_prot_stats_t;
+
+/*----------------------------------------------------------------------------
+ * PAP Statistics (returned by the PPP_READ_PAP_STATS command).
+ */
+typedef struct	ppp_pap_stats
+{
+	unsigned short rx_unknown	PACKED;	/* 00: unknown type */
+	unsigned short rx_auth_rqst	PACKED;	/* 02: Authenticate-Request */
+	unsigned short rx_auth_ack	PACKED;	/* 04: Authenticate-Ack */
+	unsigned short rx_auth_nak	PACKED;	/* 06: Authenticate-Nak */
+	unsigned short reserved		PACKED;	/* 08: */
+	unsigned short tx_auth_rqst	PACKED;	/* 0A: Authenticate-Request */
+	unsigned short tx_auth_ack	PACKED;	/* 0C: Authenticate-Ack */
+	unsigned short tx_auth_nak	PACKED;	/* 0E: Authenticate-Nak */
+	unsigned short rx_too_large	PACKED;	/* 10: packets too large */
+	unsigned short rx_bad_peerid	PACKED;	/* 12: invalid peer ID */
+	unsigned short rx_bad_passwd	PACKED;	/* 14: invalid password */
+} ppp_pap_stats_t;
+
+/*----------------------------------------------------------------------------
+ * CHAP Statistics (returned by the PPP_READ_CHAP_STATS command).
+ */
+typedef struct	ppp_chap_stats
+{
+	unsigned short rx_unknown	PACKED;	/* 00: unknown type */
+	unsigned short rx_challenge	PACKED;	/* 02: Authenticate-Request */
+	unsigned short rx_response	PACKED;	/* 04: Authenticate-Ack */
+	unsigned short rx_success	PACKED;	/* 06: Authenticate-Nak */
+	unsigned short rx_failure	PACKED;	/* 08: Authenticate-Nak */
+	unsigned short reserved		PACKED;	/* 0A: */
+	unsigned short tx_challenge	PACKED;	/* 0C: Authenticate-Request */
+	unsigned short tx_response	PACKED;	/* 0E: Authenticate-Ack */
+	unsigned short tx_success	PACKED;	/* 10: Authenticate-Nak */
+	unsigned short tx_failure	PACKED;	/* 12: Authenticate-Nak */
+	unsigned short rx_too_large	PACKED;	/* 14: packets too large */
+	unsigned short rx_bad_peerid	PACKED;	/* 16: invalid peer ID */
+	unsigned short rx_bad_passwd	PACKED;	/* 18: invalid password */
+	unsigned short rx_bad_md5	PACKED;	/* 1A: invalid MD5 format */
+	unsigned short rx_bad_resp	PACKED;	/* 1C: invalid response */
+} ppp_chap_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Connection Information (returned by the PPP_GET_CONNECTION_INFO command).
+ */
+typedef struct	ppp_conn_info
+{
+	unsigned short remote_mru	PACKED;	/* 00:  */
+	unsigned char  ip_options	PACKED;	/* 02:  */
+	unsigned char  ip_local[4]	PACKED;	/* 03:  */
+	unsigned char  ip_remote[4]	PACKED;	/* 07:  */
+	unsigned char  ipx_options	PACKED;	/* 0B:  */
+	unsigned char  ipx_network[4]	PACKED;	/* 0C:  */
+	unsigned char  ipx_local[6]	PACKED;	/* 10:  */
+	unsigned char  ipx_remote[6]	PACKED;	/* 16:  */
+	unsigned char  ipx_router[48]	PACKED;	/* 1C:  */
+	unsigned char  auth_status	PACKED;	/* 4C:  */
+	unsigned char  peer_id[0]	PACKED;	/* 4D:  */
+} ppp_conn_info_t;
+
+#ifdef		_MSC_
+#  pragma	pack()
+#endif
+#endif	/* _SDLA_PPP_H */
diff -u --recursive --new-file v2.1.24/linux/include/linux/sdla_x25.h linux/include/linux/sdla_x25.h
--- v2.1.24/linux/include/linux/sdla_x25.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/sdla_x25.h	Sun Feb  2 15:18:47 1997
@@ -0,0 +1,624 @@
+/*****************************************************************************
+* sdla_x25.h	Sangoma X.25 firmware API definitions.
+*
+* Author:	Gene Kozin	<74604.152@compuserve.com>
+*
+* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Dec 13, 1996	Gene Kozin	Initial version
+*****************************************************************************/
+#ifndef	_SDLA_X25_H
+#define	_SDLA_X25_H
+
+/*----------------------------------------------------------------------------
+ * Notes:
+ * ------
+ * 1. All structures defined in this file are byte-alined.  To ensure
+ *    portability of this code between different platforms and compilers, one
+ *    of the following defines must be defined before including this file:
+ *
+ *	Compiler	Platform	Define		Use option
+ *	--------	--------	------		----------
+ *	GNU C		Linux		_GNUC_		-
+ *	Microsoft C	DOS/Windows	_MSC_		-
+ *
+ */
+
+#ifdef		_GNUC_
+#  ifndef	PACKED
+#    define	PACKED	__attribute__((packed))
+#  endif	/* PACKED */
+#else
+#  define	PACKED
+#endif
+#ifdef		_MSC_
+#  pragma	pack(1)
+#endif
+
+/******	CONSTANTS DEFINITIONS ***********************************************/
+
+#define	X25_MAX_CHAN	255	/* max number of open X.25 circuits */
+#define	X25_MAX_DATA	1024	/* max length of X.25 data buffer */
+
+/*
+ * X.25 shared memory layout.
+ */
+#define	X25_MBOX_OFFS	0x16B0	/* general mailbox block */
+#define	X25_RXMBOX_OFFS	0x1AD0	/* receive mailbox */
+#define	X25_STATUS_OFFS	0x1EF0	/* X.25 status structure */
+
+/****** DATA STRUCTURES *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * X.25 Command Block.
+ */
+typedef struct X25Cmd
+{
+	unsigned char command	PACKED;	/* command code */
+	unsigned short length	PACKED;	/* transfer data length */
+	unsigned char result	PACKED;	/* return code */
+	unsigned char pf	PACKED;	/* P/F bit */
+	unsigned short lcn	PACKED;	/* logical channel */
+	unsigned char qdm	PACKED;	/* Q/D/M bits */
+	unsigned char cause	PACKED;	/* cause field */
+	unsigned char diagn	PACKED;	/* diagnostics */
+	unsigned char pktType	PACKED;	/* packet type */
+	unsigned char resrv[4]	PACKED;	/* reserved */
+} TX25Cmd;
+
+/*
+ * Defines for the 'command' field.
+ */
+/*----- General commands --------------*/
+#define X25_SET_GLOBAL_VARS	0x0B   	/* set global variables */ 
+#define X25_READ_MODEM_STATUS	0x0C 	/* read modem status */
+#define X25_READ_CODE_VERSION	0x15	/* read firmware version number */
+#define X25_TRACE_CONFIGURE	0x14	/* configure trace facility */
+#define X25_READ_TRACE_DATA	0x16	/* read trace data */
+#define	X25_SET_INTERRUPT_MODE	0x17	/* set interrupt generation mode */
+#define	X25_READ_INTERRUPT_MODE	0x18	/* read interrupt generation mode */
+/*----- HDLC-level commands -----------*/
+#define X25_HDLC_LINK_CONFIGURE	0x01	/* configure HDLC link level */   
+#define X25_HDLC_LINK_OPEN	0x02	/* open HDLC link */         	
+#define X25_HDLC_LINK_CLOSE	0x03	/* close HDLC link */
+#define X25_HDLC_LINK_SETUP	0x04	/* set up HDLC link */ 
+#define X25_HDLC_LINK_DISC	0x05	/* disconnect DHLC link */
+#define X25_HDLC_LINK_STATUS	0x06	/* read DHLC link status */
+#define X25_HDLC_READ_STATS	0x07	/* read operational statistics */
+#define X25_HDLC_FLUSH_STATS	0x08 	/* flush operational statistics */
+#define X25_HDLC_READ_COMM_ERR	0x09 	/* read error statistics */
+#define X25_HDLC_FLUSH_COMM_ERR	0x0A	/* flush error statistics */
+#define X25_HDLC_FLUSH_BUFFERS	0x0D	/* flush HDLC-level data buffers */
+#define X25_HDLC_SPRVS_CNT_STAT 0x0F	/* read surervisory count status */
+#define X25_HDLC_SEND_UI_FRAME	0x10	/* send unnumbered information frame */
+#define X25_HDLC_WRITE		0x11	/* send HDLC information frame */
+#define X25_HDLC_READ		0x21	/* read HDLC information frame */
+#define X25_HDLC_READ_CONFIG	0x12	/* read HDLC configuration */
+#define X25_HDLC_SET_CONFIG	0x13	/* set HDLC configuration */
+/*----- X.25-level commands -----------*/
+#define X25_READ		0x22	/* read X.25 packet */
+#define X25_WRITE		0x23	/* send X.25 packet */
+#define X25_PLACE_CALL		0x30	/* place a call on SVC */
+#define X25_ACCEPT_CALL		0x31	/* accept incomming call */
+#define X25_CLEAR_CALL		0x32	/* clear call */
+#define X25_CLEAR_CONFRM	0x33	/* send clear confirmation packet */
+#define X25_RESET		0x34	/* send reset request packet */
+#define X25_RESET_CONFRM	0x35	/* send reset confirmation packet */
+#define X25_RESTART		0x36	/* send restart request packet */
+#define X25_RESTART_CONFRM	0x37	/* send restart confirmation packet */
+#define X25_INTERRUPT		0x38	/* send interrupt request packet */
+#define X25_INTERRUPT_CONFRM	0x39	/* send interrupt confirmation pkt */
+#define X25_REGISTRATION_RQST	0x3A	/* send registration request packet */
+#define X25_REGISTRATION_CONFRM	0x3B	/* send registration confirmation */
+#define X25_IS_DATA_AVAILABLE	0x40	/* querry receive queue */
+#define X25_INCOMMING_CALL_CTL	0x41	/* select incomming call options */
+#define X25_CONFIGURE_PVC	0x42	/* configure PVC */
+#define X25_GET_ACTIVE_CHANNELS	0x43	/* get a list of active circuits */
+#define X25_READ_CHANNEL_CONFIG	0x44	/* read virt. circuit configuration */
+#define X25_FLUSH_DATA_BUFFERS	0x45	/* flush X.25-level data buffers */
+#define X25_READ_HISTORY_TABLE	0x46	/* read asynchronous event log */
+#define X25_HISTORY_TABLE_CTL	0x47	/* control asynchronous event log */
+#define	X25_GET_TX_D_BIT_STATUS	0x48	/* is packet with D-bit acknowleged */
+#define	X25_READ_STATISTICS	0x49	/* read X.25-level statistics */
+#define	X25_FLUSH_STATISTICS	0x4A	/* flush X.25-level statistics */
+#define	X25_READ_CONFIGURATION	0x50	/* read HDLC & X.25 configuration */
+#define	X25_SET_CONFIGURATION	0x51	/* set HDLC & X.25 configuration */
+
+/*
+ * Defines for the 'result' field.
+ */
+/*----- General results ---------------*/
+#define X25RES_OK		0x00
+#define X25RES_ERROR		0x01
+#define X25RES_LINK_NOT_IN_ABM	0x02	/* link is not in ABM mode */
+#define X25RES_LINK_CLOSED	0x03
+#define X25RES_INVAL_LENGTH	0x04
+#define X25RES_INVAL_CMD	0x05
+#define X25RES_UNNUMBERED_FRAME	0x06	/* unnunbered frame received */
+#define X25RES_FRM_REJECT_MODE	0x07	/* link is in Frame Reject mode */
+#define X25RES_MODEM_FAILURE	0x08	/* DCD and/or CTS dropped */
+#define X25RES_N2_RETRY_LIMIT	0x09	/* N2 retry limit has been exceeded */
+#define X25RES_INVAL_LCN	0x30	/* invalid logical channel number */
+#define X25RES_INVAL_STATE	0x31	/* channel is not in data xfer mode */
+#define X25RES_INVAL_DATA_LEN	0x32	/* invalid data length */
+#define X25RES_NOT_READY	0x33	/* no data available / buffers full */
+#define X25RES_NETWORK_DOWN	0x34
+#define X25RES_CHANNEL_IN_USE	0x35	/* there is data queued on this LCN */
+#define X25RES_REGST_NOT_SUPPRT	0x36	/* registration not supported */
+#define X25RES_INVAL_FORMAT	0x37	/* invalid packet format */
+#define X25RES_D_BIT_NOT_SUPPRT	0x38	/* D-bit pragmatics not supported */
+#define X25RES_FACIL_NOT_SUPPRT	0x39	/* Call facility not supported */
+#define X25RES_INVAL_CALL_ARG	0x3A	/* errorneous call arguments */
+#define X25RES_INVAL_CALL_DATA	0x3B	/* errorneous call user data */
+#define X25RES_ASYNC_PACKET	0x40	/* asynchronous packet received */
+#define X25RES_PROTO_VIOLATION	0x41	/* protocol violation occured */
+#define X25RES_PKT_TIMEOUT	0x42	/* X.25 packet time out */
+#define X25RES_PKT_RETRY_LIMIT	0x43	/* X.25 packet retry limit exceeded */
+/*----- Command-dependant results -----*/
+#define X25RES_LINK_DISC	0x00	/* HDLC_LINK_STATUS */
+#define X25RES_LINK_IN_ABM	0x01	/* HDLC_LINK_STATUS */
+#define X25RES_NO_DATA		0x01	/* HDLC_READ/READ_TRACE_DATA*/
+#define X25RES_TRACE_INACTIVE	0x02	/* READ_TRACE_DATA */
+#define X25RES_LINK_IS_OPEN	0x01	/* HDLC_LINK_OPEN */
+#define X25RES_LINK_IS_DISC	0x02	/* HDLC_LINK_DISC */
+#define X25RES_LINK_IS_CLOSED	0x03	/* HDLC_LINK_CLOSE */
+#define X25RES_INVAL_PARAM	0x31	/* INCOMMING_CALL_CTL */
+#define X25RES_INVAL_CONFIG	0x35	/* REGISTR_RQST/CONFRM */
+
+/*
+ * Defines for the 'qdm_bits' field.
+ */
+#define X25CMD_Q_BIT_MASK	0x04
+#define X25CMD_D_BIT_MASK	0x02
+#define X25CMD_M_BIT_MASK	0x01
+
+/*
+ * Defines for the 'pkt_type' field.
+ */
+/*----- Asynchronous events ------*/
+#define ASE_CLEAR_RQST		0x02
+#define ASE_RESET_RQST		0x04
+#define ASE_RESTART_RQST	0x08
+#define ASE_INTERRUPT		0x10
+#define ASE_DTE_REGISTR_RQST	0x20
+#define ASE_CALL_RQST		0x30
+#define ASE_CALL_ACCEPTED	0x31
+#define ASE_CLEAR_CONFRM	0x32
+#define ASE_RESET_CONFRM	0x33
+#define ASE_RESTART_CONFRM	0x34
+#define ASE_INTERRUPT_CONFRM	0x35
+#define ASE_DCE_REGISTR_CONFRM	0x36
+#define ASE_DIAGNOSTIC		0x37
+#define ASE_CALL_AUTO_CLEAR	0x38
+#define AUTO_RESPONSE_FLAG	0x80
+/*----- Time-Out events ----------*/
+#define TOE_RESTART_RQST	0x03
+#define TOE_CALL_RQST		0x05
+#define TOE_CLEAR_RQST		0x08
+#define TOE_RESET_RQST		0x0A
+/*----- Protocol Violation events */
+#define PVE_CLEAR_RQST		0x32
+#define PVE_RESET_RQST		0x33
+#define PVE_RESTART_RQST	0x34
+#define PVE_DIAGNOSTIC		0x37
+
+/*----------------------------------------------------------------------------
+ * X.25 Mailbox.
+ *	This structure is located at offsets X25_MBOX_OFFS and X25_RXMBOX_OFFS
+ *	into shared memory window.
+ */
+typedef struct X25Mbox
+{
+	unsigned char opflag	PACKED;	/* 00h: execution flag */
+	TX25Cmd cmd		PACKED;	/* 01h: command block */
+	unsigned char data[1]	PACKED;	/* 10h: data buffer */
+} TX25Mbox;
+
+/*----------------------------------------------------------------------------
+ * X.25 Time Stamp Structure.
+ */
+typedef struct X25TimeStamp
+{
+	unsigned char month	PACKED;
+	unsigned char date	PACKED;
+	unsigned char sec	PACKED;
+	unsigned char min	PACKED;
+	unsigned char hour	PACKED;
+} TX25TimeStamp;
+
+/*----------------------------------------------------------------------------
+ * X.25 Status Block.
+ *	This structure is located at offset X25_STATUS_OFF into shared memory
+ *	window.
+ */
+typedef struct X25Status
+{
+	unsigned short pvc_map	PACKED;	/* 00h: PVC map */
+	unsigned short icc_map	PACKED;	/* 02h: Incomming Chan. map */
+	unsigned short twc_map	PACKED;	/* 04h: Two-way Cnan. map */
+	unsigned short ogc_map	PACKED;	/* 06h: Outgoing Chan. map */
+	TX25TimeStamp tstamp	PACKED;	/* 08h: timestamp (BCD) */
+	unsigned char iflags	PACKED;	/* 0Dh: interrupt flags */
+	unsigned char resrv[2]	PACKED;	/* 0Eh: */
+	unsigned char gflags	PACKED;	/* 10h: misc. HDLC/X25 flags */
+	unsigned char cflags[X25_MAX_CHAN] PACKED; /* channel status bytes */
+} TX25Status;
+
+/*
+ * Bitmasks for the 'iflags' field.
+ */
+#define X25_RX_INTR	0x01	/* receive interrupt */
+#define X25_TX_INTR	0x02	/* transmit interrupt */
+#define X25_MODEM_INTR	0x04	/* modem status interrupt (CTS/DCD) */
+#define X25_EVENT_INTR	0x10	/* asyncronous event encountered */
+#define X25_CMD_INTR	0x08	/* interface command complete */
+
+/*
+ * Bitmasks for the 'gflags' field.
+ */
+#define X25_HDLC_ABM	0x01	/* HDLC is in ABM mode */
+#define X25_RX_READY	0x02	/* X.25 data available */
+#define X25_TRACE_READY	0x08	/* trace data available */
+#define X25_EVENT_IND	0x20	/* asynchronous event indicator */
+#define X25_TX_READY	0x40	/* space is available in Tx buf.*/
+
+/*
+ * Bitmasks for the 'cflags' field.
+ */
+#define X25_XFER_MODE	0x80	/* channel is in data transfer mode */
+#define X25_TXWIN_OPEN	0x40	/* transmit window open */
+#define X25_RXBUF_MASK	0x3F	/* number of data buffers available */
+
+/*****************************************************************************
+ * Following definitions structurize contents of the TX25Mbox.data field for
+ * different X.25 interface commands.
+ ****************************************************************************/
+
+/* ---------------------------------------------------------------------------
+ * X25_SET_GLOBAL_VARS Command.
+ */
+typedef struct X25GlobalVars
+{
+	unsigned char resrv	PACKED;	/* 00h: reserved */
+	unsigned char dtrCtl	PACKED;	/* 01h: DTR control code */
+	unsigned char resErr	PACKED;	/* 01h: '1' - reset modem error */
+} TX25GlobalVars;
+
+/*
+ * Defines for the 'dtrCtl' field.
+ */
+#define X25_RAISE_DTR	0x01
+#define X25_DROP_DTR	0x02
+
+/* ---------------------------------------------------------------------------
+ * X25_READ_MODEM_STATUS Command.
+ */
+typedef struct X25ModemStatus
+{
+	unsigned char	status	PACKED;		/* 00h: modem status */
+} TX25ModemStatus;
+
+/*
+ * Defines for the 'status' field.
+ */
+#define X25_CTS_MASK	0x20
+#define X25_DCD_MASK	0x08
+
+/* ---------------------------------------------------------------------------
+ * X25_HDLC_LINK_STATUS Command.
+ */
+typedef struct X25LinkStatus
+{
+	unsigned char txQueued	PACKED;	/* 00h: queued Tx I-frames*/
+	unsigned char rxQueued	PACKED;	/* 01h: queued Rx I-frames*/
+	unsigned char station	PACKED;	/* 02h: DTE/DCE config. */
+	unsigned char reserved	PACKED;	/* 03h: reserved */
+	unsigned char sfTally	PACKED;	/* 04h: supervisory frame tally */
+} TX25LinkStatus;
+
+/*
+ * Defines for the 'station' field.
+ */
+#define	X25_STATION_DTE	0x01	/* station configured as DTE */
+#define X25_STATION_DCE	0x02	/* station configured as DCE */
+
+/* ---------------------------------------------------------------------------
+ * X25_HDLC_READ_STATS Command.
+ */
+typedef struct HdlcStats
+{						/*	a number of ... */
+	unsigned short rxIFrames	PACKED;	/* 00h: ready Rx I-frames */
+	unsigned short rxNoseq		PACKED;	/* 02h: frms out-of-sequence */
+	unsigned short rxNodata		PACKED;	/* 04h: I-frms without data */
+	unsigned short rxDiscarded	PACKED;	/* 06h: discarded frames */
+	unsigned short rxTooLong	PACKED;	/* 08h: frames too long */
+	unsigned short rxBadAddr	PACKED;	/* 0Ah: frms with inval.addr*/
+	unsigned short txAcked		PACKED;	/* 0Ch: acknowledged I-frms */
+	unsigned short txRetransm	PACKED;	/* 0Eh: re-transmit. I-frms */
+	unsigned short t1Timeout	PACKED;	/* 10h: T1 timeouts */
+	unsigned short rxSABM		PACKED;	/* 12h: received SABM frames */
+	unsigned short rxDISC		PACKED;	/* 14h: received DISC frames */
+	unsigned short rxDM		PACKED;	/* 16h: received DM frames */
+	unsigned short rxFRMR		PACKED;	/* 18h: FRMR frames received */
+	unsigned short txSABM		PACKED;	/* 1Ah: transm. SABM frames*/
+	unsigned short txDISC		PACKED;	/* 1Ch: transm. DISC frames*/
+	unsigned short txDM		PACKED;	/* 1Eh: transm. DM frames */
+	unsigned short txFRMR		PACKED;	/* 20h: transm. FRMR frames*/
+} THdlcStats;
+
+/* ---------------------------------------------------------------------------
+ * X25_HDLC_READ_COMM_ERR Command.
+ */
+typedef struct HdlcCommErr
+{						/*	a number of ... */
+	unsigned char rxOverrun		PACKED;	/* 00h: Rx overrun errors */
+	unsigned char rxBadCrc		PACKED;	/* 01h: Rx CRC errors */
+	unsigned char rxAborted		PACKED;	/* 02h: Rx aborted frames */
+	unsigned char rxDropped		PACKED;	/* 03h: frames lost */
+	unsigned char txAborted		PACKED;	/* 04h: Tx aborted frames */
+	unsigned char txUnderrun	PACKED;	/* 05h: Tx underrun errors */
+	unsigned char txMissIntr	PACKED;	/* 06h: missed underrun ints */
+	unsigned char reserved		PACKED;	/* 07h: reserved */
+	unsigned char droppedDCD	PACKED;	/* 08h: times DCD dropped */
+	unsigned char droppedCTS	PACKED;	/* 09h: times CTS dropped */
+} THdlcCommErr;
+
+/* ---------------------------------------------------------------------------
+ * X25_SET_CONFIGURATION & X25_READ_CONFIGURATION Commands.
+ */
+typedef struct X25Config
+{
+	unsigned char baudRate		PACKED;	/* 00h:  */
+	unsigned char t1		PACKED;	/* 01h:  */
+	unsigned char t2		PACKED;	/* 02h:  */
+	unsigned char n2		PACKED;	/* 03h:  */
+	unsigned short hdlcMTU		PACKED;	/* 04h:  */
+	unsigned char hdlcWindow	PACKED;	/* 06h:  */
+	unsigned char t4		PACKED;	/* 07h:  */
+	unsigned char autoModem		PACKED;	/* 08h:  */
+	unsigned char autoHdlc		PACKED;	/* 09h:  */
+	unsigned char hdlcOptions	PACKED;	/* 0Ah:  */
+	unsigned char station		PACKED;	/* 0Bh:  */
+	unsigned char pktWindow		PACKED;	/* 0Ch:  */
+	unsigned short defPktSize	PACKED;	/* 0Dh:  */
+	unsigned short pktMTU		PACKED;	/* 0Fh:  */
+	unsigned short loPVC		PACKED;	/* 11h:  */
+	unsigned short hiPVC		PACKED;	/* 13h:  */
+	unsigned short loIncommingSVC	PACKED;	/* 15h:  */
+	unsigned short hiIncommingSVC	PACKED;	/* 17h:  */
+	unsigned short loTwoWaySVC	PACKED;	/* 19h:  */
+	unsigned short hiTwoWaySVC	PACKED;	/* 1Bh:  */
+	unsigned short loOutgoingSVC	PACKED;	/* 1Dh:  */
+	unsigned short hiOutgoingSVC	PACKED;	/* 1Fh:  */
+	unsigned short options		PACKED;	/* 21h:  */
+	unsigned char responseOpt	PACKED;	/* 23h:  */
+	unsigned short facil1		PACKED;	/* 24h:  */
+	unsigned short facil2		PACKED;	/* 26h:  */
+	unsigned short ccittFacil	PACKED;	/* 28h:  */
+	unsigned short otherFacil	PACKED;	/* 2Ah:  */
+	unsigned short ccittCompat	PACKED;	/* 2Ch:  */
+	unsigned char t10t20		PACKED;	/* 2Eh:  */
+	unsigned char t11t21		PACKED;	/* 2Fh:  */
+	unsigned char t12t22		PACKED;	/* 30h:  */
+	unsigned char t13t23		PACKED;	/* 31h:  */
+	unsigned char t16t26		PACKED;	/* 32H:  */
+	unsigned char t28		PACKED;	/* 33h:  */
+	unsigned char r10r20		PACKED;	/* 34h:  */
+	unsigned char r12r22		PACKED;	/* 35h:  */
+	unsigned char r13r23		PACKED;	/* 36h:  */
+} TX25Config;
+
+/* ---------------------------------------------------------------------------
+ * X25_READ_CHANNEL_CONFIG Command.
+ */
+typedef struct X25ChanAlloc			/*----- Channel allocation -*/
+{
+	unsigned short loPVC		PACKED;	/* 00h: lowest PVC number */
+	unsigned short hiPVC		PACKED;	/* 02h: highest PVC number */
+	unsigned short loIncommingSVC	PACKED;	/* 04h: lowest incoming SVC */
+	unsigned short hiIncommingSVC	PACKED;	/* 06h: highest incoming SVC */
+	unsigned short loTwoWaySVC	PACKED;	/* 08h: lowest two-way SVC */
+	unsigned short hiTwoWaySVC	PACKED;	/* 0Ah: highest two-way SVC */
+	unsigned short loOutgoingSVC	PACKED;	/* 0Ch: lowest outgoing SVC */
+	unsigned short hiOutgoingSVC	PACKED;	/* 0Eh: highest outgoing SVC */
+} TX25ChanAlloc;
+
+typedef struct X25ChanCfg		/*------ Channel configuration -----*/
+{
+	unsigned char type	PACKED;	/* 00h: channel type */
+	unsigned char txConf	PACKED;	/* 01h: Tx packet and window sizes */
+	unsigned char rxConf	PACKED;	/* 01h: Rx packet and window sizes */
+} TX25ChanCfg;
+
+/*
+ * Defines for the 'type' field.
+ */
+#define	X25_PVC  	0x01	/* PVC */
+#define	X25_SVC_IN	0x03	/* Incoming SVC */
+#define	X25_SVC_TWOWAY	0x07	/* Two-way SVC */
+#define	X25_SVC_OUT	0x0B	/* Outgoing SVC */
+
+/*----------------------------------------------------------------------------
+ * X25_READ_STATISTICS Command.
+ */
+typedef struct X25Stats
+{						/* number of packets Tx/Rx'ed */
+	unsigned short txRestartRqst	PACKED;	/* 00h: Restart Request */
+	unsigned short rxRestartRqst	PACKED;	/* 02h: Restart Request */
+	unsigned short txRestartConf	PACKED;	/* 04h: Restart Confirmation */
+	unsigned short rxRestartConf	PACKED;	/* 06h: Restart Confirmation */
+	unsigned short txResetRqst	PACKED;	/* 08h: Reset Request */
+	unsigned short rxResetRqst	PACKED;	/* 0Ah: Reset Request */
+	unsigned short txResetConf	PACKED;	/* 0Ch: Reset Confirmation */
+	unsigned short rxResetConf	PACKED;	/* 0Eh: Reset Confirmation */
+	unsigned short txCallRequest	PACKED;	/* 10h: Call Request */
+	unsigned short rxCallRequest	PACKED;	/* 12h: Call Request */
+	unsigned short txCallAccept	PACKED;	/* 14h: Call Accept */
+	unsigned short rxCallAccept	PACKED;	/* 16h: Call Accept */
+	unsigned short txClearRqst	PACKED;	/* 18h: Clear Request */
+	unsigned short rxClearRqst	PACKED;	/* 1Ah: Clear Request */
+	unsigned short txClearConf	PACKED;	/* 1Ch: Clear Confirmation */
+	unsigned short rxClearConf	PACKED;	/* 1Eh: Clear Confirmation */
+	unsigned short txDiagnostic	PACKED;	/* 20h: Diagnostic */
+	unsigned short rxDiagnostic	PACKED;	/* 22h: Diagnostic */
+	unsigned short txRegRqst	PACKED;	/* 24h: Registration Request */
+	unsigned short rxRegRqst	PACKED;	/* 26h: Registration Request */
+	unsigned short txRegConf	PACKED;	/* 28h: Registration Confirm.*/
+	unsigned short rxRegConf	PACKED;	/* 2Ah: Registration Confirm.*/
+	unsigned short txInterrupt	PACKED;	/* 2Ch: Interrupt */
+	unsigned short rxInterrupt	PACKED;	/* 2Eh: Interrupt */
+	unsigned short txIntrConf	PACKED;	/* 30h: Interrupt Confirm. */
+	unsigned short rxIntrConf	PACKED;	/* 32h: Interrupt Confirm. */
+	unsigned short txData		PACKED;	/* 34h: Data */
+	unsigned short rxData		PACKED;	/* 36h: Data */
+	unsigned short txRR		PACKED;	/* 38h: RR */
+	unsigned short rxRR		PACKED;	/* 3Ah: RR */
+	unsigned short txRNR		PACKED;	/* 3Ch: RNR */
+	unsigned short rxRNR		PACKED;	/* 3Eh: RNR */
+} X25Stats;
+
+/*----------------------------------------------------------------------------
+ * X25_READ_HISTORY_TABLE Command.
+ */
+typedef struct X25EventLog
+{
+	unsigned char	type	PACKED;	/* 00h: transaction type */
+	unsigned short	lcn	PACKED;	/* 01h: logical channel num */
+	unsigned char	packet	PACKED;	/* 03h: async packet type */
+	unsigned char	cause	PACKED;	/* 04h: X.25 cause field */
+	unsigned char	diag	PACKED;	/* 05h: X.25 diag field */
+	TX25TimeStamp	ts	PACKED;	/* 06h: time stamp */
+} TX25EventLog;
+
+/*
+ * Defines for the 'type' field.
+ */
+#define X25LOG_INCOMMING	0x00
+#define X25LOG_APPLICATION 	0x01
+#define X25LOG_AUTOMATIC	0x02
+#define X25LOG_ERROR		0x04
+#define X25LOG_TIMEOUT		0x08
+#define X25LOG_RECOVERY		0x10
+
+/*
+ * Defines for the 'packet' field.
+ */
+#define X25LOG_CALL_RQST	0x0B
+#define X25LOG_CALL_ACCEPTED	0x0F
+#define X25LOG_CLEAR_RQST	0x13
+#define X25LOG_CLEAR_CONFRM	0x17
+#define X25LOG_RESET_RQST	0x1B
+#define X25LOG_RESET_CONFRM	0x1F
+#define X25LOG_RESTART_RQST	0xFB
+#define X25LOG_RESTART_COMFRM	0xFF
+#define X25LOG_DIAGNOSTIC	0xF1
+#define X25LOG_DTE_REG_RQST	0xF3
+#define X25LOG_DTE_REG_COMFRM	0xF7
+
+/* ---------------------------------------------------------------------------
+ * X25_TRACE_CONFIGURE Command.
+ */
+typedef struct X25TraceCfg
+{
+	unsigned char flags	PACKED;	/* 00h: trace configuration flags */
+	unsigned char timeout	PACKED;	/* 01h: timeout for trace delay mode*/
+} TX25TraceCfg;
+
+/*
+ * Defines for the 'flags' field.
+ */
+#define X25_TRC_ENABLE		0x01	/* bit0: '1' - trace enabled */
+#define X25_TRC_TIMESTAMP	0x02	/* bit1: '1' - time stamping enabled*/
+#define X25_TRC_DELAY		0x04	/* bit2: '1' - trace delay enabled */
+#define X25_TRC_DATA		0x08	/* bit3: '1' - trace data packets */
+#define X25_TRC_SUPERVISORY	0x10    /* bit4: '1' - trace suprvisory pkts*/
+#define X25_TRC_ASYNCHRONOUS	0x20	/* bit5: '1' - trace asynch. packets*/
+#define X25_TRC_HDLC		0x40	/* bit6: '1' - trace all packets */
+#define X25_TRC_READ		0x80	/* bit7: '1' - get current config. */
+
+/* ---------------------------------------------------------------------------
+ * X25_READ_TRACE_DATA Command.
+ */
+typedef struct X25Trace			/*----- Trace data structure -------*/
+{
+	unsigned short length	PACKED;	/* 00h: trace data length */
+	unsigned char type	PACKED;	/* 02h: trace type */
+	unsigned char lost_cnt	PACKED;	/* 03h: N of traces lost */
+	TX25TimeStamp tstamp	PACKED;	/* 04h: mon/date/sec/min/hour */
+	unsigned short millisec	PACKED;	/* 09h: ms time stamp */
+	unsigned char data[0]	PACKED;	/* 0Bh: traced frame */
+} TX25Trace;
+
+/*
+ * Defines for the 'type' field.
+ */
+#define X25_TRC_TYPE_MASK	0x0F	/* bits 0..3: trace type */
+#define X25_TRC_TYPE_RX_FRAME	0x00	/* received frame trace */
+#define X25_TRC_TYPE_TX_FRAME	0x01	/* transmitted frame */
+#define X25_TRC_TYPE_ERR_FRAME	0x02	/* error frame */
+
+#define X25_TRC_ERROR_MASK	0xF0	/* bits 4..7: error code */
+#define X25_TRCERR_RX_ABORT	0x10	/* receive abort error */
+#define X25_TRCERR_RX_BADCRC	0x20	/* receive CRC error */
+#define X25_TRCERR_RX_OVERRUN	0x30	/* receiver overrun error */
+#define X25_TRCERR_RX_TOO_LONG	0x40	/* excessive frame length error */
+#define X25_TRCERR_TX_ABORT	0x70	/* aborted frame transmittion error */
+#define X25_TRCERR_TX_UNDERRUN	0x80	/* transmit underrun error */
+
+/*****************************************************************************
+ * Following definitions describe HDLC frame and X.25 packet formats.
+ ****************************************************************************/
+
+typedef struct HDLCFrame		/*----- DHLC Frame Format ----------*/
+{
+	unsigned char addr	PACKED;	/* address field */
+	unsigned char cntl	PACKED;	/* control field */
+	unsigned char data[0]	PACKED;
+} THDLCFrame;
+
+typedef struct X25Pkt			/*----- X.25 Paket Format ----------*/
+{
+	unsigned char lcn_hi	PACKED;	/* 4 MSB of Logical Channel Number */
+	unsigned char lcn_lo	PACKED;	/* 8 LSB of Logical Channel Number */
+	unsigned char type	PACKED;
+	unsigned char data[0]	PACKED;
+} TX25Pkt;
+
+/*
+ * Defines for the 'lcn_hi' field.
+ */
+#define	X25_Q_BIT_MASK		0x80	/* Data Qualifier Bit mask */
+#define	X25_D_BIT_MASK		0x40	/* Delivery Confirmation Bit mask */
+#define	X25_M_BITS_MASK		0x30	/* Modulo Bits mask */
+#define	X25_LCN_MSB_MASK	0x0F	/* LCN most significant bits mask */
+
+/*
+ * Defines for the 'type' field.
+ */
+#define	X25PKT_DATA		0x01	/* Data packet mask */
+#define	X25PKT_SUPERVISORY	0x02	/* Supervisory packet mask */
+#define	X25PKT_CALL_RQST	0x0B	/* Call Request/Incoming */
+#define	X25PKT_CALL_ACCEPTED	0x0F	/* Call Accepted/Connected */
+#define	X25PKT_CLEAR_RQST	0x13	/* Clear Request/Indication */
+#define	X25PKT_CLEAR_CONFRM	0x17	/* Clear Confirmation */
+#define	X25PKT_RESET_RQST	0x1B	/* Reset Request/Indication */
+#define	X25PKT_RESET_CONFRM	0x1F	/* Reset Confirmation */
+#define	X25PKT_RESTART_RQST	0xFB	/* Restart Request/Indication */
+#define	X25PKT_RESTART_CONFRM	0xFF	/* Restart Confirmation */
+#define	X25PKT_INTERRUPT	0x23	/* Interrupt */
+#define	X25PKT_INTERRUPT_CONFRM	0x27	/* Interrupt Confirmation */
+#define	X25PKT_DIAGNOSTIC	0xF1	/* Diagnostic */
+#define	X25PKT_REGISTR_RQST	0xF3	/* Registration Request */
+#define	X25PKT_REGISTR_CONFRM	0xF7	/* Registration Confirmation */
+#define	X25PKT_RR_MASKED	0x01	/* Receive Ready packet after masking */
+#define	X25PKT_RNR_MASKED	0x05	/* Receive Not Ready after masking  */
+
+#ifdef		_MSC_
+#  pragma	pack()
+#endif
+#endif	/* _SDLA_X25_H */
diff -u --recursive --new-file v2.1.24/linux/include/linux/sdladrv.h linux/include/linux/sdladrv.h
--- v2.1.24/linux/include/linux/sdladrv.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/sdladrv.h	Sun Feb  2 15:18:47 1997
@@ -0,0 +1,61 @@
+/*****************************************************************************
+* sdladrv.h	SDLA Support Module.  Kernel API Definitions.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*
+* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Dec 11, 1996	Gene Kozin	Complete overhaul.
+* Oct 17, 1996	Gene Kozin	Minor bug fixes.
+* Jun 12, 1996	Gene Kozin 	Added support for S503 card.
+* Dec 06, 1995	Gene Kozin	Initial version.
+*****************************************************************************/
+#ifndef	_SDLADRV_H
+#define	_SDLADRV_H
+
+#define	SDLA_MAXIORANGE	4	/* maximum I/O port range */
+#define	SDLA_WINDOWSIZE	0x2000	/* default dual-port memory window size */
+
+/****** Data Structures *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * Adapter hardware configuration. Pointer to this structure is passed to all
+ * APIs.
+ */
+typedef struct sdlahw
+{
+	unsigned type;			/* adapter type */
+	unsigned fwid;			/* firmware ID */
+	unsigned port;			/* adapter I/O port base */
+	int irq;			/* interrupt request level */
+	unsigned long dpmbase;		/* dual-port memory base */
+	unsigned dpmsize;		/* dual-port memory size */
+	unsigned pclk;			/* CPU clock rate, kHz */
+	unsigned long memory;		/* memory size */
+	unsigned long vector;		/* local offset of the DPM window */
+	unsigned io_range;		/* I/O port range */
+	unsigned char regs[SDLA_MAXIORANGE]; /* was written to registers */
+	unsigned reserved[5];
+} sdlahw_t;
+
+/****** Function Prototypes *************************************************/
+
+extern int sdla_setup	(sdlahw_t* hw, void* sfm, unsigned len);
+extern int sdla_down	(sdlahw_t* hw);
+extern int sdla_inten	(sdlahw_t* hw);
+extern int sdla_intde	(sdlahw_t* hw);
+extern int sdla_intack	(sdlahw_t* hw);
+extern int sdla_intr	(sdlahw_t* hw);
+extern int sdla_mapmem	(sdlahw_t* hw, unsigned long addr);
+extern int sdla_peek	(sdlahw_t* hw, unsigned long addr, void* buf,
+			 unsigned len);
+extern int sdla_poke	(sdlahw_t* hw, unsigned long addr, void* buf,
+			 unsigned len);
+extern int sdla_exec	(void* opflag);
+
+#endif	/* _SDLADRV_H */
diff -u --recursive --new-file v2.1.24/linux/include/linux/sdlasfm.h linux/include/linux/sdlasfm.h
--- v2.1.24/linux/include/linux/sdlasfm.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/sdlasfm.h	Sun Feb  2 15:18:47 1997
@@ -0,0 +1,92 @@
+/*****************************************************************************
+* sdlasfm.h	WANPIPE(tm) Multiprotocol WAN Link Driver.
+*		Definitions for the SDLA Firmware Module (SFM).
+*
+* Author:	Gene Kozin	<74604.152@compuserve.com>
+*
+* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Dec 11, 1996	Gene Kozin	Cosmetic changes
+* Apr 16, 1996	Gene Kozin	Changed adapter & firmware IDs. Version 2
+* Dec 15, 1995	Gene Kozin	Structures chaned
+* Nov 09, 1995	Gene Kozin	Initial version.
+*****************************************************************************/
+#ifndef	_SDLASFM_H
+#define	_SDLASFM_H
+
+/****** Defines *************************************************************/
+
+#define	SFM_VERSION	2
+#define	SFM_SIGNATURE	"SFM - Sangoma SDLA Firmware Module"
+
+/* min/max */
+#define	SFM_IMAGE_SIZE	0x8000	/* max size of SDLA code image file */
+#define	SFM_DESCR_LEN	256	/* max length of description string */
+#define	SFM_MAX_SDLA	16	/* max number of compatible adapters */
+
+/* Adapter types */
+#define SDLA_S502A	5020
+#define SDLA_S502E	5021
+#define SDLA_S503	5030
+#define SDLA_S508	5080
+#define SDLA_S507	5070
+#define SDLA_S509	5090
+
+/* Firmware identification numbers:
+ *    0  ..  999	Test & Diagnostics
+ *  1000 .. 1999	Streaming HDLC
+ *  2000 .. 2999	Bisync
+ *  3000 .. 3999	SDLC
+ *  4000 .. 4999	HDLC
+ *  5000 .. 5999	X.25
+ *  6000 .. 6999	Frame Relay
+ *  7000 .. 7999	PPP
+ */
+#define	SFID_CALIB502	 200
+#define	SFID_STRM502	1200
+#define	SFID_STRM508	1800
+#define	SFID_BSC502	2200
+#define	SFID_SDLC502	3200
+#define	SFID_HDLC502	4200
+#define	SFID_X25_502	5200
+#define	SFID_X25_508	5800
+#define	SFID_FR502	6200
+#define	SFID_FR508	6800
+#define	SFID_PPP502	7200
+#define	SFID_PPP508	7800
+
+/****** Data Types **********************************************************/
+
+typedef struct	sfm_info		/* firmware module information */
+{
+	unsigned short	codeid;		/* firmware ID */
+	unsigned short	version;	/* firmaware version number */
+	unsigned short	adapter[SFM_MAX_SDLA]; /* compatible adapter types */
+	unsigned long	memsize;	/* minimum memory size */
+	unsigned short	reserved[2];	/* reserved */
+	unsigned short	startoffs;	/* entry point offset */
+	unsigned short	winoffs;	/* dual-port memory window offset */
+	unsigned short	codeoffs;	/* code load offset */
+	unsigned short	codesize;	/* code size */
+	unsigned short	dataoffs;	/* configuration data load offset */
+	unsigned short	datasize;	/* configuration data size */
+} sfm_info_t;
+
+typedef struct sfm			/* SDLA firmware file structire */
+{
+	char		signature[80];	/* SFM file signature */
+	unsigned short	version;	/* file format version */
+	unsigned short	checksum;	/* info + image */
+	unsigned short	reserved[6];	/* reserved */
+	char		descr[SFM_DESCR_LEN]; /* description string */
+	sfm_info_t	info;		/* firmware module info */
+	unsigned char	image[1];	/* code image (variable size) */
+} sfm_t;
+
+#endif	/* _SDLASFM_H */
+
diff -u --recursive --new-file v2.1.24/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.1.24/linux/include/linux/socket.h	Thu Jan 23 21:06:52 1997
+++ linux/include/linux/socket.h	Sun Feb  2 15:18:47 1997
@@ -74,7 +74,22 @@
 				 (struct cmsghdr *)(msg)->msg_control : \
 				 (struct cmsghdr *)NULL)
 
-extern __inline__ struct cmsghdr * cmsg_nxthdr(struct msghdr *mhdr,
+/*
+ *	This mess will go away with glibc
+ */
+ 
+#ifdef __KERNEL__
+#define KINLINE extern __inline__
+#else
+#define KINLINE static
+#endif
+
+
+/*
+ *	Get the next cmsg header
+ */
+ 
+KINLINE struct cmsghdr * cmsg_nxthdr(struct msghdr *mhdr,
 					       struct cmsghdr *cmsg)
 {
 	unsigned char * ptr;
diff -u --recursive --new-file v2.1.24/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.1.24/linux/include/linux/sysctl.h	Thu Jan 23 21:06:52 1997
+++ linux/include/linux/sysctl.h	Sun Feb  2 15:18:47 1997
@@ -138,7 +138,6 @@
 	NET_NETROM_TRANSPORT_BUSY_DELAY,
 	NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE,
 	NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT,
-	NET_NETROM_TRANSPORT_PACKET_LENGTH,
 	NET_NETROM_ROUTING_CONTROL,
 	NET_NETROM_LINK_FAILS_COUNT
 };
@@ -154,7 +153,8 @@
 	NET_ROSE_CLEAR_REQUEST_TIMEOUT,
 	NET_ROSE_NO_ACTIVITY_TIMEOUT,
 	NET_ROSE_ACK_HOLD_BACK_TIMEOUT,
-	NET_ROSE_ROUTING_CONTROL
+	NET_ROSE_ROUTING_CONTROL,
+	NET_ROSE_LINK_FAIL_TIMEOUT
 };
 
 /* /proc/sys/net/x25 */
diff -u --recursive --new-file v2.1.24/linux/include/linux/tty_ldisc.h linux/include/linux/tty_ldisc.h
--- v2.1.24/linux/include/linux/tty_ldisc.h	Tue Jan 28 18:50:56 1997
+++ linux/include/linux/tty_ldisc.h	Sun Feb  2 16:39:28 1997
@@ -64,13 +64,12 @@
  * 	This function notifies the line discpline that a change has
  * 	been made to the termios stucture.
  * 
- * int	(*select)(struct tty_struct * tty, struct inode * inode,
- * 		  struct file * file, int sel_type,
- * 		  struct select_table_struct *wait);
+ * int	(*poll)(struct tty_struct * tty, struct file * file,
+ * 		  poll_table *wait);
  *
- * 	This function is called when a user attempts to select on a
+ * 	This function is called when a user attempts to select/poll on a
  * 	tty device.  It is solely the responsibility of the line
- * 	discipline to handle select requests.
+ * 	discipline to handle poll requests.
  *
  * void	(*receive_buf)(struct tty_struct *, const unsigned char *cp,
  * 		       char *fp, int count);
diff -u --recursive --new-file v2.1.24/linux/include/linux/wanpipe.h linux/include/linux/wanpipe.h
--- v2.1.24/linux/include/linux/wanpipe.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/wanpipe.h	Sun Feb  2 15:18:47 1997
@@ -0,0 +1,131 @@
+/*****************************************************************************
+* wanpipe.h	WANPIPE(tm) Multiprotocol WAN Link Driver.
+*		User-level API definitions.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Jan 02, 1997	Gene Kozin	Version 3.0.0
+*****************************************************************************/
+#ifndef	_WANPIPE_H
+#define	_WANPIPE_H
+
+#include <linux/wanrouter.h>
+
+/* Defines */
+#define	WANPIPE_MAGIC	0x414C4453L	/* signatire: 'SDLA' reversed */
+
+/* IOCTL numbers (up to 16) */
+#define	WANPIPE_DUMP	(ROUTER_USER+0)	/* dump adapter's memory */
+#define	WANPIPE_EXEC	(ROUTER_USER+1)	/* execute firmware command */
+
+/*
+ * Data structures for IOCTL calls.
+ */
+
+typedef struct sdla_dump	/* WANPIPE_DUMP */
+{
+	unsigned long magic;	/* for verification */
+	unsigned long offset;	/* absolute adapter memory address */
+	unsigned long length;	/* block length */
+	void* ptr;		/* -> buffer */
+} sdla_dump_t;
+
+typedef struct sdla_exec	/* WANPIPE_EXEC */
+{
+	unsigned long magic;	/* for verification */
+	void* cmd;		/* -> command structure */
+	void* data;		/* -> data buffer */
+} sdla_exec_t;
+
+#ifdef	__KERNEL__
+/****** Kernel Interface ****************************************************/
+
+#include <linux/sdladrv.h>	/* SDLA support module API definitions */
+#include <linux/sdlasfm.h>	/* SDLA firmware module definitions */
+
+#ifndef	min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef	max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#define	is_digit(ch) (((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')?1:0)
+#define	is_alpha(ch) ((((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'z')||\
+	 	  ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'Z'))?1:0)
+#define	is_hex_digit(ch) ((((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')||\
+	 	  ((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'f')||\
+	 	  ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'F'))?1:0)
+
+/****** Data Structures *****************************************************/
+
+/* Adapter Data Space.
+ * This structure is needed because we handle multiple cards, otherwise
+ * static data would do it.
+ */
+typedef struct sdla
+{
+	char devname[WAN_DRVNAME_SZ+1];	/* card name */
+	sdlahw_t hw;			/* hardware configuration */
+	wan_device_t wandev;		/* WAN device data space */
+	unsigned open_cnt;		/* number of open interfaces */
+	unsigned long state_tick;	/* link state timestamp */
+	char in_isr;			/* interrupt-in-service flag */
+	void* mbox;			/* -> mailbox */
+	void* rxmb;			/* -> receive mailbox */
+	void* flags;			/* -> adapter status flags */
+	void (*isr)(struct sdla* card);	/* interrupt service routine */
+	void (*poll)(struct sdla* card); /* polling routine */
+	int (*exec)(struct sdla* card, void* u_cmd, void* u_data);
+	union
+	{
+		struct
+		{			/****** X.25 specific data **********/
+			unsigned lo_pvc;
+			unsigned hi_pvc;
+			unsigned lo_svc;
+			unsigned hi_svc;
+		} x;
+		struct
+		{			/****** frame relay specific data ***/
+			void* rxmb_base;	/* -> first Rx buffer */
+			void* rxmb_last;	/* -> last Rx buffer */
+			unsigned rx_base;	/* S508 receive buffer base */
+			unsigned rx_top;	/* S508 receive buffer end */
+			unsigned short node_dlci;
+			unsigned short dlci_num;
+		} f;
+		struct			/****** PPP-specific data ***********/
+		{
+			char if_name[WAN_IFNAME_SZ+1];	/* interface name */
+			void* txbuf;		/* -> current Tx buffer */
+			void* txbuf_base;	/* -> first Tx buffer */
+			void* txbuf_last;	/* -> last Tx buffer */
+			void* rxbuf_base;	/* -> first Rx buffer */
+			void* rxbuf_last;	/* -> last Rx buffer */
+			unsigned rx_base;	/* S508 receive buffer base */
+			unsigned rx_top;	/* S508 receive buffer end */
+		} p;
+	} u;
+} sdla_t;
+
+/****** Public Functions ****************************************************/
+
+void wanpipe_open      (sdla_t* card);			/* wpmain.c */
+void wanpipe_close     (sdla_t* card);			/* wpmain.c */
+void wanpipe_set_state (sdla_t* card, int state);	/* wpmain.c */
+
+int wpx_init (sdla_t* card, wandev_conf_t* conf);	/* wpx.c */
+int wpf_init (sdla_t* card, wandev_conf_t* conf);	/* wpf.c */
+int wpp_init (sdla_t* card, wandev_conf_t* conf);	/* wpp.c */
+
+#endif	/* __KERNEL__ */
+#endif	/* _WANPIPE_H */
+
diff -u --recursive --new-file v2.1.24/linux/include/linux/wanrouter.h linux/include/linux/wanrouter.h
--- v2.1.24/linux/include/linux/wanrouter.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/wanrouter.h	Sun Feb  2 16:47:01 1997
@@ -0,0 +1,332 @@
+/*****************************************************************************
+* wanrouter.h	Definitions for the WAN Multiprotocol Router Module.
+*		This module provides API and common services for WAN Link
+*		Drivers and is completely hardware-independent.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Jan 02, 1997	Gene Kozin	Initial version (based on wanpipe.h).
+*****************************************************************************/
+#ifndef	_ROUTER_H
+#define	_ROUTER_H
+
+#define	ROUTER_NAME	"wanrouter"	/* in case we ever change it */
+#define	ROUTER_VERSION	1		/* version number */
+#define	ROUTER_RELEASE	0		/* release (minor version) number */
+#define	ROUTER_IOCTL	'W'		/* for IOCTL calls */
+#define	ROUTER_MAGIC	0x524D4157L	/* signature: 'WANR' reversed */
+
+/* IOCTL codes for /proc/router/<device> entries (up to 255) */
+enum router_ioctls
+{
+	ROUTER_SETUP	= ROUTER_IOCTL<<8,	/* configure device */
+	ROUTER_DOWN,				/* shut down device */
+	ROUTER_STAT,				/* get device status */
+	ROUTER_IFNEW,				/* add interface */
+	ROUTER_IFDEL,				/* delete interface */
+	ROUTER_IFSTAT,				/* get interface status */
+	ROUTER_USER	= (ROUTER_IOCTL<<8)+16,	/* driver-specific calls */
+	ROUTER_USER_MAX	= (ROUTER_IOCTL<<8)+31
+};
+
+/* NLPID for packet encapsulation (ISO/IEC TR 9577) */
+#define	NLPID_IP	0xCC	/* Internet Protocol Datagram */
+#define	NLPID_SNAP	0x80	/* IEEE Subnetwork Access Protocol */
+#define	NLPID_CLNP	0x81	/* ISO/IEC 8473 */
+#define	NLPID_ESIS	0x82	/* ISO/IEC 9542 */
+#define	NLPID_ISIS	0x83	/* ISO/IEC ISIS */
+#define	NLPID_Q933	0x08	/* CCITT Q.933 */
+
+/* Miscellaneous */
+#define	WAN_IFNAME_SZ	15	/* max length of the interface name */
+#define	WAN_DRVNAME_SZ	15	/* max length of the link driver name */
+#define	WAN_ADDRESS_SZ	31	/* max length of the WAN media address */
+
+/****** Data Types **********************************************************/
+
+/*----------------------------------------------------------------------------
+ * X.25-specific link-level configuration.
+ */
+typedef struct wan_x25_conf
+{
+	unsigned lo_pvc;	/* lowest permanent circuit number */
+	unsigned hi_pvc;	/* highest permanent circuit number */
+	unsigned lo_svc;	/* lowest switched circuit number */
+	unsigned hi_svc;	/* highest switched circuit number */
+	unsigned hdlc_window;	/* HDLC window size (1..7) */
+	unsigned pkt_window;	/* X.25 packet window size (1..7) */
+	unsigned t1;		/* HDLC timer T1, sec (1..30) */
+	unsigned t2;		/* HDLC timer T2, sec (0..29) */
+	unsigned t4;		/* HDLC supervisory frame timer = T4 * T1 */
+	unsigned n2;		/* HDLC retransmission limit (1..30) */
+	unsigned t10_t20;	/* X.25 RESTART timeout, sec (1..255) */
+	unsigned t11_t21;	/* X.25 CALL timeout, sec (1..255) */
+	unsigned t12_t22;	/* X.25 RESET timeout, sec (1..255) */
+	unsigned t13_t23;	/* X.25 CLEAR timeout, sec (1..255) */
+	unsigned t16_t26;	/* X.25 INTERRUPT timeout, sec (1..255) */
+	unsigned t28;		/* X.25 REGISTRATION timeout, sec (1..255) */
+	unsigned r10_r20;	/* RESTART retransmission limit (0..250) */
+	unsigned r12_r22;	/* RESET retransmission limit (0..250) */
+	unsigned r13_r23;	/* CLEAR retransmission limit (0..250) */
+	unsigned ccitt_compat;	/* compatibility mode: 1988/1984/1980 */
+} wan_x25_conf_t;
+
+/*----------------------------------------------------------------------------
+ * Frame relay specific link-level configuration.
+ */
+typedef struct wan_fr_conf
+{
+	unsigned cir;		/* committed information rate */
+	unsigned signalling;	/* local in-channel signalling type */
+	unsigned t391;		/* link integrity verification timer */
+	unsigned t392;		/* polling verification timer */
+	unsigned n391;		/* full status polling cycle counter */
+	unsigned n392;		/* error threshold counter */
+	unsigned n393;		/* monitored events counter */
+	unsigned dlci;		/* first DLC number (access node) */
+	unsigned dlci_num;	/* number of DLCs (access node) */
+} wan_fr_conf_t;
+
+/*----------------------------------------------------------------------------
+ * PPP-specific link-level configuration.
+ */
+typedef struct wan_ppp_conf
+{
+	unsigned restart_tmr;	/* restart timer */
+	unsigned auth_rsrt_tmr;	/* authentication timer */
+	unsigned auth_wait_tmr;	/* authentication timer */
+	unsigned mdm_fail_tmr;	/* modem failure timer */
+	unsigned dtr_drop_tmr;	/* DTR drop timer */
+	unsigned connect_tmout;	/* connection timeout */
+	unsigned conf_retry;	/* max. retry */
+	unsigned term_retry;	/* max. retry */
+	unsigned fail_retry;	/* max. retry */
+	unsigned auth_retry;	/* max. retry */
+	unsigned auth_options;	/* authentication opt. */
+	unsigned ip_options;	/* IP options */
+} wan_ppp_conf_t;
+
+/*----------------------------------------------------------------------------
+ * WAN device configuration. Passed to ROUTER_SETUP IOCTL.
+ */
+typedef struct wandev_conf
+{
+	unsigned magic;		/* magic number (for verification) */
+	unsigned config_id;	/* configuration structure identifier */
+				/****** hardware configuration ******/
+	unsigned ioport;	/* adapter I/O port base */
+	unsigned long maddr;	/* dual-port memory address */
+	unsigned msize;		/* dual-port memory size */
+	int irq;		/* interrupt request level */
+	int dma;		/* DMA request level */
+	unsigned bps;		/* data transfer rate */
+	unsigned mtu;		/* maximum transmit unit size */
+	char interface;		/* RS-232/V.35, etc. */
+	char clocking;		/* external/internal */
+	char line_coding;	/* NRZ/NRZI/FM0/FM1, etc. */
+	char station;		/* DTE/DCE, primary/secondary, etc. */
+	char connection;	/* permanent/switched/on-demand */
+	unsigned hw_opt[4];	/* other hardware options */
+	unsigned reserved[4];
+				/****** arbitrary data ***************/
+	unsigned data_size;	/* data buffer size */
+	void* data;		/* data buffer, e.g. firmware */
+	union			/****** protocol-specific ************/
+	{
+		wan_x25_conf_t x25;	/* X.25 configuration */
+		wan_ppp_conf_t ppp;	/* PPP configuration */
+		wan_fr_conf_t fr;	/* frame relay configuration */
+	} u;
+} wandev_conf_t;
+
+/* 'config_id' definitions */
+#define	WANCONFIG_X25	101	/* X.25 link */
+#define	WANCONFIG_FR	102	/* frame relay link */
+#define	WANCONFIG_PPP	103	/* synchronous PPP link */
+
+/*
+ * Configuration options defines.
+ */
+/* general options */
+#define	WANOPT_OFF	0
+#define	WANOPT_ON	1
+#define	WANOPT_NO	0
+#define	WANOPT_YES	1
+
+/* intercace options */
+#define	WANOPT_RS232	0
+#define	WANOPT_V35	1
+
+/* data encoding options */
+#define	WANOPT_NRZ	0
+#define	WANOPT_NRZI	1
+#define	WANOPT_FM0	2
+#define	WANOPT_FM1	3
+
+/* link type options */
+#define	WANOPT_POINTTOPOINT	0	/* RTS always active */
+#define	WANOPT_MULTIDROP	1	/* RTS is active when transmitting */
+
+/* clocking options */
+#define	WANOPT_EXTERNAL	0
+#define	WANOPT_INTERNAL	1
+
+/* station options */
+#define	WANOPT_DTE		0
+#define	WANOPT_DCE		1
+#define	WANOPT_CPE		0
+#define	WANOPT_NODE		1
+#define	WANOPT_SECONDARY	0
+#define	WANOPT_PRIMARY		1
+
+/* connection options */
+#define	WANOPT_PERMANENT	0	/* DTR always active */
+#define	WANOPT_SWITCHED		1	/* use DTR to setup link (dial-up) */
+#define	WANOPT_ONDEMAND		2	/* activate DTR only before sending */
+
+/* frame relay in-channel signalling */
+#define	WANOPT_FR_ANSI		0	/* ANSI T1.617 Annex D */
+#define	WANOPT_FR_Q933		1	/* ITU Q.933A */
+#define	WANOPT_FR_LMI		2	/* LMI */
+
+/*----------------------------------------------------------------------------
+ * WAN Link Status Info (for ROUTER_STAT IOCTL).
+ */
+typedef struct wandev_stat
+{
+	unsigned state;		/* link state */
+	unsigned ndev;		/* number of configured interfaces */
+
+	/* link/interface configuration */
+	unsigned connection;	/* permanent/switched/on-demand */
+	unsigned media_type;	/* Frame relay/PPP/X.25/SDLC, etc. */
+	unsigned mtu;		/* max. transmit unit for this device */
+
+	/* physical level statistics */
+	unsigned modem_status;	/* modem status */
+	unsigned rx_frames;	/* received frames count */
+	unsigned rx_overruns;	/* receiver overrun error count */
+	unsigned rx_crc_err;	/* receive CRC error count */
+	unsigned rx_aborts;	/* received aborted frames count */
+	unsigned rx_bad_length;	/* unexpetedly long/short frames count */
+	unsigned rx_dropped;	/* frames discarded at device level */
+	unsigned tx_frames;	/* transmitted frames count */
+	unsigned tx_underruns;	/* aborted transmissions (underruns) count */
+	unsigned tx_timeouts;	/* transmission timeouts */
+	unsigned tx_rejects;	/* other transmit errors */
+
+	/* media level statistics */
+	unsigned rx_bad_format;	/* frames with invalid format */
+	unsigned rx_bad_addr;	/* frames with invalid media address */
+	unsigned tx_retries;	/* frames re-transmitted */
+	unsigned reserved[16];	/* reserved for future use */
+} wandev_stat_t;
+
+/* 'state' defines */
+enum wan_states
+{
+	WAN_UNCONFIGURED,	/* link/channel is not configured */
+	WAN_DISCONNECTED,	/* link/channel is disconnected */
+	WAN_CONNECTING,		/* connection is in progress */
+	WAN_CONNECTED,		/* link/channel is operational */
+	WAN_LIMIT		/* for verification only */
+};
+
+/* 'modem_status' masks */
+#define	WAN_MODEM_CTS	0x0001	/* CTS line active */
+#define	WAN_MODEM_DCD	0x0002	/* DCD line active */
+#define	WAN_MODEM_DTR	0x0010	/* DTR line active */
+#define	WAN_MODEM_RTS	0x0020	/* RTS line active */
+
+/*----------------------------------------------------------------------------
+ * WAN interface (logical channel) configuration (for ROUTER_IFNEW IOCTL).
+ */
+typedef struct wanif_conf
+{
+	unsigned magic;			/* magic number */
+	unsigned config_id;		/* configuration identifier */
+	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
+	char addr[WAN_ADDRESS_SZ+1];	/* media address, ASCIIZ */
+	unsigned idle_timeout;		/* sec, before disconnecting */
+	unsigned hold_timeout;		/* sec, before re-connecting */
+	int reserved[8];		/* reserved for future extensions */
+} wanif_conf_t;
+
+#ifdef	__KERNEL__
+/****** Kernel Interface ****************************************************/
+
+#include <linux/fs.h>		/* support for device drivers */
+#include <linux/proc_fs.h>	/* proc filesystem pragmatics */
+#include <linux/inet.h>		/* in_aton(), in_ntoa() prototypes */
+#include <linux/netdevice.h>	/* support for network drivers */
+
+/*----------------------------------------------------------------------------
+ * WAN device data space.
+ */
+typedef struct wan_device
+{
+	unsigned magic;			/* magic number */
+	char* name;			/* -> WAN device name (ASCIIZ) */
+	void* private;			/* -> driver private data */
+					/****** hardware configuration ******/
+	unsigned ioport;		/* adapter I/O port base #1 */
+	unsigned long maddr;		/* dual-port memory address */
+	unsigned msize;			/* dual-port memory size */
+	int irq;			/* interrupt request level */
+	int dma;			/* DMA request level */
+	unsigned bps;			/* data transfer rate */
+	unsigned mtu;			/* max physical transmit unit size */
+	char interface;			/* RS-232/V.35, etc. */
+	char clocking;			/* external/internal */
+	char line_coding;		/* NRZ/NRZI/FM0/FM1, etc. */
+	char station;			/* DTE/DCE, primary/secondary, etc. */
+	char connection;		/* permanent/switched/on-demand */
+	unsigned hw_opt[4];		/* other hardware options */
+					/****** status and statistics *******/
+	char state;			/* device state */
+	unsigned modem_status;		/* modem status */
+	struct enet_statistics stats;	/* interface statistics */
+	unsigned reserved[16];		/* reserved for future use */
+	unsigned critical;		/* critical section flag */
+					/****** device management methods ***/
+	int (*setup) (struct wan_device* wandev, wandev_conf_t* conf);
+	int (*shutdown) (struct wan_device* wandev);
+	int (*update) (struct wan_device* wandev);
+	int (*ioctl) (struct wan_device* wandev, unsigned cmd,
+		unsigned long arg);
+	int (*new_if) (struct wan_device* wandev, struct device* dev,
+		wanif_conf_t* conf);
+	int (*del_if) (struct wan_device* wandev, struct device* dev);
+					/****** maintained by the router ****/
+	struct wan_device* next;	/* -> next device */
+	struct device* dev;		/* list of network interfaces */
+	unsigned ndev;			/* number of interfaces */
+	struct proc_dir_entry dent;	/* proc filesystem entry */
+} wan_device_t;
+
+/* Init Point */
+extern void wanrouter_init(void);
+
+/* Public functions available for device drivers */
+extern int register_wan_device (wan_device_t* wandev);
+extern int unregister_wan_device (char* name);
+unsigned short wanrouter_type_trans (struct sk_buff* skb, struct device* dev);
+int wanrouter_encapsulate (struct sk_buff* skb, struct device* dev);
+
+/* Proc interface functions. These must not be called by the drivers! */
+extern int wanrouter_proc_init (void);
+extern void wanrouter_proc_cleanup (void);
+extern int wanrouter_proc_add (wan_device_t* wandev);
+extern int wanrouter_proc_delete (wan_device_t* wandev);
+extern int wanrouter_ioctl(struct inode* inode, struct file* file,
+	unsigned int cmd, unsigned long arg);
+
+#endif	/* __KERNEL__ */
+#endif	/* _ROUTER_H */
diff -u --recursive --new-file v2.1.24/linux/include/net/ax25.h linux/include/net/ax25.h
--- v2.1.24/linux/include/net/ax25.h	Thu Jan 23 21:06:52 1997
+++ linux/include/net/ax25.h	Sun Feb  2 16:41:47 1997
@@ -118,7 +118,7 @@
 #define	AX25_VALUES_IPDEFMODE	0	/* 0=DG 1=VC */
 #define	AX25_VALUES_AXDEFMODE	1	/* 0=Normal 1=Extended Seq Nos */
 #define	AX25_VALUES_TEXT	2	/* Allow PID=Text - 0=No 1=Yes */
-#define	AX25_VALUES_BACKOFF	3	/* 0=Linear 1=Exponential */
+#define	AX25_VALUES_BACKOFF	3	/* 0=None 1=Linear 2=Exponential */
 #define	AX25_VALUES_CONMODE	4	/* Allow connected modes - 0=No 1=Yes */
 #define	AX25_VALUES_WINDOW	5	/* Default window size for standard AX.25 */
 #define	AX25_VALUES_EWINDOW	6	/* Default window size for extended AX.25 */
@@ -135,7 +135,7 @@
 #define	AX25_DEF_IPDEFMODE	0			/* Datagram */
 #define	AX25_DEF_AXDEFMODE	0			/* Normal */
 #define	AX25_DEF_TEXT		1			/* PID=Text allowed */
-#define	AX25_DEF_BACKOFF	1			/* Exponential backoff */
+#define	AX25_DEF_BACKOFF	1			/* Linear backoff */
 #define	AX25_DEF_CONMODE	1			/* Connected mode allowed */
 #define	AX25_DEF_WINDOW		2			/* Window=2 */
 #define	AX25_DEF_EWINDOW	32			/* Module-128 Window=32 */
@@ -197,7 +197,7 @@
 extern char *ax2asc(ax25_address *);
 extern ax25_address *asc2ax(char *);
 extern int  ax25cmp(ax25_address *, ax25_address *);
-extern int  ax25_send_frame(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *, struct device *);
+extern int  ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct device *);
 extern int  ax25_link_up(ax25_address *, ax25_address *, struct device *);
 extern void ax25_destroy_socket(ax25_cb *);
 extern struct device *ax25rtr_get_dev(ax25_address *);
@@ -216,7 +216,7 @@
 extern int  ax25_process_rx_frame(ax25_cb *, struct sk_buff *, int, int);
 
 /* ax25_out.c */
-extern void ax25_output(ax25_cb *, struct sk_buff *);
+extern void ax25_output(ax25_cb *, int, struct sk_buff *);
 extern void ax25_kick(ax25_cb *);
 extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int);
 extern void ax25_nr_error_recovery(ax25_cb *);
diff -u --recursive --new-file v2.1.24/linux/include/net/netrom.h linux/include/net/netrom.h
--- v2.1.24/linux/include/net/netrom.h	Thu Jan 23 21:06:52 1997
+++ linux/include/net/netrom.h	Sun Feb  2 15:18:47 1997
@@ -10,9 +10,6 @@
 
 #define	NR_SLOWHZ			10	/* Run timing at 1/10 second */
 
-#define	NR_T1CLAMPLO  	 		(1 * NR_SLOWHZ)		/* If defined, clamp at 1 second **/
-#define	NR_T1CLAMPHI 			(300 * NR_SLOWHZ)	/* If defined, clamp at 30 seconds **/
-
 #define	NR_NETWORK_LEN			15
 #define	NR_TRANSPORT_LEN		5
 
@@ -51,12 +48,13 @@
 #define	NR_DEFAULT_OBS			6			/* Default Obsolescence Count - 6 */
 #define	NR_DEFAULT_QUAL			10			/* Default Neighbour Quality - 10 */
 #define	NR_DEFAULT_TTL			16			/* Default Time To Live - 16 */
-#define NR_MODULUS 			256
-#define NR_MAX_WINDOW_SIZE		127			/* Maximum Window Allowable - 127 */
-#define	NR_DEFAULT_PACLEN		236			/* Default Packet Length - 236 */
 #define	NR_DEFAULT_ROUTING		1			/* Is routing enabled ? */
 #define	NR_DEFAULT_FAILS		2			/* Link fails until route fails */
 
+#define NR_MODULUS 			256
+#define NR_MAX_WINDOW_SIZE		127			/* Maximum Window Allowable - 127 */
+#define	NR_MAX_PACKET_SIZE		236			/* Maximum Packet Length - 236 */
+
 typedef struct {
 	ax25_address		user_addr, source_addr, dest_addr;
 	struct device		*device;
@@ -65,9 +63,9 @@
 	unsigned char		state, condition, bpqext, hdrincl, window;
 	unsigned short		vs, vr, va, vl;
 	unsigned char		n2, n2count;
-	unsigned short		t1, t2, t4, idle, rtt;
+	unsigned short		t1, t2, t4, idle;
 	unsigned short		t1timer, t2timer, t4timer, idletimer;
-	unsigned short		fraglen, paclen;
+	unsigned short		fraglen;
 	struct sk_buff_head	ack_queue;
 	struct sk_buff_head	reseq_queue;
 	struct sk_buff_head	frag_queue;
@@ -95,7 +93,7 @@
 struct nr_node {
 	struct nr_node  *next;
 	ax25_address    callsign;
-	char mnemonic[7];
+	char		mnemonic[7];
 	unsigned char   which;
 	unsigned char   count;
 	struct nr_route routes[3];
@@ -111,7 +109,6 @@
 extern int  sysctl_netrom_transport_busy_delay;
 extern int  sysctl_netrom_transport_requested_window_size;
 extern int  sysctl_netrom_transport_no_activity_timeout;
-extern int  sysctl_netrom_transport_packet_length;
 extern int  sysctl_netrom_routing_control;
 extern int  sysctl_netrom_link_fails_count;
 extern int  nr_rx_frame(struct sk_buff *, struct device *);
@@ -154,8 +151,6 @@
 extern int  nr_in_rx_window(struct sock *, unsigned short);
 extern void nr_write_internal(struct sock *, int);
 extern void nr_transmit_dm(struct sk_buff *);
-extern unsigned short nr_calculate_t1(struct sock *);
-extern void nr_calculate_rtt(struct sock *);
 
 /* nr_timer.c */
 extern void nr_set_timer(struct sock *);
diff -u --recursive --new-file v2.1.24/linux/include/net/rose.h linux/include/net/rose.h
--- v2.1.24/linux/include/net/rose.h	Thu Jan 23 21:06:52 1997
+++ linux/include/net/rose.h	Sun Feb  2 15:18:47 1997
@@ -52,10 +52,12 @@
 #define	ROSE_DEFAULT_T3			(180 * ROSE_SLOWHZ)	/* Default T13 T23 value */
 #define	ROSE_DEFAULT_HB			(5 * ROSE_SLOWHZ)	/* Default Holdback value */
 #define	ROSE_DEFAULT_IDLE		(20 * 60 * ROSE_SLOWHZ)	/* Default No Activity value */
-#define	ROSE_DEFAULT_WINDOW		2			/* Default Window Size	*/
+#define	ROSE_DEFAULT_ROUTING		1			/* Default routing flag */
+#define	ROSE_DEFAULT_FAIL_TIMEOUT	(120 * ROSE_SLOWHZ)	/* Time until link considered usable */
+
 #define ROSE_MODULUS 			8
-#define ROSE_MAX_WINDOW_SIZE		7			/* Maximum Window Allowable */
-#define	ROSE_PACLEN			128			/* Default Packet Length */
+#define ROSE_MAX_WINDOW_SIZE		2			/* Maximum Window Allowable */
+#define	ROSE_MAX_PACKET_SIZE		128			/* Maximum Packet Length */
 
 #define	ROSE_COND_ACK_PENDING		0x01
 #define	ROSE_COND_PEER_RX_BUSY		0x02
@@ -81,7 +83,7 @@
 	unsigned int      number;
 	int               restarted;
 	struct sk_buff_head queue;
-	unsigned short    t0, t0timer;
+	unsigned short    t0timer, ftimer;
 	struct timer_list timer;
 };
 
@@ -89,7 +91,6 @@
 	struct rose_node  *next;
 	rose_address      address;
 	unsigned short    mask;
-	unsigned char     which;
 	unsigned char     count;
 	struct rose_neigh *neighbour[3];
 };
@@ -127,6 +128,7 @@
 extern int  sysctl_rose_no_activity_timeout;
 extern int  sysctl_rose_ack_hold_back_timeout;
 extern int  sysctl_rose_routing_control;
+extern int  sysctl_rose_link_fail_timeout;
 extern int  rosecmp(rose_address *, rose_address *);
 extern int  rosecmpm(rose_address *, rose_address *, unsigned short);
 extern char *rose2asc(rose_address *);
@@ -145,6 +147,7 @@
 extern int  rose_process_rx_frame(struct sock *, struct sk_buff *);
 
 /* rose_link.c */
+extern void rose_link_set_timer(struct rose_neigh *);
 extern void rose_link_rx_restart(struct sk_buff *, struct rose_neigh *, unsigned short);
 extern void rose_transmit_restart_request(struct rose_neigh *);
 extern void rose_transmit_restart_confirmation(struct rose_neigh *);
diff -u --recursive --new-file v2.1.24/linux/init/main.c linux/init/main.c
--- v2.1.24/linux/init/main.c	Tue Jan 28 18:50:56 1997
+++ linux/init/main.c	Sun Feb  2 15:53:10 1997
@@ -710,6 +710,7 @@
 		}
 		if (checksetup(line))
 			continue;
+		
 		/*
 		 * Then check if it's an environment variable or
 		 * an option.
diff -u --recursive --new-file v2.1.24/linux/kernel/module.c linux/kernel/module.c
--- v2.1.24/linux/kernel/module.c	Tue Jan 28 18:50:57 1997
+++ linux/kernel/module.c	Wed Jan 29 13:40:34 1997
@@ -583,7 +583,7 @@
 
 calc_space_needed:
 	for (; i < mod->nsyms; ++i, ++s)
-		space += strlen((++s)->name)+1;
+		space += strlen(s->name)+1;
 
 	if (put_user(space, ret))
 		return -EFAULT;
diff -u --recursive --new-file v2.1.24/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.24/linux/kernel/sched.c	Sun Feb  2 15:46:21 1997
+++ linux/kernel/sched.c	Sun Feb  2 17:46:41 1997
@@ -1262,64 +1262,81 @@
  * The Alpha uses getxpid, getxuid, and getxgid instead.  Maybe this
  * should be moved into arch/i386 instead?
  */
+ 
 asmlinkage int sys_getpid(void)
 {
-	int ret;
-
-	lock_kernel();
-	ret = current->pid;
-	unlock_kernel();
-	return ret;
+	/* This is SMP safe - current->pid doesnt change */
+	return current->pid;
 }
 
+/*
+ * This is not strictly SMP safe: p_opptr could change
+ * from under us. However, rather than getting any lock
+ * we can use an optimistic algorithm: get the parent
+ * pid, and go back and check that the parent is still
+ * the same. If it has changed (which is extremely unlikely
+ * indeed), we just try again..
+ *
+ * NOTE! This depends on the fact that even if we _do_
+ * get an old value of "parent", we can happily dereference
+ * the pointer: we just can't necessarily trust the result
+ * until we know that the parent pointer is valid.
+ *
+ * The "mb()" macro is a memory barrier - a synchronizing
+ * event. It also makes sure that gcc doesn't optimize
+ * away the necessary memory references.. The barrier doesn't
+ * have to have all that strong semantics: on x86 we don't
+ * really require a synchronizing instruction, for example.
+ * The barrier is more important for code generation than
+ * for any real memory ordering semantics (even if there is
+ * a small window for a race, using the old pointer is
+ * harmless for a while).
+ */
 asmlinkage int sys_getppid(void)
 {
-	int ret;
-
-	lock_kernel();
-	ret = current->p_opptr->pid;
-	unlock_kernel();
-	return ret;
+	int pid;
+	struct task_struct * me = current;
+	struct task_struct * parent;
+
+	parent = me->p_opptr;
+	for (;;) {
+		pid = parent->pid;
+#if __SMP__
+{
+		struct task_struct *old = parent;
+		mb();
+		parent = me->p_opptr;
+		if (old != parent)
+			continue;
+}
+#endif
+		break;
+	}
+	return pid;
 }
 
 asmlinkage int sys_getuid(void)
 {
-	int ret;
-
-	lock_kernel();
-	ret = current->uid;
-	unlock_kernel();
-	return ret;
+	/* Only we change this so SMP safe */
+	return current->uid;
 }
 
 asmlinkage int sys_geteuid(void)
 {
-	int ret;
-
-	lock_kernel();
-	ret = current->euid;
-	unlock_kernel();
-	return ret;
+	/* Only we change this so SMP safe */
+	return current->euid;
 }
 
 asmlinkage int sys_getgid(void)
 {
-	int ret;
-
-	lock_kernel();
-	ret = current->gid;
-	unlock_kernel();
-	return ret;
+	/* Only we change this so SMP safe */
+	return current->gid;
 }
 
 asmlinkage int sys_getegid(void)
 {
-	int ret;
-
-	lock_kernel();
-	ret = current->egid;
-	unlock_kernel();
-	return ret;
+	/* Only we change this so SMP safe */
+	return  current->egid;
 }
 
 /*
@@ -1327,12 +1344,17 @@
  * moved into the arch dependent tree for those ports that require
  * it for backward compatibility?
  */
+
 asmlinkage int sys_nice(int increment)
 {
 	unsigned long newprio;
 	int increase = 0;
 	int ret = -EPERM;
 
+	/*
+	 *	We need a lock. sys_setpriority can affect other tasks.
+	 */
+	 
 	lock_kernel();
 	newprio = increment;
 	if (increment < 0) {
diff -u --recursive --new-file v2.1.24/linux/kernel/sys.c linux/kernel/sys.c
--- v2.1.24/linux/kernel/sys.c	Tue Jan 28 18:50:57 1997
+++ linux/kernel/sys.c	Sun Feb  2 17:32:31 1997
@@ -766,12 +766,8 @@
 
 asmlinkage int sys_getpgrp(void)
 {
-	int ret;
-
-	lock_kernel();
-	ret = current->pgrp;
-	unlock_kernel();
-	return ret;
+	/* SMP - assuming writes are word atomic this is fine */
+	return current->pgrp;
 }
 
 asmlinkage int sys_getsid(pid_t pid)
@@ -779,10 +775,12 @@
 	struct task_struct * p;
 	int ret;
 
-	lock_kernel();
+	/* SMP: The 'self' case requires no lock */
 	if (!pid) {
 		ret = current->session;
 	} else {
+		/* Walking the process table needs locks */
+		lock_kernel();
 		for_each_task(p) {
 			if (p->pid == pid) {
 				ret = p->session;
@@ -790,9 +788,9 @@
 			}
 		}
 		ret = -ESRCH;
-	}
 out:
-	unlock_kernel();
+		unlock_kernel();
+	}
 	return ret;
 }
 
@@ -1117,11 +1115,7 @@
 
 asmlinkage int sys_umask(int mask)
 {
-	int old;
-
-	lock_kernel();
-	old = current->fs->umask;
-	current->fs->umask = mask & S_IRWXUGO;
-	unlock_kernel();
-	return (old);
+	/* The xchg() isn't SMP-safe on x86 right now.. */
+	mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
+	return mask;
 }
diff -u --recursive --new-file v2.1.24/linux/net/Config.in linux/net/Config.in
--- v2.1.24/linux/net/Config.in	Thu Jan  2 15:55:26 1997
+++ linux/net/Config.in	Sun Feb  2 15:18:48 1997
@@ -26,6 +26,9 @@
   fi
 fi
 tristate 'Appletalk DDP' CONFIG_ATALK
+if [ "$CONFIG_ATALK" != "n" ]; then
+  bool 'IP-over-DDP support (EXPERIMENTAL)' CONFIG_IPDDP
+fi
 tristate 'Amateur Radio AX.25 Level 2' CONFIG_AX25
 if [ "$CONFIG_AX25" != "n" ]; then
   dep_tristate 'Amateur Radio NET/ROM' CONFIG_NETROM $CONFIG_AX25
@@ -36,5 +39,6 @@
   tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
   bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
   bool '802.2 LLC (VERY EXPERIMENTAL)' CONFIG_LLC
+  tristate 'WAN router' CONFIG_WAN_ROUTER
 fi
 endmenu
diff -u --recursive --new-file v2.1.24/linux/net/Makefile linux/net/Makefile
--- v2.1.24/linux/net/Makefile	Wed Jan 15 19:45:47 1997
+++ linux/net/Makefile	Sun Feb  2 15:18:48 1997
@@ -9,7 +9,7 @@
 
 MOD_SUB_DIRS := ipv4
 ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \
-		netrom rose lapb x25 #decnet
+		netrom rose lapb x25 wanrouter #decnet
 SUB_DIRS     := core ethernet unix
 MOD_LIST_NAME := NET_MISC_MODULES
 
@@ -46,6 +46,14 @@
 else
   ifeq ($(CONFIG_ATALK),m)
   MOD_SUB_DIRS += appletalk
+  endif
+endif
+
+ifeq ($(CONFIG_WAN_ROUTER),y)
+SUB_DIRS += wanrouter
+else
+  ifeq ($(CONFIG_WAN_ROUTER),m)
+  MOD_SUB_DIRS += wanrouter
   endif
 endif
 
diff -u --recursive --new-file v2.1.24/linux/net/README linux/net/README
--- v2.1.24/linux/net/README	Thu Jan  2 15:55:26 1997
+++ linux/net/README	Sun Feb  2 15:18:48 1997
@@ -14,6 +14,7 @@
 lapb			jsn@cs.nott.ac.uk
 netrom			jsn@cs.nott.ac.uk
 rose			jsn@cs.nott.ac.uk
+wanrouter		genek@compuserve.com and dm@sangoma.com
 unix			alan@lxorguk.ukuu.org.uk
 x25			jsn@cs.nott.ac.uk
 
diff -u --recursive --new-file v2.1.24/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c
--- v2.1.24/linux/net/appletalk/aarp.c	Thu Jan  2 15:55:26 1997
+++ linux/net/appletalk/aarp.c	Sun Feb  2 15:18:48 1997
@@ -441,9 +441,11 @@
 		 *	Compressible ?
 		 * 
 		 *	IFF: src_net==dest_net==device_net
+		 *	(zero matches anything)
 		 */
 		 
-		if(at->s_net==sa->s_net && sa->s_net==ddp->deh_snet)
+		if( ( ddp->deh_snet==0 || at->s_net==ddp->deh_snet)
+		  &&( ddp->deh_dnet==0 || at->s_net==ddp->deh_dnet) )
 		{
 			skb_pull(skb,sizeof(struct ddpehdr)-4);
 			/*
diff -u --recursive --new-file v2.1.24/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.24/linux/net/appletalk/ddp.c	Sun Feb  2 15:46:21 1997
+++ linux/net/appletalk/ddp.c	Sun Feb  2 15:18:48 1997
@@ -23,6 +23,7 @@
  *		Alan Cox		:	Hooks for PPP (based on the
  *						localtalk hook).
  *		Alan Cox		:	Posix bits
+ *		Bradford Johnson	:	IP-over-DDP (experimental)
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -59,6 +60,8 @@
 #include <net/p8022.h>
 #include <net/psnap.h>
 #include <net/sock.h>
+#include <linux/ip.h>
+#include <net/route.h>
 #include <linux/atalk.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
@@ -163,6 +166,7 @@
 extern inline void atalk_destroy_socket(struct sock *sk)
 {
 	sklist_destroy_socket(&atalk_socket_list,sk);
+	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -1109,10 +1113,15 @@
 
 	if(addr->sat_family!=AF_APPLETALK)
 		return -EAFNOSUPPORT;
-#if 0 	/* Netatalk doesn't check this - fix netatalk first!*/
 	if(addr->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast)
+	{
+#if 1	
+		printk(KERN_WARNING "%s is broken and did not set SO_BROADCAST. It will break when 2.2 is released.\n",
+			current->comm);
+#else
 		return -EACCES;
-#endif
+#endif			
+	}
 	if(sk->zapped)
 	{
 		if(atalk_autobind(sk)<0)
@@ -1191,6 +1200,208 @@
 	return(0);
 }
 
+/*	
+ *	IP-over-DDP support.  Under construction.
+ */
+
+#ifdef CONFIG_IPDDP
+
+#define SIOCADDIPDDPRT SIOCDEVPRIVATE
+#define SIOCDELIPDDPRT SIOCDEVPRIVATE+1
+#define SIOCFINDIPDDPRT SIOCDEVPRIVATE+2
+
+struct ipddp_route {
+	struct device *dev;		/* Carrier device */
+	__u32 ip;			/* IP address */
+	struct at_addr at;		/* Gateway appletalk address */
+	int flags;
+	struct ipddp_route *next;
+};
+
+static struct ipddp_route *ipddp_route_head;
+
+static struct ipddp_route ipddp_route_test;
+
+int ipddp_open(struct device *dev)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+int ipddp_close(struct device *dev)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+int ipddp_xmit(struct sk_buff *skb, struct device *dev)
+{
+	/* Retrieve the saved address hint */
+	struct at_addr *a=(struct at_addr *)skb->data;
+	skb_pull(skb,4);
+	
+	((struct net_device_stats *) dev->priv)->tx_packets++;
+
+	/* printk("ipddp_xmit called with headroom %d\n",skb_headroom(skb)); */
+
+	if( aarp_send_ddp(skb->dev,skb,a,NULL) < 0 )
+		dev_kfree_skb(skb,FREE_WRITE);
+
+	return 0;
+}
+
+struct net_device_stats *ipddp_get_stats(struct device *dev)
+{
+	return (struct enet_statistics *) dev->priv;
+}
+
+int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+	struct ipddp_route *urt = (struct ipddp_route *)ifr->ifr_data;
+
+	if(!suser())
+		return -EPERM;
+	
+	/* for now we only have one route at a time */
+
+	switch(cmd) 
+	{
+		case SIOCADDIPDDPRT:
+			if(copy_from_user(&ipddp_route_test,urt,sizeof(struct ipddp_route)))
+				return -EFAULT;
+			ipddp_route_test.dev = atrtr_get_dev(&ipddp_route_test.at);
+			if (dev==NULL)
+				return -ENETUNREACH;
+			ipddp_route_test.next = NULL;
+			printk("added ipddp route through %s\n",ipddp_route_test.dev->name);
+			ipddp_route_head = &ipddp_route_test;
+			return 0;
+		case SIOCFINDIPDDPRT:
+			if(copy_to_user(urt,&ipddp_route_test,sizeof(struct ipddp_route)))
+				return -EFAULT;
+			return 0;
+		case SIOCDELIPDDPRT:
+			ipddp_route_test.dev = NULL;
+			ipddp_route_head = NULL;
+			return 0;
+		default: 
+			return -EINVAL;
+	}
+}
+
+int ipddp_header (struct sk_buff *skb, struct device *dev, unsigned short type,
+		void *daddr, void *saddr, unsigned len)
+{
+	/* printk("ipddp_header\n"); */
+	/* Push down the header space and the type byte */
+	skb_push(skb, sizeof(struct ddpehdr)+1+4);
+	return 0;
+}
+
+/*
+ *	Now the packet really wants to go out. 
+ */
+ 
+int ipddp_rebuild_header (struct sk_buff *skb)
+{
+	struct ddpehdr *ddp;
+	struct at_addr at;
+	struct ipddp_route *rt;
+	struct at_addr *our_addr;
+	u32 paddr = ((struct rtable *)skb->dst)->rt_gateway;
+
+	/*
+	 *	On entry skb->data points to the ddpehdr we reserved earlier.
+	 *	skb->h.raw will be the higher level header.
+	 */
+
+	/*
+	 *	We created this earlier
+	 */
+
+	ddp = (struct ddpehdr *) (skb->data+4);
+	
+	/* find appropriate route */
+
+	for(rt=ipddp_route_head;rt;rt=rt->next) 
+	{
+		if(rt->ip == paddr) 
+			break;
+	}
+
+	if(!rt) {
+		printk("ipddp unreachable dst %08lx\n",ntohl(paddr));
+		return -ENETUNREACH;
+	}
+
+	our_addr = atalk_find_dev_addr(rt->dev);
+ 	
+	/* fill in ddpehdr */
+	ddp->deh_len = skb->len;
+	ddp->deh_hops = 1;
+	ddp->deh_pad = 0;
+	ddp->deh_sum = 0;
+	ddp->deh_dnet = rt->at.s_net;	/* FIXME more hops?? */ 
+	ddp->deh_snet = our_addr->s_net;
+	ddp->deh_dnode = rt->at.s_node;
+	ddp->deh_snode = our_addr->s_node;
+	ddp->deh_dport = 72;
+	ddp->deh_sport = 72;
+	
+	*((__u8 *)(ddp+1)) = 22;	/* ddp type = IP */
+
+	/* fix up length field */
+	*((__u16 *)ddp)=ntohs(*((__u16 *)ddp));
+
+	/* set skb->dev to appropriate device */
+	skb->dev = rt->dev;
+
+	/* skb->raddr = (unsigned long) at */ 
+	at = rt->at;
+	/* Hide it at the start of the buffer */
+	memcpy(skb->data,(void *)&at,sizeof(at));
+	skb->arp = 1;	/* so the actual device doesn't try to arp it... */
+	skb->protocol = htons(ETH_P_ATALK);	/* Protocol has changed */
+	
+	return 0;
+}
+
+int ipddp_init (struct device *dev)
+{
+	ether_setup(dev);
+	dev->hard_start_xmit = ipddp_xmit;
+	dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+	if(!dev->priv) 
+		return -ENOMEM;
+	memset(dev->priv,0,sizeof(struct enet_statistics));
+	dev->get_stats = ipddp_get_stats;
+	dev->do_ioctl = ipddp_ioctl;
+	dev->type = ARPHRD_IPDDP;	/* IP over DDP tunnel */
+	dev->family = AF_INET;
+	dev->mtu = 585;
+	dev->flags |= IFF_NOARP;
+	dev->hard_header = ipddp_header; /* see ip_output.c */
+	dev->rebuild_header = ipddp_rebuild_header;
+	/*
+	 *	The worst case header we will need is currently a
+	 *	ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1)
+	 *	We send over SNAP so that takes another 8 bytes.
+	 */
+	dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
+	dev->open = ipddp_open;
+	dev->stop = ipddp_close;
+
+	return 0;
+}
+
+static struct device dev_ipddp = {
+	"ipddp0\0   ",
+		0, 0, 0, 0,
+		0x0, 0,
+		0, 0, 0, NULL, ipddp_init };
+
+#endif /* CONFIG_IPDDP */
+
 /*
  *	Receive a packet (in skb) from device dev. This has come from the SNAP decoder, and on entry
  *	skb->h.raw is the DDP header, skb->len is the DDP length. The physical headers have been
@@ -1349,18 +1560,38 @@
 	tosat.sat_port = ddp->deh_dport;
 
 	sock=atalk_search_socket( &tosat, atif );
-
+	
 	if(sock==NULL)	/* But not one of our sockets */
 	{
 		kfree_skb(skb,FREE_READ);
 		return(0);
 	}
 
+#ifdef CONFIG_IPDDP
+	/*
+	 *	Check if IP-over-DDP
+	 */
 
+	if(skb->data[12]==22) {
+		struct enet_statistics *estats = 
+			(struct enet_statistics *) dev_ipddp.priv;
+		skb->protocol=htons(ETH_P_IP);
+		skb_pull(skb,13);
+		skb->dev=&dev_ipddp;
+		skb->h.raw = skb->data;
+	/*	printk("passing up ipddp, 0x%02x better be 45\n",skb->data[0]);
+	 *	printk("tot_len %d, skb->len %d\n",
+	 *		ntohs(skb->h.iph->tot_len),skb->len);
+	 */
+		estats->rx_packets++;
+		netif_rx(skb);
+		return 0;
+	}
+#endif /* CONFIG_IPDDP */	
 	/*
 	 *	Queue packet (standard)
 	 */
-
+	 
 	skb->sk = sock;
 
 	if(sock_queue_rcv_skb(sock,skb)<0)
@@ -1468,8 +1699,10 @@
 			return(-EINVAL);
 		if(usat->sat_family != AF_APPLETALK)
 			return -EINVAL;
+#if 0         /* netatalk doesn't implement this check */
 		if(usat->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast)
 			return -EPERM;
+#endif
 	}
 	else
 	{
@@ -1848,7 +2081,11 @@
 	proc_net_register(&proc_appletalk);
 	proc_net_register(&proc_atalk_route);
 	proc_net_register(&proc_atalk_iface);
-#endif
+#endif	
+
+#ifdef CONFIG_IPDDP
+	register_netdev(&dev_ipddp);
+#endif /* CONFIG_IPDDP */
 
 	printk(KERN_INFO "Appletalk 0.18 for Linux NET3.037\n");
 }
diff -u --recursive --new-file v2.1.24/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.1.24/linux/net/ax25/af_ax25.c	Sun Feb  2 15:46:22 1997
+++ linux/net/ax25/af_ax25.c	Sun Feb  2 15:18:48 1997
@@ -138,7 +138,7 @@
  */
 ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}};
 
-ax25_cb *ax25_list = NULL;
+ax25_cb *volatile ax25_list = NULL;
 
 static struct proto_ops ax25_proto_ops;
 
@@ -416,7 +416,6 @@
  *	Find an AX.25 control block given both ends. It will only pick up
  *	floating AX.25 control blocks or non Raw socket bound control blocks.
  */
-
 static ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, ax25_digi *digi, struct device *dev)
 {
 	ax25_cb *s;
@@ -477,10 +476,8 @@
 			if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL)
 				return;
 
-			skb_set_owner_r(copy, sk);
-			skb_queue_tail(&sk->receive_queue, copy);
-			if (!sk->dead)
-				sk->data_ready(sk, skb->len);
+			if (sock_queue_rcv_skb(sk, copy) != 0)
+				kfree_skb(copy, FREE_READ);
 		}
 
 		sk = sk->next;
@@ -532,7 +529,7 @@
 	}
 
 	if (ax25->sk != NULL) {
-		if (ax25->sk->wmem_alloc || ax25->sk->rmem_alloc) { /* Defer: outstanding buffers */
+		if (ax25->sk->wmem_alloc > 0 || ax25->sk->rmem_alloc > 0) {	/* Defer: outstanding buffers */
 			init_timer(&ax25->timer);
 			ax25->timer.expires  = jiffies + 10 * HZ;
 			ax25->timer.function = ax25_destroy_timer;
@@ -841,7 +838,7 @@
 	ax25->backoff = ax25_dev_get_value(dev, AX25_VALUES_BACKOFF);
 }
 
-int ax25_send_frame(struct sk_buff *skb, ax25_address *src, ax25_address *dest,
+int ax25_send_frame(struct sk_buff *skb, int fragment, ax25_address *src, ax25_address *dest,
 	ax25_digi *digi, struct device *dev)
 {
 	ax25_cb *ax25;
@@ -860,7 +857,7 @@
 			if (ax25_queue_length(ax25, skb) > ax25->maxqueue * ax25->window) {
 				kfree_skb(skb, FREE_WRITE);
 			} else {
-				ax25_output(ax25, skb);
+				ax25_output(ax25, fragment, skb);
 			}
 			ax25->idletimer = ax25->idle;
 			return 1;		/* It already existed */
@@ -900,7 +897,7 @@
 
 	ax25_set_timer(ax25);
 
-	ax25_output(ax25, skb);
+	ax25_output(ax25, fragment, skb);
 
 	return 1;			/* We had to create it */
 }
@@ -1004,7 +1001,9 @@
 			return 0;
 
 		case AX25_BACKOFF:
-			sk->protinfo.ax25->backoff = opt ? 1 : 0;
+			if (opt < 0 || opt > 2)
+				return -EINVAL;
+			sk->protinfo.ax25->backoff = opt;
 			return 0;
 
 		case AX25_EXTSEQ:
@@ -1097,7 +1096,7 @@
 	if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0)
 		return err;
 
-	put_user(val, (int *) optval);
+	put_user(val, (int *)optval);
 
 	return 0;
 }
@@ -1171,12 +1170,11 @@
 		return -ENOMEM;
 	}
 
-	sock_init_data(sock,sk);
+	sock_init_data(sock, sk);
 	
-	sock->ops = &ax25_proto_ops;
-
-	sk->protocol      = protocol;
-	sk->mtu           = AX25_MTU;	/* 256 */
+	sock->ops    = &ax25_proto_ops;
+	sk->protocol = protocol;
+	sk->mtu      = AX25_MTU;	/* 256 */
 
 	ax25->sk          = sk;
 	sk->protinfo.ax25 = ax25;
@@ -1199,9 +1197,6 @@
 
 	ax25_fillin_cb(ax25, dev);
 
-	sk->type   = osk->type;
-	sk->socket = osk->socket;
-
 	switch (osk->type) {
 		case SOCK_DGRAM:
 			break;
@@ -1213,17 +1208,19 @@
 			return NULL;
 	}
 
-	sock_init_data(NULL,sk);
+	sock_init_data(NULL, sk);
 	
-	sk->priority    = osk->priority;
-	sk->protocol    = osk->protocol;
-	sk->rcvbuf      = osk->rcvbuf;
-	sk->sndbuf      = osk->sndbuf;
-	sk->debug       = osk->debug;
-	sk->state       = TCP_ESTABLISHED;
-	sk->mtu         = osk->mtu;
-	sk->sleep       = osk->sleep;
-	sk->zapped      = osk->zapped;
+	sk->type     = osk->type;
+	sk->socket   = osk->socket;
+	sk->priority = osk->priority;
+	sk->protocol = osk->protocol;
+	sk->rcvbuf   = osk->rcvbuf;
+	sk->sndbuf   = osk->sndbuf;
+	sk->debug    = osk->debug;
+	sk->state    = TCP_ESTABLISHED;
+	sk->mtu      = osk->mtu;
+	sk->sleep    = osk->sleep;
+	sk->zapped   = osk->zapped;
 
 	ax25->modulus = osk->protinfo.ax25->modulus;
 	ax25->backoff = osk->protinfo.ax25->backoff;
@@ -1461,7 +1458,7 @@
 			} else {
 				sk->protinfo.ax25->digipeat->repeated[ct] = 0;
 			}
-			sk->protinfo.ax25->digipeat->calls[ct]    = fsa->fsa_digipeater[ct];
+			sk->protinfo.ax25->digipeat->calls[ct] = fsa->fsa_digipeater[ct];
 			ct++;
 		}
 	}
@@ -1706,9 +1703,9 @@
 				return 0;
 			}
 #endif
-			skb->arp = 1;
-			skb->dev = dev_out;
+			skb->dev      = dev_out;
 			skb->priority = SOPRI_NORMAL;
+
 			ax25_queue_xmit(skb);
 
 			return 0;
@@ -1771,10 +1768,8 @@
 						 *	Remove the control and PID.
 						 */
 						skb_pull(skb, 2);
-						skb_set_owner_r(skb, sk);
-						skb_queue_tail(&sk->receive_queue, skb);
-						if (!sk->dead)
-							sk->data_ready(sk, skb->len);
+						if (sock_queue_rcv_skb(sk, skb) != 0)
+							kfree_skb(skb, FREE_READ);
 					}
 				} else {
 					kfree_skb(skb, FREE_READ);
@@ -1975,7 +1970,7 @@
 	if (sk->protinfo.ax25->device == NULL)
 		return -ENETUNREACH;
 
-	if (usax) {
+	if (usax != NULL) {
 		if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 			return -EINVAL;
 		if (usax->sax25_family != AF_AX25)
@@ -2030,8 +2025,6 @@
 	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
-	skb->arp = 1;
-
 	skb_reserve(skb, size - len);
 
 	SOCK_DEBUG(sk, "AX.25: Appending user data\n");
@@ -2052,14 +2045,15 @@
 			return -ENOTCONN;
 		}
 
-		ax25_output(sk->protinfo.ax25, skb);	/* Shove it onto the queue and kick */
+		ax25_output(sk->protinfo.ax25, 1, skb);	/* Shove it onto the queue and kick */
 
 		return len;
 	} else {
 		asmptr = skb_push(skb, 1 + size_ax25_addr(dp));
 
 		SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp);
-		if(dp != 0)
+
+		if (dp != NULL)
 			SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi);
 
 		/* Build an AX.25 header */
@@ -2081,7 +2075,6 @@
 
 		return len;
 	}
-
 }
 
 static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags,
@@ -2468,9 +2461,10 @@
 
 	skb->protocol = htons(ETH_P_AX25);
 	skb->dev      = ax25_fwd_dev(skb->dev);
+	skb->arp      = 1;
 
-	ptr = skb_push(skb, 1);
-	*ptr++ = 0;			/* KISS */
+	ptr    = skb_push(skb, 1);
+	*ptr++ = 0x00;			/* KISS */
 
 	dev_queue_xmit(skb);
 }
@@ -2568,7 +2562,7 @@
 
 			skb_pull(ourskb, AX25_HEADER_LEN - 1);	/* Keep PID */
 
-			ax25_send_frame(ourskb, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev);
+			ax25_send_frame(ourskb, 1, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev);
 
 			return 1;
 		}
diff -u --recursive --new-file v2.1.24/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c
--- v2.1.24/linux/net/ax25/ax25_in.c	Thu Jan 23 21:06:54 1997
+++ linux/net/ax25/ax25_in.c	Sun Feb  2 15:18:48 1997
@@ -90,11 +90,7 @@
 						return 1;
 					}
 
-					skbn->arp  = 1;
-					skbn->dev  = ax25->device;
-
-					if (ax25->sk != NULL)
-						skb_set_owner_r(skbn, ax25->sk);
+					skbn->dev = ax25->device;
 
 					skb_reserve(skbn, AX25_MAX_HEADER_LEN);
 
@@ -156,7 +152,7 @@
 	if (skb == NULL) return 0;
 
 	ax25->idletimer = ax25->idle;
-	
+
 	pid = *skb->data;
 
 #ifdef CONFIG_INET
@@ -217,7 +213,6 @@
 		case AX25_UA:
 			if (pf || dama) {
 				if (dama) ax25_dama_on(ax25); /* bke */
-					
 				ax25_calculate_rtt(ax25);
 				ax25->t1timer = 0;
 				ax25->t3timer = ax25->t3;
@@ -228,7 +223,6 @@
 				ax25->state   = AX25_STATE_3;
 				ax25->n2count = 0;
 				ax25->dama_slave = dama;	/* bke */
-					
 				if (ax25->sk != NULL) {
 					ax25->sk->state = TCP_ESTABLISHED;
 					/* For WAIT_SABM connections we will produce an accept ready socket here */
@@ -298,22 +292,8 @@
 			}
 			break;
 
-		case AX25_UA:
-			if (pf) {
-				ax25->state = AX25_STATE_0;
-				ax25_dama_off(ax25);
-				if (ax25->sk != NULL) {
-					ax25->sk->state     = TCP_CLOSE;
-					ax25->sk->err       = 0;
-					ax25->sk->shutdown |= SEND_SHUTDOWN;
-					if (!ax25->sk->dead)
-						ax25->sk->state_change(ax25->sk);
-					ax25->sk->dead      = 1;
-				}
-			}
-			break;
-
 		case AX25_DM:
+		case AX25_UA:
 			if (pf) {
 				ax25->state = AX25_STATE_0;
 				ax25_dama_off(ax25);
@@ -358,24 +338,15 @@
 
 	switch (frametype) {
 		case AX25_SABM:
-			if (dama) ax25_dama_on(ax25);
-			ax25->modulus   = AX25_MODULUS;
-			ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			ax25->condition = 0x00;
-			ax25->t1timer   = 0;
-			ax25->t3timer   = ax25->t3;
-			ax25->idletimer = ax25->idle;
-			ax25->vs        = 0;
-			ax25->va        = 0;
-			ax25->vr        = 0;
-			ax25->dama_slave = dama;
-			break;
-
 		case AX25_SABME:
 			if (dama) ax25_dama_on(ax25);
-			ax25->modulus   = AX25_EMODULUS;
-			ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
+			if (frametype == AX25_SABM) {
+				ax25->modulus = AX25_MODULUS;
+				ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
+			} else {
+				ax25->modulus = AX25_EMODULUS;
+				ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
+			}
 			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
@@ -385,6 +356,7 @@
 			ax25->va        = 0;
 			ax25->vr        = 0;
 			ax25->dama_slave = dama;
+			ax25_requeue_frames(ax25);
 			break;
 
 		case AX25_DISC:
@@ -418,20 +390,12 @@
 			}
 			break;
 
-		case AX25_RNR:
-			ax25->condition |= AX25_COND_PEER_RX_BUSY;
-			ax25_check_need_response(ax25, type, pf);
-			if (ax25_validate_nr(ax25, nr)) {
-				ax25_check_iframes_acked(ax25, nr);
-				dama_check_need_response(ax25, type, pf);
-			} else {
-				ax25_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-			}
-			break;
-
 		case AX25_RR:
-			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+		case AX25_RNR:
+			if (frametype == AX25_RR)
+				ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+			else
+				ax25->condition |= AX25_COND_PEER_RX_BUSY;
 			ax25_check_need_response(ax25, type, pf);
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_check_iframes_acked(ax25, nr);
@@ -546,27 +510,15 @@
 
 	switch (frametype) {
 		case AX25_SABM:
-			if (dama) ax25_dama_on(ax25);
-			ax25->dama_slave = dama;
-			ax25->modulus   = AX25_MODULUS;
-			ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			ax25->condition = 0x00;
-			ax25->t1timer   = 0;
-			ax25->t3timer   = ax25->t3;
-			ax25->idletimer = ax25->idle;
-			ax25->vs        = 0;
-			ax25->va        = 0;
-			ax25->vr        = 0;
-			ax25->state     = AX25_STATE_3;
-			ax25->n2count   = 0;
-			break;
-
 		case AX25_SABME:
 			if (dama) ax25_dama_on(ax25);
-			ax25->dama_slave = dama;
-			ax25->modulus   = AX25_EMODULUS;
-			ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
+			if (frametype == AX25_SABM) {
+				ax25->modulus = AX25_MODULUS;
+				ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
+			} else {
+				ax25->modulus = AX25_EMODULUS;
+				ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
+			}
 			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
@@ -577,6 +529,8 @@
 			ax25->vr        = 0;
 			ax25->state     = AX25_STATE_3;
 			ax25->n2count   = 0;
+			ax25->dama_slave = dama;
+			ax25_requeue_frames(ax25);
 			break;
 
 		case AX25_DISC:
@@ -610,8 +564,12 @@
 			}
 			break;
 
+		case AX25_RR:
 		case AX25_RNR:
-			ax25->condition |= AX25_COND_PEER_RX_BUSY;
+			if (frametype == AX25_RR)
+				ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+			else
+				ax25->condition |= AX25_COND_PEER_RX_BUSY;
 			if (type == AX25_RESPONSE && pf) {
 				ax25->t1timer = 0;
 				if (ax25_validate_nr(ax25, nr)) {
@@ -627,38 +585,6 @@
 				}
 				break;
 			}
-
-			ax25_check_need_response(ax25, type, pf);
-			if (ax25_validate_nr(ax25, nr)) {
-				ax25_frames_acked(ax25, nr);
-				dama_check_need_response(ax25, type, pf);
-			} else {
-				ax25_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-			}
-			break;
-
-		case AX25_RR:
-			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-			if (pf && (type == AX25_RESPONSE || (ax25->dama_slave && type == AX25_COMMAND))) {
-				ax25->t1timer = 0;
-				if (ax25_validate_nr(ax25, nr)) {
-					ax25_frames_acked(ax25, nr);
-					if (ax25->vs == ax25->va) {
-						ax25->t3timer = ax25->t3;
-						ax25->n2count = 0;
-						ax25->state   = AX25_STATE_3;
-					} else {
-						ax25_requeue_frames(ax25);
-					}
-					dama_check_need_response(ax25, type, pf);
-				} else {
-					ax25_nr_error_recovery(ax25);
-					ax25->state = AX25_STATE_1;
-				}
-				break;
-			}
-
 			ax25_check_need_response(ax25, type, pf);
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_frames_acked(ax25, nr);
@@ -689,8 +615,7 @@
 				}
 				break;
 			}
-
-			ax25_check_need_response(ax25, type, pf);	
+			ax25_check_need_response(ax25, type, pf);
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_frames_acked(ax25, nr);
 				if(ax25->vs != ax25->va) {
diff -u --recursive --new-file v2.1.24/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c
--- v2.1.24/linux/net/ax25/ax25_out.c	Thu Jan 23 21:06:54 1997
+++ linux/net/ax25/ax25_out.c	Sun Feb  2 15:18:48 1997
@@ -55,10 +55,12 @@
 #include <linux/interrupt.h>
 
 /*
- * All outgoing AX.25 I frames pass via this routine. Therefore this is
- * where the fragmentation of frames takes place.
+ *	All outgoing AX.25 I frames pass via this routine. Therefore this is
+ *	where the fragmentation of frames takes place. If fragment is set to
+ *	zero then we are not allowed to do fragmentation, even if the frame
+ *	is too large.
  */
-void ax25_output(ax25_cb *ax25, struct sk_buff *skb)
+void ax25_output(ax25_cb *ax25, int fragment, struct sk_buff *skb)
 {
 	struct sk_buff *skbn;
 	unsigned char *p;
@@ -67,7 +69,7 @@
 
 	mtu = ax25->paclen;
 
-	if ((skb->len - 1) > mtu) {
+	if ((skb->len - 1) > mtu && fragment) {
 		if (*skb->data == AX25_P_TEXT) {
 			skb_pull(skb, 1); /* skip PID */
 			ka9qfrag = 0;
@@ -96,8 +98,6 @@
 			
 			restore_flags(flags);
 			
-			skbn->arp  = 1;
-
 			len = (mtu > skb->len) ? skb->len : mtu;
 
 			if (ka9qfrag == 1) {
@@ -257,7 +257,6 @@
 	ptr = skb_push(skb, size_ax25_addr(ax25->digipeat));
 	build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
 
-	skb->arp      = 1;
 	skb->dev      = ax25->device;
 	skb->priority = SOPRI_NORMAL;
 
@@ -397,9 +396,9 @@
 		if (!ax25o->dama_slave)
 			continue;
 
-		if ( !(ax25o->condition & AX25_COND_PEER_RX_BUSY) && 
-		     (ax25o->state == AX25_STATE_3 || 
-		     (ax25o->state == AX25_STATE_4 && ax25o->t1timer == 0))) {
+		if (!(ax25o->condition & AX25_COND_PEER_RX_BUSY) && 
+		    (ax25o->state == AX25_STATE_3 || 
+		    (ax25o->state == AX25_STATE_4 && ax25o->t1timer == 0))) {
 			ax25_requeue_frames(ax25o);
 			ax25_kick(ax25o);
 		}
diff -u --recursive --new-file v2.1.24/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c
--- v2.1.24/linux/net/ax25/ax25_route.c	Thu Jan 23 21:06:54 1997
+++ linux/net/ax25/ax25_route.c	Sun Feb  2 15:18:48 1997
@@ -486,7 +486,7 @@
 		return;
 	}
 
-	memcpy(&dest, skb->data    , AX25_ADDR_LEN);
+	memcpy(&dest, skb->data + 0, AX25_ADDR_LEN);
 	memcpy(&src,  skb->data + 7, AX25_ADDR_LEN);
 
 	bp = skb_push(skb, len);
@@ -638,11 +638,11 @@
 
 	return ax25_dev->forward;
 }
-      
+
 #ifdef MODULE
 
 /*
- *    Free all memory associated with routing and device structures.
+ *	Free all memory associated with routing and device structures.
  */
 void ax25_rt_free(void)
 {
diff -u --recursive --new-file v2.1.24/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c
--- v2.1.24/linux/net/ax25/ax25_subr.c	Sun Feb  2 15:46:22 1997
+++ linux/net/ax25/ax25_subr.c	Sun Feb  2 15:18:48 1997
@@ -101,7 +101,8 @@
 	}
 }
 
-/* Maybe this should be your ax25_invoke_retransmission(), which appears
+/*
+ * Maybe this should be your ax25_invoke_retransmission(), which appears
  * to be used but not do anything.  ax25_invoke_retransmission() used to
  * be in AX 0.29, but has now gone in 0.30.
  */
@@ -260,11 +261,9 @@
 	/*
 	 *	Do the address ourselves
 	 */
-
 	dptr  = skb_push(skb, size_ax25_addr(digi));
 	dptr += build_ax25_addr(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS);
 
-	skb->arp      = 1;
 	skb->dev      = dev;
 	skb->priority = SOPRI_NORMAL;
 
@@ -278,11 +277,19 @@
 {
 	int n, t = 2;
 
-	if (ax25->backoff) {
-		for (n = 0; n < ax25->n2count; n++)
-			t *= 2;
-
-		if (t > 8) t = 8;
+	switch (ax25->backoff) {
+		case 0:
+			break;
+
+		case 1:
+			t += 2 * ax25->n2count;
+			break;
+
+		case 2:
+			for (n = 0; n < ax25->n2count; n++)
+				t *= 2;
+			if (t > 8) t = 8;
+			break;
 	}
 
 	return t * ax25->rtt;
@@ -306,7 +313,7 @@
 /*
  *	Digipeated address processing
  */
- 
+
 
 /*
  *	Given an AX.25 address pull of to, from, digi list, command/response and the start of data
@@ -333,8 +340,10 @@
 	/* Copy to, from */
 	if (dest != NULL) 
 		memcpy(dest, buf + 0, AX25_ADDR_LEN);
+
 	if (src != NULL)  
 		memcpy(src,  buf + 7, AX25_ADDR_LEN);
+
 	buf += 2 * AX25_ADDR_LEN;
 	len -= 2 * AX25_ADDR_LEN;
 	digi->lastrepeat = -1;
@@ -486,7 +495,6 @@
 /*
  *	count the number of buffers of one socket on the write/ack-queue
  */
-
 int ax25_queue_length(ax25_cb *ax25, struct sk_buff *skb)
 {
 	return ax25_list_length(&ax25->write_queue, skb) + ax25_list_length(&ax25->ack_queue, skb);
@@ -500,7 +508,6 @@
  *
  *	Not to mention this request isn't currently reliable.
  */
- 
 void ax25_kiss_cmd(ax25_cb *ax25, unsigned char cmd, unsigned char param)
 {
 	struct sk_buff *skb;
@@ -539,6 +546,7 @@
 		return;
 
 	ax25->dama_slave = 0;
+
 	if (ax25_dev_is_dama_slave(ax25->device) == 0) {
 		SOCK_DEBUG(ax25->sk, "ax25_dama_off: DAMA off\n");
 		ax25_kiss_cmd(ax25, 5, 0);
diff -u --recursive --new-file v2.1.24/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c
--- v2.1.24/linux/net/ax25/ax25_timer.c	Sun Feb  2 15:46:22 1997
+++ linux/net/ax25/ax25_timer.c	Sun Feb  2 15:18:48 1997
@@ -49,37 +49,20 @@
 static void ax25_timer(unsigned long);
 
 /*
- *	Linux set/reset timer routines
+ *	Linux set timer
  */
 void ax25_set_timer(ax25_cb *ax25)
 {
 	unsigned long flags;	
 
-	save_flags(flags);
-	cli();
-	del_timer(&ax25->timer);
-	restore_flags(flags);
-
-	ax25->timer.next     = ax25->timer.prev = NULL;	
-	ax25->timer.data     = (unsigned long)ax25;
-	ax25->timer.function = &ax25_timer;
-
-	ax25->timer.expires = jiffies + 10;
-	add_timer(&ax25->timer);
-}
-
-static void ax25_reset_timer(ax25_cb *ax25)
-{
-	unsigned long flags;
-	
-	save_flags(flags);
-	cli();
+	save_flags(flags); cli();
 	del_timer(&ax25->timer);
 	restore_flags(flags);
 
 	ax25->timer.data     = (unsigned long)ax25;
 	ax25->timer.function = &ax25_timer;
 	ax25->timer.expires  = jiffies + 10;
+
 	add_timer(&ax25->timer);
 }
 
@@ -158,7 +141,7 @@
 				ax25->sk->dead      = 1;
 			}
 
-			ax25_reset_timer(ax25);
+			ax25_set_timer(ax25);
 			return;
 		}
 
@@ -207,9 +190,8 @@
 
 	/* dl1bke 960114: DAMA T1 timeouts are handled in ax25_dama_slave_transmit */
 	/* 		  nevertheless we have to re-enqueue the timer struct...   */
-
 	if (ax25->t1timer == 0 || --ax25->t1timer > 0) {
-		ax25_reset_timer(ax25);
+		ax25_set_timer(ax25);
 		return;
 	}
 
@@ -229,7 +211,7 @@
  *                Thus we'll have to do parts of our T1 handling in
  *                ax25_enquiry_response().
  */
-void ax25_t1_timeout(ax25_cb * ax25)
+void ax25_t1_timeout(ax25_cb *ax25)
 {	
 	switch (ax25->state) {
 		case AX25_STATE_1: 
diff -u --recursive --new-file v2.1.24/linux/net/ax25/sysctl_net_ax25.c linux/net/ax25/sysctl_net_ax25.c
--- v2.1.24/linux/net/ax25/sysctl_net_ax25.c	Thu Jan 23 21:06:54 1997
+++ linux/net/ax25/sysctl_net_ax25.c	Sun Feb  2 15:18:48 1997
@@ -11,7 +11,7 @@
 
 static int min_ax25[] = {0, 0, 0, 0, 0, 1,  1,                1,                1,
 	                 0,                   0,  1,   1,  1, 0x00};
-static int max_ax25[] = {1, 1, 1, 1, 1, 7, 63, 30 * AX25_SLOWHZ, 20 * AX25_SLOWHZ,
+static int max_ax25[] = {1, 1, 1, 2, 1, 7, 63, 30 * AX25_SLOWHZ, 20 * AX25_SLOWHZ,
 	3600 * AX25_SLOWHZ, 65535 * AX25_SLOWHZ, 31, 512, 20, 0x03};
 
 static struct ctl_table_header *ax25_table_header;
diff -u --recursive --new-file v2.1.24/linux/net/core/dev.c linux/net/core/dev.c
--- v2.1.24/linux/net/core/dev.c	Thu Jan 23 21:06:54 1997
+++ linux/net/core/dev.c	Sun Feb  2 15:18:49 1997
@@ -1006,17 +1006,19 @@
 #ifdef CONFIG_PROC_FS
 static int sprintf_stats(char *buffer, struct device *dev)
 {
-	struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL);
+	struct net_device_stats *stats = (dev->get_stats ? dev->get_stats(dev): NULL);
 	int size;
 	
 	if (stats)
-		size = sprintf(buffer, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n",
+		size = sprintf(buffer, "%6s:%8ld %7ld %4ld %4ld %4ld %4ld %8ld %8ld %4ld %4ld %4ld %5ld %4ld\n",
 		   dev->name,
+		   stats->rx_bytes,
 		   stats->rx_packets, stats->rx_errors,
 		   stats->rx_dropped + stats->rx_missed_errors,
 		   stats->rx_fifo_errors,
 		   stats->rx_length_errors + stats->rx_over_errors
 		   + stats->rx_crc_errors + stats->rx_frame_errors,
+		   stats->tx_bytes,
 		   stats->tx_packets, stats->tx_errors, stats->tx_dropped,
 		   stats->tx_fifo_errors, stats->collisions,
 		   stats->tx_carrier_errors + stats->tx_aborted_errors
@@ -1043,7 +1045,7 @@
 
 
 	size = sprintf(buffer, "Inter-|   Receive                  |  Transmit\n"
-			    " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n");
+			    " face |bytes    packets errs drop fifo frame|bytes    packets errs drop fifo colls carrier\n");
 	
 	pos+=size;
 	len+=size;
diff -u --recursive --new-file v2.1.24/linux/net/core/firewall.c linux/net/core/firewall.c
--- v2.1.24/linux/net/core/firewall.c	Wed Jan 15 19:45:47 1997
+++ linux/net/core/firewall.c	Sun Feb  2 15:18:49 1997
@@ -10,8 +10,9 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/firewall.h>
+#include <asm/semaphore.h>
 
-static int firewall_lock=0;
+struct semaphore firewall_sem = MUTEX; 
 static int firewall_policy[NPROTO];
 static struct firewall_ops *firewall_chain[NPROTO];
 
@@ -30,13 +31,7 @@
 	 *	Don't allow two people to adjust at once.
 	 */
 
-	/*
-	 *	FIXME: Swap for a kernel semaphore object
-	 */
-	 
-	while(firewall_lock)
-		schedule();
-	firewall_lock=1;
+	down(&firewall_sem); 
 
 	p=&firewall_chain[pf];
 
@@ -47,7 +42,6 @@
 		p=&((*p)->next);
 	}
 
-
 	/*
 	 * We need to use a memory barrier to make sure that this
 	 * works correctly even in SMP with weakly ordered writes.
@@ -56,6 +50,7 @@
 	 * chain), but not wrt itself (so you can't call this from
 	 * an interrupt. Not that you'd want to).
 	 */
+
 	fw->next=*p;
 	mb();
 	*p = fw;
@@ -64,7 +59,7 @@
 	 *	And release the sleep lock
 	 */
 
-	firewall_lock=0;
+ 	up(&firewall_sem); 
 	return 0;
 }
 
@@ -83,9 +78,7 @@
 	 *	Don't allow two people to adjust at once.
 	 */
 
-	while(firewall_lock)
-		schedule();
-	firewall_lock=1;
+	down(&firewall_sem); 
 
 	nl=&firewall_chain[pf];
 
@@ -95,12 +88,12 @@
 		{
 			struct firewall_ops *f=fw->next;
 			*nl = f;
-			firewall_lock=0;
+			up(&firewall_sem); 
 			return 0;
 		}
 		nl=&((*nl)->next);
 	}
-	firewall_lock=0;
+	up(&firewall_sem);
 	return -ENOENT;
 }
 
diff -u --recursive --new-file v2.1.24/linux/net/core/iovec.c linux/net/core/iovec.c
--- v2.1.24/linux/net/core/iovec.c	Thu Jan 23 21:06:55 1997
+++ linux/net/core/iovec.c	Sun Feb  2 15:18:49 1997
@@ -11,7 +11,8 @@
  *		Andrew Lunn	:	Errors in iovec copying.
  *		Pedro Roque	:	Added memcpy_fromiovecend and
  *					csum_..._fromiovecend.
- *      Andi Kleen  :   fixed error handling for 2.1
+ *		Andi Kleen	:	fixed error handling for 2.1
+ *		Alexey Kuznetsov:	2.1 optimisations
  */
 
 
@@ -35,6 +36,9 @@
 /*
  *	Verify iovec
  *	verify area does a simple check for completly bogus addresses
+ *
+ *	Save time not doing verify_area. copy_*_user will make this work
+ *	in any case.
  */
 
 int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
@@ -48,14 +52,10 @@
 		if(mode==VERIFY_READ)
 		{
 			err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address);
-		}
-		else
-		{
-			err=verify_area(mode, m->msg_name, m->msg_namelen);
+			if(err<0)
+				return err;
 		}
 		
-		if(err<0)
-			return err;
 		m->msg_name = address;
 	} else
 		m->msg_name = NULL;
@@ -67,27 +67,18 @@
 			return -ENOMEM;
 	}
 	
-	for(ct=0;ct<m->msg_iovlen;ct++)
+	err = copy_from_user(iov, m->msg_iov, sizeof(struct iovec)*m->msg_iovlen);
+	if (err)
 	{
-		err = copy_from_user(&iov[ct], &m->msg_iov[ct],
-				     sizeof(struct iovec));
-		if (err)
-		{
-			if (m->msg_iovlen > UIO_FASTIOV)
-				kfree(iov);
-			return err;
-		}
-		
-		err = verify_area(mode, iov[ct].iov_base, iov[ct].iov_len);
-		if(err)
-		{
-			if (m->msg_iovlen > UIO_FASTIOV)
-				kfree(iov);
-			return err;
-		}
-		len+=iov[ct].iov_len;
+		if (m->msg_iovlen > UIO_FASTIOV)
+			kfree(iov);
+		return -EFAULT;
 	}
-	m->msg_iov=&iov[0];
+
+	for(ct=0;ct<m->msg_iovlen;ct++)
+		len+=iov[ct].iov_len;
+
+	m->msg_iov=iov;
 	return len;
 }
 
@@ -131,7 +122,7 @@
 			err = copy_from_user(kdata, iov->iov_base, copy);
 			if (err)
 			{
-				return err; 
+				return -EFAULT;
 			}
 			len-=copy;
 			kdata+=copy;
@@ -171,7 +162,7 @@
 			err = copy_from_user(kdata, base, copy);
 			if (err)
 			{
-				return err;
+				return -EFAULT;
 			}
 			len-=copy;
 			kdata+=copy;
@@ -185,7 +176,7 @@
 		err = copy_from_user(kdata, iov->iov_base, copy);
 		if (err)
 		{
-			return err;
+			return -EFAULT;
 		}
 		len-=copy;
 		kdata+=copy;
diff -u --recursive --new-file v2.1.24/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- v2.1.24/linux/net/ipv4/Config.in	Thu Dec 12 19:37:25 1996
+++ linux/net/ipv4/Config.in	Sun Feb  2 15:18:49 1997
@@ -1,7 +1,6 @@
 #
 # IP configuration
 #
-bool 'IP: forwarding/gatewaying' CONFIG_IP_FORWARD
 bool 'IP: multicasting' CONFIG_IP_MULTICAST
 if [ "$CONFIG_FIREWALL" = "y" ]; then
   bool 'IP: firewalling' CONFIG_IP_FIREWALL
@@ -10,16 +9,12 @@
 	bool 'IP: firewall packet netlink device' CONFIG_IP_FIREWALL_NETLINK
     fi
     bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE
-    if [ "$CONFIG_IP_FORWARD" = "y" ]; then
-      bool 'IP: masquerading' CONFIG_IP_MASQUERADE
-      if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
-        comment 'Protocol-specific masquerading support will be built as modules.'
-      fi
-# hmm... but transparent proxy is useful without forwarding too..
-# i.e. non-lan users will get anonftpd instead of wu-ftpd...
-      bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY
-      bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG
+    bool 'IP: masquerading' CONFIG_IP_MASQUERADE
+    if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
+      comment 'Protocol-specific masquerading support will be built as modules.'
     fi
+    bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY
+    bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG
   fi
 fi
 bool 'IP: accounting' CONFIG_IP_ACCT
diff -u --recursive --new-file v2.1.24/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.1.24/linux/net/ipv4/af_inet.c	Tue Jan 28 18:50:58 1997
+++ linux/net/ipv4/af_inet.c	Sun Feb  2 15:18:49 1997
@@ -1732,15 +1732,21 @@
 	/*
 	 *	Set the ARP module up
 	 */
+
 	arp_init();
+
   	/*
   	 *	Set the IP module up
   	 */
+
 	ip_init();
+
 	/*
 	 *	Set the ICMP layer up
 	 */
+
 	icmp_init(&inet_family_ops);
+
 	/*
 	 *	Set the firewalling up
 	 */
@@ -1757,7 +1763,7 @@
 #if defined(CONFIG_IP_MROUTE)
 	ip_mr_init();
 #endif
-
+	
 	/*
 	 *  Initialise AF_INET alias type (register net_alias_type)
 	 */
diff -u --recursive --new-file v2.1.24/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.24/linux/net/ipv4/arp.c	Tue Jan 28 18:50:58 1997
+++ linux/net/ipv4/arp.c	Sun Feb  2 15:18:49 1997
@@ -1552,7 +1552,7 @@
 	}
 
 	start_bh_atomic();
-	arp_update(sip, sha, dev, 0, !RT_LOCALADDR(rt->rt_flags));
+	arp_update(sip, sha, dev, 0, !RT_LOCALADDR(rt->rt_flags) && dev->type != ARPHRD_METRICOM);
 	end_bh_atomic();
 	kfree_skb(skb, FREE_READ);
 	return 0;
@@ -1617,6 +1617,13 @@
 		if (!dev)
 			dev = rt->u.dst.dev;
 		if (rt->rt_flags&(RTF_LOCAL|RTF_BROADCAST|RTF_MULTICAST|RTCF_NAT)) {
+			if (rt->rt_flags&RTF_BROADCAST &&
+			    dev->type == ARPHRD_METRICOM &&
+			    r->arp_ha.sa_family == ARPHRD_METRICOM) {
+				memcpy(dev->broadcast, r->arp_ha.sa_data, dev->addr_len);
+				ip_rt_put(rt);
+				return 0;
+			}
 			ip_rt_put(rt);
 			return -EINVAL;
 		}
diff -u --recursive --new-file v2.1.24/linux/net/ipv4/fib.c linux/net/ipv4/fib.c
--- v2.1.24/linux/net/ipv4/fib.c	Thu Jan 23 21:06:57 1997
+++ linux/net/ipv4/fib.c	Sun Feb  2 15:18:49 1997
@@ -1571,11 +1571,9 @@
 
 static int get_rt_from_user(struct in_rtmsg *rtm, void *arg)
 {
-	int err;
 	struct rtentry r;
 
-	err = copy_from_user(&r, arg, sizeof(struct rtentry));
-	if (err)
+	if (copy_from_user(&r, arg, sizeof(struct rtentry)))
 		return -EFAULT;
 	if (r.rt_dev) {
 		struct device *dev;
@@ -1662,18 +1660,16 @@
 		case SIOCRTMSG:
 			if (!suser())
 				return -EPERM;
-			err = copy_from_user(&dummy_nlh, arg, sizeof(dummy_nlh));
-			if (err)
-				return err;
+			if (copy_from_user(&dummy_nlh, arg, sizeof(dummy_nlh)))
+				return -EFAULT;
 			switch (dummy_nlh.nlmsg_type)
 			{
 			case RTMSG_NEWROUTE:
 			case RTMSG_DELROUTE:
 				if (dummy_nlh.nlmsg_len < sizeof(m.rtmsg) + sizeof(dummy_nlh))
 					return -EINVAL;
-				err = copy_from_user(&m.rtmsg, arg+sizeof(dummy_nlh), sizeof(m.rtmsg));
-				if (err)
-					return err;
+				if (copy_from_user(&m.rtmsg, arg+sizeof(dummy_nlh), sizeof(m.rtmsg)))
+					return -EFAULT;
 				fib_lock();
 				err = rtmsg_process(&dummy_nlh, &m.rtmsg);
 				fib_unlock();
@@ -1682,9 +1678,8 @@
 			case RTMSG_DELRULE:
 				if (dummy_nlh.nlmsg_len < sizeof(m.rtrmsg) + sizeof(dummy_nlh))
 					return -EINVAL;
-				err = copy_from_user(&m.rtrmsg, arg+sizeof(dummy_nlh), sizeof(m.rtrmsg));
-				if (err)
-					return err;
+				if (copy_from_user(&m.rtrmsg, arg+sizeof(dummy_nlh), sizeof(m.rtrmsg)))
+					return -EFAULT;
 				fib_lock();
 				err = rtrulemsg_process(&dummy_nlh, &m.rtrmsg);
 				fib_unlock();
@@ -1693,9 +1688,8 @@
 			case RTMSG_DELDEVICE:
 				if (dummy_nlh.nlmsg_len < sizeof(m.ifmsg) + sizeof(dummy_nlh))
 					return -EINVAL;
-				err = copy_from_user(&m.ifmsg, arg+sizeof(dummy_nlh), sizeof(m.ifmsg));
-				if (err)
-					return err;
+				if (copy_from_user(&m.ifmsg, arg+sizeof(dummy_nlh), sizeof(m.ifmsg)))
+					return -EFAULT;
 				fib_lock();
 				err = ifmsg_process(&dummy_nlh, &m.ifmsg);
 				fib_unlock();
@@ -1703,9 +1697,8 @@
 			case RTMSG_CONTROL:
 				if (dummy_nlh.nlmsg_len < sizeof(m.rtcmsg) + sizeof(dummy_nlh))
 					return -EINVAL;
-				err = copy_from_user(&m.rtcmsg, arg+sizeof(dummy_nlh), sizeof(m.rtcmsg));
-				if (err)
-					return err;
+				if (copy_from_user(&m.rtcmsg, arg+sizeof(dummy_nlh), sizeof(m.rtcmsg)))
+					return -EFAULT;
 				fib_lock();
 				err = rtcmsg_process(&dummy_nlh, &m.rtcmsg);
 				fib_unlock();
diff -u --recursive --new-file v2.1.24/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- v2.1.24/linux/net/ipv4/ip_forward.c	Thu Jan 23 21:06:57 1997
+++ linux/net/ipv4/ip_forward.c	Sun Feb  2 15:18:49 1997
@@ -173,7 +173,6 @@
 			}
 			if (rt->rt_flags&RTCF_MASQ)
 				goto skip_call_fw_firewall;
-		}
 #endif
 #ifdef CONFIG_FIREWALL
 		fw_res=call_fw_firewall(PF_INET, dev2, iph, NULL);
@@ -191,6 +190,8 @@
 #endif
 
 #ifdef CONFIG_IP_MASQUERADE
+		}
+
 skip_call_fw_firewall:
 		/*
 		 * If this fragment needs masquerading, make it so...
@@ -219,7 +220,7 @@
 		}
 
 #ifdef CONFIG_FIREWALL
-		if ((fw_res = call_out_firewall(PF_INET, skb->dev, iph, NULL)) < FW_ACCEPT) {
+		if ((fw_res = call_out_firewall(PF_INET, dev2, iph, NULL)) < FW_ACCEPT) {
 			/* FW_ACCEPT and FW_MASQUERADE are treated equal:
 			   masquerading is only supported via forward rules */
 			if (fw_res == FW_REJECT)
diff -u --recursive --new-file v2.1.24/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v2.1.24/linux/net/ipv4/ip_fw.c	Tue Jan 28 18:50:58 1997
+++ linux/net/ipv4/ip_fw.c	Sun Feb  2 15:18:49 1997
@@ -1309,14 +1309,13 @@
 
 	if(register_firewall(PF_INET,&ipfw_ops)<0)
 		panic("Unable to register IP firewall.\n");
-
 #ifdef CONFIG_PROC_FS		
 	proc_net_register(&proc_net_ipfwin);
 	proc_net_register(&proc_net_ipfwout);
 	proc_net_register(&proc_net_ipfwfwd);
 #endif
 #endif
-        
+
 #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
 	/* Register for device up/down reports */
 	register_netdevice_notifier(&ipfw_dev_notifier);
diff -u --recursive --new-file v2.1.24/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.24/linux/net/ipv4/tcp.c	Sun Feb  2 15:46:22 1997
+++ linux/net/ipv4/tcp.c	Sun Feb  2 15:18:49 1997
@@ -799,6 +799,7 @@
 int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
 		   int len, int flags)
 {
+	int err = 0;
 	int copied  = 0;
 	struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
 
@@ -849,6 +850,8 @@
 			int tmp;
 			struct sk_buff *skb;
 
+			if (err)
+				return (err);
 			/*
 			 * Stop on errors
 			 */
@@ -1030,7 +1033,7 @@
 				skb->h.th->urg_ptr = ntohs(copy);
 			}
 
-			skb->csum = csum_partial_copy_fromuser(from,
+			skb->csum = csum_partial_copy_from_user(&err, from,
 					skb_put(skb, copy), copy, 0);
 		
 			from += copy;
@@ -1044,6 +1047,9 @@
 
 	sk->err = 0;
 
+	if (err)
+		return (err);
+
 	return copied;
 }
 
@@ -1124,7 +1130,7 @@
 						       msg->msg_name);       
 		}
 		if(addr_len)
-			*addr_len= tp->af_specific->sockaddr_len;
+			*addr_len = tp->af_specific->sockaddr_len;
 		/* 
 		 *	Read urgent data
 		 */
@@ -1173,14 +1179,14 @@
 			break;
 		tcp_eat_skb(sk, skb);
 	}
-
+       
 	SOCK_DEBUG(sk, "sk->rspace = %lu\n", sock_rspace(sk));
-
-	/*
-	 *  We send a ACK if the sender is blocked
-	 *  else let tcp_data deal with the acking policy.
-	 */
-
+	
+  	/*
+  	 *  We send a ACK if the sender is blocked
+  	 *  else let tcp_data deal with the acking policy.
+  	 */
+  
 	if (sk->delayed_acks)
 	{
 		struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
@@ -1456,7 +1462,7 @@
 					       msg->msg_name);       
 	}
 	if(addr_len)
-		*addr_len = tp->af_specific->sockaddr_len;
+		*addr_len= tp->af_specific->sockaddr_len;
 
 	remove_wait_queue(sk->sleep, &wait);
 	current->state = TASK_RUNNING;
diff -u --recursive --new-file v2.1.24/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.24/linux/net/ipv4/tcp_input.c	Sun Feb  2 15:46:22 1997
+++ linux/net/ipv4/tcp_input.c	Sun Feb  2 15:18:49 1997
@@ -760,21 +760,19 @@
 	}
 	else
 		tcp_clear_xmit_timer(sk, TIME_RETRANS);
-
-
+	
 	tcp_fast_retrans(sk, ack_seq, ack, (flag & (FLAG_DATA|FLAG_WIN_UPDATE)));
 
 	/*
 	 *	Remember the highest ack received.
 	 */
-
+	 
 	tp->snd_una = ack;
-
 	return 1;
 
 uninteresting_ack:
 
-	SOCK_DEBUG(sk, "Ack ignored %u %u\n", ack, tp->snd_nxt);
+	SOCK_DEBUG(sk, "Ack ignored %u %u\n",ack,tp->snd_nxt);
 	return 0;
 }
 
@@ -893,21 +891,18 @@
 			break;
 
 		if (!after(skb->end_seq, tp->rcv_nxt)) {
-			SOCK_DEBUG(sk, "ofo packet already received \n");
+			SOCK_DEBUG(sk, "ofo packet was allready received \n");
 			skb_unlink(skb);
 			kfree_skb(skb, FREE_READ);
 			
 			continue;
 		}
-		SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n",
-			       tp->rcv_nxt, skb->seq, skb->end_seq);
-		
-		skb_unlink(skb);
+		SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq);
 
+		skb_unlink(skb);
 		 
 		skb_queue_tail(&sk->receive_queue, skb);
 
-
 		tp->rcv_nxt = skb->end_seq;
 	}
 }
@@ -970,9 +965,7 @@
 		 * Partial packet
 		 * seq < rcv_next < end_seq
 		 */
-		SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n",
-			       tp->rcv_nxt, skb->seq, skb->end_seq);
-
+		SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq);
 		skb_queue_tail(&sk->receive_queue, skb);
 
 		tp->rcv_nxt = skb->end_seq;
@@ -999,8 +992,7 @@
 
 	tp->pred_flags = 0;
 
-	SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n",
-		       tp->rcv_nxt, skb->seq, skb->end_seq);
+	SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq);
 
 	if (skb_peek(&sk->out_of_order_queue) == NULL) {
 		skb_queue_head(&sk->out_of_order_queue,skb);
@@ -1078,16 +1070,16 @@
 	}
 
 	sk->delayed_acks++;
-
+	
 	/*
 	 *	Now tell the user we may have some data. 
 	 */
-
-	if (!sk->dead)
+	 
+	if (!sk->dead) 
 	{
-		SOCK_DEBUG(sk, "Data Wakeup.\n");
+		SOCK_DEBUG(sk, "Data wakeup.\n");
 		sk->data_ready(sk,0);
-	}
+	} 
 	return(1);
 }
 
diff -u --recursive --new-file v2.1.24/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.24/linux/net/ipv4/tcp_ipv4.c	Sun Feb  2 15:46:22 1997
+++ linux/net/ipv4/tcp_ipv4.c	Sun Feb  2 15:18:49 1997
@@ -1004,6 +1004,8 @@
 	default:
 		/* CHECKSUM_UNNECESSARY */
 	}
+	
+	tcp_statistics.TcpInSegs++;
 
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
 	if (IPCB(skb)->redirport)
diff -u --recursive --new-file v2.1.24/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.24/linux/net/ipv4/udp.c	Tue Jan 28 18:50:58 1997
+++ linux/net/ipv4/udp.c	Sun Feb  2 15:18:49 1997
@@ -778,8 +778,8 @@
 		/* <mea@utu.fi> wants to know, who sent it, to
 		   go and stomp on the garbage sender... */
 
-	  /* RFC1122: OK.  Discards the bad packet silently (as far as */
-	  /* the network is concerned, anyway) as per 4.1.3.4 (MUST). */
+		/* RFC1122: OK.  Discards the bad packet silently (as far as */
+		/* the network is concerned, anyway) as per 4.1.3.4 (MUST). */
 
 		NETDEBUG(printk("UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n",
 		       ntohl(saddr),ntohs(uh->source),
@@ -793,11 +793,17 @@
 
 	len = ulen;
 
-	/* Wrong! --ANK */
+	/*
+	 *	FIXME:
+	 *	Trimming things wrongly. We must adjust the base/end to allow
+	 *	for the headers we keep!
+	 *		 --ANK 
+	 */
 	skb_trim(skb,len);
 
 
-	if (rt->rt_flags&(RTF_BROADCAST|RTF_MULTICAST)) {
+	if (rt->rt_flags&(RTF_BROADCAST|RTF_MULTICAST))
+	{
 		/*
 		 *	Multicasts and broadcasts go to each listener.
 		 */
diff -u --recursive --new-file v2.1.24/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.1.24/linux/net/ipv6/af_inet6.c	Tue Jan 28 18:50:59 1997
+++ linux/net/ipv6/af_inet6.c	Sun Feb  2 15:18:51 1997
@@ -129,6 +129,7 @@
 	}
 	
 	sock_init_data(sock,sk);
+	sk->zapped=0;
 
 	sk->family = AF_INET6;
 	sk->protocol = protocol;
@@ -779,8 +780,8 @@
 
 	if (sizeof(struct ipv6_options) > sizeof(dummy_skb->cb))
 	{
-		printk(KERN_CRIT "inet6_proto_init: panic\n");
-		return;
+		printk(KERN_CRIT "inet6_proto_init: size fault\n");
+		return -EINVAL;
 	}
 
   	(void) sock_register(&inet6_family_ops);
diff -u --recursive --new-file v2.1.24/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.1.24/linux/net/ipv6/tcp_ipv6.c	Sun Feb  2 15:46:22 1997
+++ linux/net/ipv6/tcp_ipv6.c	Sun Feb  2 15:18:51 1997
@@ -905,6 +905,8 @@
 				/* CHECKSUM_UNNECESSARY */
 		}
 
+		tcp_statistics.TcpInSegs++;
+		
 		sk = inet6_get_sock(&tcpv6_prot, daddr, saddr, 
 				    th->dest, th->source);
 
diff -u --recursive --new-file v2.1.24/linux/net/lapb/lapb_iface.c linux/net/lapb/lapb_iface.c
--- v2.1.24/linux/net/lapb/lapb_iface.c	Thu Jan 23 21:06:58 1997
+++ linux/net/lapb/lapb_iface.c	Sun Feb  2 15:18:51 1997
@@ -49,8 +49,6 @@
  */
 static void lapb_free_cb(lapb_cb *lapb)
 {
-	del_timer(&lapb->timer);
-
 	kfree_s(lapb, sizeof(lapb_cb));
 
 	MOD_DEC_USE_COUNT;
@@ -161,6 +159,10 @@
 
 	lapb_insert_cb(lapb);
 
+	lapb->t1timer = lapb->t1;
+
+	lapb_set_timer(lapb);
+
 	return LAPB_OK;
 }
 
@@ -171,6 +173,8 @@
 	if ((lapb = lapb_tokentostruct(token)) == NULL)
 		return LAPB_BADTOKEN;
 
+	del_timer(&lapb->timer);
+
 	lapb_clear_queues(lapb);
 
 	lapb_remove_cb(lapb);
@@ -225,14 +229,8 @@
 				return LAPB_INVALUE;
 		}
 
-		lapb->mode   = parms->mode;
-		lapb->window = parms->window;
-
-		if (lapb->mode & LAPB_DCE) {
-			lapb_set_timer(lapb);
-		} else {
-			lapb->t1timer = 0;
-		}
+		lapb->mode    = parms->mode;
+		lapb->window  = parms->window;
 	}
 
 	lapb->t1    = parms->t1;
@@ -265,8 +263,6 @@
 
 	lapb->state = LAPB_STATE_1;
 
-	lapb_set_timer(lapb);
-
 	return LAPB_OK;
 }
 	
@@ -290,7 +286,7 @@
 #endif
 			lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
 			lapb->state   = LAPB_STATE_0;
-			lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+			lapb->t1timer = lapb->t1;
 			return LAPB_NOTCONNECTED;
 
 		case LAPB_STATE_2:
diff -u --recursive --new-file v2.1.24/linux/net/lapb/lapb_in.c linux/net/lapb/lapb_in.c
--- v2.1.24/linux/net/lapb/lapb_in.c	Thu Jan 23 21:06:58 1997
+++ linux/net/lapb/lapb_in.c	Sun Feb  2 15:18:51 1997
@@ -198,7 +198,7 @@
 #endif
 				lapb_clear_queues(lapb);
 				lapb->state   = LAPB_STATE_0;
-				lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+				lapb->t1timer = lapb->t1;
 				lapb->t2timer = 0;
 				lapb_disconnect_indication(lapb, LAPB_REFUSED);
 			}
@@ -244,7 +244,7 @@
 				printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
 #endif
 				lapb->state   = LAPB_STATE_0;
-				lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+				lapb->t1timer = lapb->t1;
 				lapb->t2timer = 0;
 				lapb_disconnect_confirmation(lapb, LAPB_OK);
 			}
@@ -259,7 +259,7 @@
 				printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
 #endif
 				lapb->state   = LAPB_STATE_0;
-				lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+				lapb->t1timer = lapb->t1;
 				lapb->t2timer = 0;
 				lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED);
 			}
@@ -315,6 +315,7 @@
 				lapb->vs        = 0;
 				lapb->vr        = 0;
 				lapb->va        = 0;
+				lapb_requeue_frames(lapb);
 			}
 			break;
 
@@ -333,6 +334,7 @@
 				lapb->vs        = 0;
 				lapb->vr        = 0;
 				lapb->va        = 0;
+				lapb_requeue_frames(lapb);
 			} else {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, pf);
@@ -351,7 +353,7 @@
 			lapb_clear_queues(lapb);
 			lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE);
 			lapb->state   = LAPB_STATE_0;
-			lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+			lapb->t1timer = lapb->t1;
 			lapb->t2timer = 0;
 			lapb_disconnect_indication(lapb, LAPB_OK);
 			break;
@@ -365,7 +367,7 @@
 #endif
 			lapb_clear_queues(lapb);
 			lapb->state   = LAPB_STATE_0;
-			lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+			lapb->t1timer = lapb->t1;
 			lapb->t2timer = 0;
 			lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED);
 			break;
@@ -519,6 +521,7 @@
 				lapb->vs        = 0;
 				lapb->vr        = 0;
 				lapb->va        = 0;
+				lapb_requeue_frames(lapb);
 			}
 			break;
 
@@ -537,6 +540,7 @@
 				lapb->vs        = 0;
 				lapb->vr        = 0;
 				lapb->va        = 0;
+				lapb_requeue_frames(lapb);
 			} else {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, pf);
@@ -555,7 +559,7 @@
 			lapb_clear_queues(lapb);
 			lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE);
 			lapb->state   = LAPB_STATE_0;
-			lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+			lapb->t1timer = lapb->t1;
 			lapb->t2timer = 0;
 			lapb_disconnect_indication(lapb, LAPB_OK);
 			break;
@@ -569,7 +573,7 @@
 #endif
 			lapb_clear_queues(lapb);
 			lapb->state   = LAPB_STATE_0;
-			lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
+			lapb->t1timer = lapb->t1;
 			lapb->t2timer = 0;
 			lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED);
 			break;
diff -u --recursive --new-file v2.1.24/linux/net/lapb/lapb_timer.c linux/net/lapb/lapb_timer.c
--- v2.1.24/linux/net/lapb/lapb_timer.c	Thu Jan 23 21:06:58 1997
+++ linux/net/lapb/lapb_timer.c	Sun Feb  2 15:18:51 1997
@@ -41,37 +41,20 @@
 static void lapb_timer(unsigned long);
 
 /*
- *	Linux set/reset timer routines
+ *	Linux set timer
  */
 void lapb_set_timer(lapb_cb *lapb)
 {
 	unsigned long flags;	
 
-	save_flags(flags);
-	cli();
-	del_timer(&lapb->timer);
-	restore_flags(flags);
-
-	lapb->timer.next     = lapb->timer.prev = NULL;	
-	lapb->timer.data     = (unsigned long)lapb;
-	lapb->timer.function = &lapb_timer;
-
-	lapb->timer.expires = jiffies + 10;
-	add_timer(&lapb->timer);
-}
-
-static void lapb_reset_timer(lapb_cb *lapb)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
+	save_flags(flags); cli();
 	del_timer(&lapb->timer);
 	restore_flags(flags);
 
 	lapb->timer.data     = (unsigned long)lapb;
 	lapb->timer.function = &lapb_timer;
 	lapb->timer.expires  = jiffies + 10;
+
 	add_timer(&lapb->timer);
 }
 
@@ -98,7 +81,7 @@
 	}
 
 	if (lapb->t1timer == 0 || --lapb->t1timer > 0) {
-		lapb_reset_timer(lapb);
+		lapb_set_timer(lapb);
 		return;
 	}
 
@@ -111,7 +94,6 @@
 			if (lapb->n2count == lapb->n2) {
 				lapb_clear_queues(lapb);
 				lapb->state   = LAPB_STATE_0;
-				lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
 				lapb->t2timer = 0;
 				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
@@ -137,7 +119,6 @@
 			if (lapb->n2count == lapb->n2) {
 				lapb_clear_queues(lapb);
 				lapb->state   = LAPB_STATE_0;
-				lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
 				lapb->t2timer = 0;
 				lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
@@ -156,13 +137,15 @@
 			lapb->n2count = 1;
 			lapb_transmit_enquiry(lapb);
 			lapb->state   = LAPB_STATE_4;
+#if LAPB_DEBUG > 0
+			printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
+#endif
 			break;
 
 		case LAPB_STATE_4:
 			if (lapb->n2count == lapb->n2) {
 				lapb_clear_queues(lapb);
 				lapb->state   = LAPB_STATE_0;
-				lapb->t1timer = (lapb->mode & LAPB_DCE) ? lapb->t1 : 0;
 				lapb->t2timer = 0;
 				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
diff -u --recursive --new-file v2.1.24/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.1.24/linux/net/netrom/af_netrom.c	Sun Feb  2 15:46:23 1997
+++ linux/net/netrom/af_netrom.c	Sun Feb  2 15:18:52 1997
@@ -74,7 +74,6 @@
 int sysctl_netrom_transport_busy_delay            = NR_DEFAULT_T4;
 int sysctl_netrom_transport_requested_window_size = NR_DEFAULT_WINDOW;
 int sysctl_netrom_transport_no_activity_timeout   = NR_DEFAULT_IDLE;
-int sysctl_netrom_transport_packet_length         = NR_DEFAULT_PACLEN;
 int sysctl_netrom_routing_control                 = NR_DEFAULT_ROUTING;
 int sysctl_netrom_link_fails_count                = NR_DEFAULT_FAILS;
 
@@ -119,7 +118,6 @@
 /*
  *	Socket removal during an interrupt is now safe.
  */
-
 static void nr_remove_socket(struct sock *sk)
 {
 	struct sock *s;
@@ -310,7 +308,7 @@
 		kfree_skb(skb, FREE_READ);
 	}
 
-	if (sk->wmem_alloc || sk->rmem_alloc) {	/* Defer: outstanding buffers */
+	if (sk->wmem_alloc > 0 || sk->rmem_alloc > 0) {	/* Defer: outstanding buffers */
 		init_timer(&sk->timer);
 		sk->timer.expires  = jiffies + 10 * HZ;
 		sk->timer.function = nr_destroy_timer;
@@ -365,7 +363,6 @@
 	  	case NETROM_T1:
   			if (nr_ctl.arg < 1) 
   				return -EINVAL;
-  			sk->protinfo.nr->rtt = (nr_ctl.arg * NR_SLOWHZ) / 2;
   			sk->protinfo.nr->t1  = nr_ctl.arg * NR_SLOWHZ;
   			save_flags(flags); cli();
   			if (sk->protinfo.nr->t1timer > sk->protinfo.nr->t1)
@@ -410,14 +407,6 @@
 	  		restore_flags(flags);
 	  		break;
 
-	  	case NETROM_PACLEN:
-	  		if (nr_ctl.arg < 16 || nr_ctl.arg > 65535) 
-	  			return -EINVAL;
-	  		if (nr_ctl.arg > 236) /* we probably want this */
-	  			printk(KERN_WARNING "nr_ctl_ioctl: Warning --- huge paclen %d\n", (int)nr_ctl.arg);
-	  		sk->protinfo.nr->paclen = nr_ctl.arg;
-	  		break;
-
 	  	default:
 	  		return -EINVAL;
 	  }
@@ -446,7 +435,7 @@
 		case NETROM_T1:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.nr->rtt = (opt * NR_SLOWHZ) / 2;
+			sk->protinfo.nr->t1 = opt * NR_SLOWHZ;
 			return 0;
 
 		case NETROM_T2:
@@ -477,12 +466,6 @@
 			sk->protinfo.nr->hdrincl = opt ? 1 : 0;
 			return 0;
 
-		case NETROM_PACLEN:
-			if (opt < 1 || opt > 65536)
-				return -EINVAL;
-			sk->protinfo.nr->paclen = opt;
-			return 0;
-
 		default:
 			return -ENOPROTOOPT;
 	}
@@ -523,10 +506,6 @@
 			val = sk->protinfo.nr->hdrincl;
 			break;
 
-		case NETROM_PACLEN:
-			val = sk->protinfo.nr->paclen;
-			break;
-
 		default:
 			return -ENOPROTOOPT;
 	}
@@ -571,30 +550,25 @@
 
 	nr = sk->protinfo.nr;
 
-	sock_init_data(sock,sk);
-
-	init_timer(&sk->timer);
-
-	sock->ops	  = &nr_proto_ops;
+	sock_init_data(sock, sk);
 
-	sk->protocol      = protocol;
-	sk->mtu           = NETROM_MTU;	/* 236 */
+	sock->ops    = &nr_proto_ops;
+	sk->protocol = protocol;
+	sk->mtu      = NETROM_MTU;	/* 236 */
 
 	skb_queue_head_init(&nr->ack_queue);
 	skb_queue_head_init(&nr->reseq_queue);
 	skb_queue_head_init(&nr->frag_queue);
 
-	nr->rtt      = sysctl_netrom_transport_timeout / 2;
-	nr->t1       = sysctl_netrom_transport_timeout;
-	nr->t2       = sysctl_netrom_transport_acknowledge_delay;
-	nr->n2       = sysctl_netrom_transport_maximum_tries;
-	nr->t4       = sysctl_netrom_transport_busy_delay;
-	nr->idle     = sysctl_netrom_transport_no_activity_timeout;
-	nr->paclen   = sysctl_netrom_transport_packet_length;
-	nr->window   = sysctl_netrom_transport_requested_window_size;
+	nr->t1     = sysctl_netrom_transport_timeout;
+	nr->t2     = sysctl_netrom_transport_acknowledge_delay;
+	nr->n2     = sysctl_netrom_transport_maximum_tries;
+	nr->t4     = sysctl_netrom_transport_busy_delay;
+	nr->idle   = sysctl_netrom_transport_no_activity_timeout;
+	nr->window = sysctl_netrom_transport_requested_window_size;
 
-	nr->bpqext     = 1;
-	nr->state      = NR_STATE_0;
+	nr->bpqext = 1;
+	nr->state  = NR_STATE_0;
 
 	return 0;
 }
@@ -612,38 +586,34 @@
 
 	nr = sk->protinfo.nr;
 
-	sock_init_data(NULL,sk);
+	sock_init_data(NULL, sk);
 
-	init_timer(&sk->timer);
-
-	sk->type        = osk->type;
-	sk->socket      = osk->socket;
-	sk->priority    = osk->priority;
-	sk->protocol    = osk->protocol;
-	sk->rcvbuf      = osk->rcvbuf;
-	sk->sndbuf      = osk->sndbuf;
-	sk->debug       = osk->debug;
-	sk->state       = TCP_ESTABLISHED;
-	sk->mtu         = osk->mtu;
-	sk->sleep       = osk->sleep;
-	sk->zapped      = osk->zapped;
+	sk->type     = osk->type;
+	sk->socket   = osk->socket;
+	sk->priority = osk->priority;
+	sk->protocol = osk->protocol;
+	sk->rcvbuf   = osk->rcvbuf;
+	sk->sndbuf   = osk->sndbuf;
+	sk->debug    = osk->debug;
+	sk->state    = TCP_ESTABLISHED;
+	sk->mtu      = osk->mtu;
+	sk->sleep    = osk->sleep;
+	sk->zapped   = osk->zapped;
 
 	skb_queue_head_init(&nr->ack_queue);
 	skb_queue_head_init(&nr->reseq_queue);
 	skb_queue_head_init(&nr->frag_queue);
 
-	nr->rtt      = osk->protinfo.nr->rtt;
-	nr->t1       = osk->protinfo.nr->t1;
-	nr->t2       = osk->protinfo.nr->t2;
-	nr->n2       = osk->protinfo.nr->n2;
-	nr->t4       = osk->protinfo.nr->t4;
-	nr->idle     = osk->protinfo.nr->idle;
-	nr->paclen   = osk->protinfo.nr->paclen;
-	nr->window   = osk->protinfo.nr->window;
-
-	nr->device   = osk->protinfo.nr->device;
-	nr->bpqext   = osk->protinfo.nr->bpqext;
-	nr->hdrincl  = osk->protinfo.nr->hdrincl;
+	nr->t1      = osk->protinfo.nr->t1;
+	nr->t2      = osk->protinfo.nr->t2;
+	nr->n2      = osk->protinfo.nr->n2;
+	nr->t4      = osk->protinfo.nr->t4;
+	nr->idle    = osk->protinfo.nr->idle;
+	nr->window  = osk->protinfo.nr->window;
+
+	nr->device  = osk->protinfo.nr->device;
+	nr->bpqext  = osk->protinfo.nr->bpqext;
+	nr->hdrincl = osk->protinfo.nr->hdrincl;
 
 	return sk;
 }
@@ -687,7 +657,7 @@
 			nr_write_internal(sk, NR_DISCACK);
 			sk->protinfo.nr->state = NR_STATE_0;
 			sk->state              = TCP_CLOSE;
-			sk->shutdown           = SEND_SHUTDOWN;
+			sk->shutdown          |= SEND_SHUTDOWN;
 			sk->state_change(sk);
 			sk->dead               = 1;
 			nr_destroy_socket(sk);
@@ -697,7 +667,7 @@
 			nr_clear_queues(sk);
 			sk->protinfo.nr->n2count = 0;
 			nr_write_internal(sk, NR_DISCREQ);
-			sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk);
+			sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
 			sk->protinfo.nr->t2timer = 0;
 			sk->protinfo.nr->t4timer = 0;
 			sk->protinfo.nr->state   = NR_STATE_2;
@@ -1033,8 +1003,8 @@
 	/* L4 timeout negotiation */
 	if (skb->len == 37) {
 		timeout = skb->data[36] * 256 + skb->data[35];
-		if (timeout * NR_SLOWHZ < make->protinfo.nr->rtt * 2)
-			make->protinfo.nr->rtt = (timeout * NR_SLOWHZ) / 2;
+		if (timeout * NR_SLOWHZ < make->protinfo.nr->t1)
+			make->protinfo.nr->t1 = timeout * NR_SLOWHZ;
 		make->protinfo.nr->bpqext = 1;
 	} else {
 		make->protinfo.nr->bpqext = 0;
@@ -1110,8 +1080,6 @@
 	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
-	skb->arp = 1;
-
 	skb_reserve(skb, size - len);
 
 	/*
@@ -1285,7 +1253,7 @@
 
 	cli();
 
-	len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2    n2  rtt wnd paclen Snd-Q Rcv-Q\n");
+	len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2    n2  wnd Snd-Q Rcv-Q\n");
 
 	for (s = nr_list; s != NULL; s = s->next) {
 		if ((dev = s->protinfo.nr->device) == NULL)
@@ -1297,7 +1265,7 @@
 			ax2asc(&s->protinfo.nr->user_addr));
 		len += sprintf(buffer + len, "%-9s ",
 			ax2asc(&s->protinfo.nr->dest_addr));
-		len += sprintf(buffer + len, "%-9s %-3s  %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %2d/%02d %3d %3d %6d %5d %5d\n",
+		len += sprintf(buffer + len, "%-9s %-3s  %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %2d/%02d %3d %5d %5d\n",
 			ax2asc(&s->protinfo.nr->source_addr),
 			devname, s->protinfo.nr->my_index, s->protinfo.nr->my_id,
 			s->protinfo.nr->your_index, s->protinfo.nr->your_id,
@@ -1307,9 +1275,9 @@
 			s->protinfo.nr->t1      / NR_SLOWHZ,
 			s->protinfo.nr->t2timer / NR_SLOWHZ,
 			s->protinfo.nr->t2      / NR_SLOWHZ,
-			s->protinfo.nr->n2count, s->protinfo.nr->n2,
-			s->protinfo.nr->rtt     / NR_SLOWHZ,
-			s->protinfo.nr->window, s->protinfo.nr->paclen,
+			s->protinfo.nr->n2count,
+			s->protinfo.nr->n2,
+			s->protinfo.nr->window,
 			s->wmem_alloc, s->rmem_alloc);
 
 		pos = begin + len;
@@ -1399,7 +1367,7 @@
 
 	sock_register(&nr_family_ops);
 	register_netdevice_notifier(&nr_dev_notifier);
-	printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.6 for AX25.034 Linux 2.1\n");
+	printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.6 for AX25.035 Linux 2.1\n");
 
 	if (!ax25_protocol_register(AX25_P_NETROM, nr_route_frame))
 		printk(KERN_ERR "NET/ROM unable to register protocol with AX.25\n");
diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- v2.1.24/linux/net/netrom/nr_dev.c	Thu Jan 23 21:06:58 1997
+++ linux/net/netrom/nr_dev.c	Sun Feb  2 15:18:52 1997
@@ -228,9 +228,7 @@
 
 int nr_init(struct device *dev)
 {
-	int i;
-
-	dev->mtu		= 236;		/* MTU			*/
+	dev->mtu		= NR_MAX_PACKET_SIZE;
 	dev->tbusy		= 0;
 	dev->hard_start_xmit	= nr_xmit;
 	dev->open		= nr_open;
@@ -259,9 +257,7 @@
 
 	dev->get_stats = nr_get_stats;
 
-	/* Fill in the generic fields of the device structure. */
-	for (i = 0; i < DEV_NUMBUFFS; i++)
-		skb_queue_head_init(&dev->buffs[i]);
+	dev_init_buffers(dev);
 
 	return 0;
 };
diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c
--- v2.1.24/linux/net/netrom/nr_in.c	Thu Jan 23 21:06:58 1997
+++ linux/net/netrom/nr_in.c	Sun Feb  2 15:18:52 1997
@@ -67,8 +67,6 @@
 		if ((skbn = alloc_skb(sk->protinfo.nr->fraglen, GFP_ATOMIC)) == NULL)
 			return 1;
 
-		skbn->arp  = 1;
-		skb_set_owner_r(skbn, sk);
 		skbn->h.raw = skbn->data;
 
 		skbo = skb_dequeue(&sk->protinfo.nr->frag_queue);
@@ -97,7 +95,6 @@
 	switch (frametype) {
 
 		case NR_CONNACK:
-			nr_calculate_rtt(sk);
 			sk->protinfo.nr->your_index = skb->data[17];
 			sk->protinfo.nr->your_id    = skb->data[18];
 			sk->protinfo.nr->t1timer    = 0;
@@ -311,7 +308,7 @@
 int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
 	int queued = 0, frametype;
-	
+
 	if (sk->protinfo.nr->state == NR_STATE_0)
 		return 0;
 
@@ -319,8 +316,7 @@
 
 	frametype = skb->data[19];
 
-	switch (sk->protinfo.nr->state)
-	{
+	switch (sk->protinfo.nr->state) {
 		case NR_STATE_1:
 			queued = nr_state1_machine(sk, skb, frametype);
 			break;
diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_out.c linux/net/netrom/nr_out.c
--- v2.1.24/linux/net/netrom/nr_out.c	Thu Jan 23 21:06:58 1997
+++ linux/net/netrom/nr_out.c	Sun Feb  2 15:18:52 1997
@@ -50,11 +50,9 @@
 {
 	struct sk_buff *skbn;
 	unsigned char transport[NR_TRANSPORT_LEN];
-	int err, frontlen, len, mtu;
+	int err, frontlen, len;
 
-	mtu = sk->protinfo.nr->paclen;
-
-	if (skb->len - NR_TRANSPORT_LEN > mtu) {
+	if (skb->len - NR_TRANSPORT_LEN > NR_MAX_PACKET_SIZE) {
 		/* Save a copy of the Transport Header */
 		memcpy(transport, skb->data, NR_TRANSPORT_LEN);
 		skb_pull(skb, NR_TRANSPORT_LEN);
@@ -62,15 +60,12 @@
 		frontlen = skb_headroom(skb);
 
 		while (skb->len > 0) {
-			if ((skbn = sock_alloc_send_skb(sk, frontlen + mtu, 0, 0, &err)) == NULL)
+			if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, 0, &err)) == NULL)
 				return;
 
-			skbn->sk   = sk;
-			skbn->arp  = 1;
-
 			skb_reserve(skbn, frontlen);
 
-			len = (mtu > skb->len) ? skb->len : mtu;
+			len = (NR_MAX_PACKET_SIZE > skb->len) ? skb->len : NR_MAX_PACKET_SIZE;
 
 			/* Copy the user data */
 			memcpy(skb_put(skbn, len), skb->data, len);
@@ -187,9 +182,8 @@
 		sk->protinfo.nr->vl         = sk->protinfo.nr->vr;
 		sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
 
-		if (sk->protinfo.nr->t1timer == 0) {
-			sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk);
-		}
+		if (sk->protinfo.nr->t1timer == 0)
+			sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
 	}
 
 	nr_set_timer(sk);
@@ -218,8 +212,6 @@
 
 	*dptr++ = sysctl_netrom_network_ttl_initialiser;
 
-	skb->arp = 1;
-
 	if (!nr_route_frame(skb, NULL)) {
 		kfree_skb(skb, FREE_WRITE);
 
@@ -245,7 +237,7 @@
 	nr_write_internal(sk, NR_CONNREQ);
 
 	sk->protinfo.nr->t2timer = 0;
-	sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk);
+	sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
 }
 
 /*
@@ -258,9 +250,8 @@
 	if (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY) {
 		frametype |= NR_CHOKE_FLAG;
 	} else {
-		if (skb_peek(&sk->protinfo.nr->reseq_queue) != NULL) {
+		if (skb_peek(&sk->protinfo.nr->reseq_queue) != NULL)
 			frametype |= NR_NAK_FLAG;
-		}
 	}
 
 	nr_write_internal(sk, frametype);
@@ -273,13 +264,12 @@
 {
 	if (sk->protinfo.nr->vs == nr) {
 		nr_frames_acked(sk, nr);
-		nr_calculate_rtt(sk);
 		sk->protinfo.nr->t1timer = 0;
 		sk->protinfo.nr->n2count = 0;
 	} else {
 		if (sk->protinfo.nr->va != nr) {
 			nr_frames_acked(sk, nr);
-			sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk);
+			sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
 		}
 	}
 }
diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c
--- v2.1.24/linux/net/netrom/nr_route.c	Thu Jan 23 21:06:58 1997
+++ linux/net/netrom/nr_route.c	Sun Feb  2 15:18:52 1997
@@ -101,6 +101,7 @@
 		nr_neigh->locked   = 0;
 		nr_neigh->count    = 0;
 		nr_neigh->number   = nr_neigh_no++;
+		nr_neigh->failed   = 0;
 
 		if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
 			if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
@@ -330,7 +331,7 @@
 
 			if (nr_neigh->count == 0 && !nr_neigh->locked)
 				nr_remove_neigh(nr_neigh);
-				
+
 			nr_node->count--;
 
 			if (nr_node->count == 0) {
@@ -697,7 +698,7 @@
 
 	if (ax25 != NULL)
 		nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
-		            ax25->device, 0, sysctl_netrom_network_ttl_initialiser);
+			    ax25->device, 0, sysctl_netrom_obsolescence_count_initialiser);
 
 	if ((dev = nr_dev_get(nr_dest)) != NULL)	/* Its for me */
 		return nr_rx_frame(skb, dev);
@@ -729,7 +730,7 @@
 	dptr  = skb_push(skb, 1);
 	*dptr = AX25_P_NETROM;
 
-	return ax25_send_frame(skb, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
+	return ax25_send_frame(skb, 0, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
 }
 
 int nr_nodes_get_info(char *buffer, char **start, off_t offset,
diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_subr.c linux/net/netrom/nr_subr.c
--- v2.1.24/linux/net/netrom/nr_subr.c	Thu Jan 23 21:06:58 1997
+++ linux/net/netrom/nr_subr.c	Sun Feb  2 15:18:52 1997
@@ -175,7 +175,7 @@
 	switch (frametype & 0x0F) {
 
 		case NR_CONNREQ:
-			timeout  = (sk->protinfo.nr->rtt / NR_SLOWHZ) * 2;
+			timeout  = sk->protinfo.nr->t1 / NR_SLOWHZ;
 			*dptr++  = sk->protinfo.nr->my_index;
 			*dptr++  = sk->protinfo.nr->my_id;
 			*dptr++  = 0;
@@ -267,40 +267,8 @@
 	*dptr++ = NR_CONNACK | NR_CHOKE_FLAG;
 	*dptr++ = 0;
 
-	skbn->sk   = NULL;
-
 	if (!nr_route_frame(skbn, NULL))
 		kfree_skb(skbn, FREE_WRITE);
-}
-
-/*
- *	Exponential backoff for NET/ROM
- */
-unsigned short nr_calculate_t1(struct sock *sk)
-{
-	int n, t;
-	
-	for (t = 2, n = 0; n < sk->protinfo.nr->n2count; n++)
-		t *= 2;
-
-	if (t > 8) t = 8;
-
-	return t * sk->protinfo.nr->rtt;
-}
-
-/*
- *	Calculate the Round Trip Time
- */
-void nr_calculate_rtt(struct sock *sk)
-{
-	if (sk->protinfo.nr->t1timer > 0 && sk->protinfo.nr->n2count == 0)
-		sk->protinfo.nr->rtt = (9 * sk->protinfo.nr->rtt + sk->protinfo.nr->t1 - sk->protinfo.nr->t1timer) / 10;
-
-	if (sk->protinfo.nr->rtt < NR_T1CLAMPLO)
-		sk->protinfo.nr->rtt = NR_T1CLAMPLO;
-
-        if (sk->protinfo.nr->rtt > NR_T1CLAMPHI)
-                sk->protinfo.nr->rtt = NR_T1CLAMPHI;
 }
 
 #endif
diff -u --recursive --new-file v2.1.24/linux/net/netrom/nr_timer.c linux/net/netrom/nr_timer.c
--- v2.1.24/linux/net/netrom/nr_timer.c	Thu Jan 23 21:06:58 1997
+++ linux/net/netrom/nr_timer.c	Sun Feb  2 15:18:52 1997
@@ -43,37 +43,20 @@
 static void nr_timer(unsigned long);
 
 /*
- *	Linux set/reset timer routines
+ *	Linux set timer
  */
 void nr_set_timer(struct sock *sk)
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
-	del_timer(&sk->timer);
-	restore_flags(flags);
-
-	sk->timer.next     = sk->timer.prev = NULL;	
-	sk->timer.data     = (unsigned long)sk;
-	sk->timer.function = &nr_timer;
-
-	sk->timer.expires = jiffies+10;
-	add_timer(&sk->timer);
-}
-
-static void nr_reset_timer(struct sock *sk)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
+	save_flags(flags); cli();
 	del_timer(&sk->timer);
 	restore_flags(flags);
 
 	sk->timer.data     = (unsigned long)sk;
 	sk->timer.function = &nr_timer;
 	sk->timer.expires  = jiffies+10;
+
 	add_timer(&sk->timer);
 }
 
@@ -133,7 +116,7 @@
 	}
 
 	if (sk->protinfo.nr->t1timer == 0 || --sk->protinfo.nr->t1timer > 0) {
-		nr_reset_timer(sk);
+		nr_set_timer(sk);
 		return;
 	}
 
@@ -187,7 +170,7 @@
 			break;
 	}
 
-	sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk);
+	sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
 
 	nr_set_timer(sk);
 }
diff -u --recursive --new-file v2.1.24/linux/net/netrom/sysctl_net_netrom.c linux/net/netrom/sysctl_net_netrom.c
--- v2.1.24/linux/net/netrom/sysctl_net_netrom.c	Thu Jan 23 21:06:58 1997
+++ linux/net/netrom/sysctl_net_netrom.c	Sun Feb  2 15:18:52 1997
@@ -26,7 +26,6 @@
 static int min_window[]  = {1}, max_window[]  = {127};
 static int min_idle[]    = {0 * NR_SLOWHZ};
 static int max_idle[]    = {65535 * NR_SLOWHZ};
-static int min_n1[]      = {1}, max_n1[]      = {236};
 static int min_route[]   = {0}, max_route[]   = {1};
 static int min_fails[]   = {1}, max_fails[]   = {10};
 
@@ -60,9 +59,6 @@
         {NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT, "transport_no_activity_timeout",
          &sysctl_netrom_transport_no_activity_timeout, sizeof(int), 0644, NULL,
          &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_idle, &max_idle},
-        {NET_NETROM_TRANSPORT_PACKET_LENGTH, "transport_packet_length",
-         &sysctl_netrom_transport_packet_length, sizeof(int), 0644, NULL,
-         &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_n1, &max_n1},
         {NET_NETROM_ROUTING_CONTROL, "routing_control",
          &sysctl_netrom_routing_control, sizeof(int), 0644, NULL,
          &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_route, &max_route},
diff -u --recursive --new-file v2.1.24/linux/net/netsyms.c linux/net/netsyms.c
--- v2.1.24/linux/net/netsyms.c	Tue Jan 28 18:50:59 1997
+++ linux/net/netsyms.c	Sun Feb  2 15:18:52 1997
@@ -93,6 +93,7 @@
 EXPORT_SYMBOL(sk_free);
 EXPORT_SYMBOL(sock_wake_async);
 EXPORT_SYMBOL(sock_alloc_send_skb);
+EXPORT_SYMBOL(sock_init_data);
 EXPORT_SYMBOL(sock_no_fcntl);
 EXPORT_SYMBOL(sock_rfree);
 EXPORT_SYMBOL(sock_wfree);
@@ -102,7 +103,6 @@
 EXPORT_SYMBOL(skb_copy_datagram_iovec);
 EXPORT_SYMBOL(skb_realloc_headroom);
 EXPORT_SYMBOL(datagram_poll);
-EXPORT_SYMBOL(sock_init_data);
 EXPORT_SYMBOL(put_cmsg);
 
 EXPORT_SYMBOL(neigh_table_init);
diff -u --recursive --new-file v2.1.24/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.1.24/linux/net/rose/af_rose.c	Sun Feb  2 15:46:23 1997
+++ linux/net/rose/af_rose.c	Sun Feb  2 15:18:52 1997
@@ -59,7 +59,8 @@
 int sysctl_rose_clear_request_timeout   = ROSE_DEFAULT_T3;
 int sysctl_rose_no_activity_timeout     = ROSE_DEFAULT_IDLE;
 int sysctl_rose_ack_hold_back_timeout   = ROSE_DEFAULT_HB;
-int sysctl_rose_routing_control         = 1;
+int sysctl_rose_routing_control         = ROSE_DEFAULT_ROUTING;
+int sysctl_rose_link_fail_timeout       = ROSE_DEFAULT_FAIL_TIMEOUT;
 
 static unsigned int lci = 1;
 
@@ -157,7 +158,7 @@
 	memset(rose, 0x00, sizeof(*rose));
 
 	sk->protinfo.rose = rose;
-	rose->sk = sk;
+	rose->sk          = sk;
 
 	return sk;
 }
@@ -221,7 +222,7 @@
 
 	if (event != NETDEV_DOWN)
 		return NOTIFY_DONE;
-		
+
 	rose_kill_by_device(dev);
 	rose_rt_device_down(dev);
 	rose_link_device_down(dev);
@@ -356,7 +357,7 @@
 		kfree_skb(skb, FREE_READ);
 	}
 
-	if (sk->wmem_alloc || sk->rmem_alloc) {	/* Defer: outstanding buffers */
+	if (sk->wmem_alloc > 0 || sk->rmem_alloc > 0) {	/* Defer: outstanding buffers */
 		init_timer(&sk->timer);
 		sk->timer.expires  = jiffies + 10 * HZ;
 		sk->timer.function = rose_destroy_timer;
@@ -412,16 +413,6 @@
 			rose_set_timer(sk);
 	  		break;
 
-	  	case ROSE_T0:
-  			if (rose_ctl.arg < 1) 
-  				return -EINVAL;
-  			if (sk->protinfo.rose->neighbour != NULL) {
-	  			save_flags(flags); cli();
-	  			sk->protinfo.rose->neighbour->t0 = rose_ctl.arg * ROSE_SLOWHZ;
-	  			restore_flags(flags);
-	  		}
-  			break;
-
 	  	case ROSE_T1:
   			if (rose_ctl.arg < 1) 
   				return -EINVAL;
@@ -487,13 +478,6 @@
 	get_user(opt, (int *)optval);
 
 	switch (optname) {
-		case ROSE_T0:
-			if (opt < 1)
-				return -EINVAL;
-			if (sk->protinfo.rose->neighbour != NULL)
-				sk->protinfo.rose->neighbour->t0 = opt * ROSE_SLOWHZ;
-			return 0;
-
 		case ROSE_T1:
 			if (opt < 1)
 				return -EINVAL;
@@ -544,13 +528,6 @@
 		return -EOPNOTSUPP;
 	
 	switch (optname) {
-		case ROSE_T0:
-			if (sk->protinfo.rose->neighbour != NULL)
-				val = sk->protinfo.rose->neighbour->t0 / ROSE_SLOWHZ;
-			else
-				val = sysctl_rose_restart_request_timeout / ROSE_SLOWHZ;
-			break;
-
 		case ROSE_T1:
 			val = sk->protinfo.rose->t1 / ROSE_SLOWHZ;
 			break;
@@ -609,28 +586,6 @@
 	return -EOPNOTSUPP;
 }
 
-static void def_callback1(struct sock *sk)
-{
-	if (!sk->dead)
-		wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
-	if (!sk->dead) {
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 1);
-	}
-}
-
-static void def_callback3(struct sock *sk)
-{
-	if (!sk->dead) {
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 2); 
-	}		
-}
-
 static int rose_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
@@ -644,19 +599,19 @@
 
 	rose = sk->protinfo.rose;
 
-	sock_init_data(sock,sk);
+	sock_init_data(sock, sk);
 	
-	sock->ops	  = &rose_proto_ops;
-	sk->protocol      = protocol;
-	sk->mtu           = ROSE_MTU;	/* 128 */
+	sock->ops    = &rose_proto_ops;
+	sk->protocol = protocol;
+	sk->mtu      = ROSE_MTU;	/* 128 */
 
 	skb_queue_head_init(&rose->frag_queue);
 
-	rose->t1    = sysctl_rose_call_request_timeout;
-	rose->t2    = sysctl_rose_reset_request_timeout;
-	rose->t3    = sysctl_rose_clear_request_timeout;
-	rose->hb    = sysctl_rose_ack_hold_back_timeout;
-	rose->idle  = sysctl_rose_no_activity_timeout;
+	rose->t1   = sysctl_rose_call_request_timeout;
+	rose->t2   = sysctl_rose_reset_request_timeout;
+	rose->t3   = sysctl_rose_clear_request_timeout;
+	rose->hb   = sysctl_rose_ack_hold_back_timeout;
+	rose->idle = sysctl_rose_no_activity_timeout;
 
 	rose->state = ROSE_STATE_0;
 
@@ -676,28 +631,19 @@
 
 	rose = sk->protinfo.rose;
 
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->back_log);
-
-	init_timer(&sk->timer);
-
-	sk->type        = osk->type;
-	sk->socket      = osk->socket;
-	sk->priority    = osk->priority;
-	sk->protocol    = osk->protocol;
-	sk->rcvbuf      = osk->rcvbuf;
-	sk->sndbuf      = osk->sndbuf;
-	sk->debug       = osk->debug;
-	sk->state       = TCP_ESTABLISHED;
-	sk->mtu         = osk->mtu;
-	sk->sleep       = osk->sleep;
-	sk->zapped      = osk->zapped;
-
-	sk->state_change = def_callback1;
-	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback3;
-	sk->error_report = def_callback1;
+	sock_init_data(NULL, sk);
+
+	sk->type     = osk->type;
+	sk->socket   = osk->socket;
+	sk->priority = osk->priority;
+	sk->protocol = osk->protocol;
+	sk->rcvbuf   = osk->rcvbuf;
+	sk->sndbuf   = osk->sndbuf;
+	sk->debug    = osk->debug;
+	sk->state    = TCP_ESTABLISHED;
+	sk->mtu      = osk->mtu;
+	sk->sleep    = osk->sleep;
+	sk->zapped   = osk->zapped;
 
 	skb_queue_head_init(&rose->frag_queue);
 
@@ -845,7 +791,7 @@
 	if (sk->state == TCP_ESTABLISHED)
 		return -EISCONN;	/* No reconnect on a seqpacket socket */
 
-	sk->state   = TCP_CLOSE;	
+	sk->state   = TCP_CLOSE;
 	sock->state = SS_UNCONNECTED;
 
 	if (addr_len != sizeof(struct sockaddr_rose))
@@ -894,7 +840,7 @@
 	/* Now the loop */
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
 		return -EINPROGRESS;
-		
+
 	cli();	/* To avoid races on the sleep */
 
 	/*
@@ -920,7 +866,7 @@
 
 	return 0;
 }
-	
+
 static int rose_socketpair(struct socket *sock1, struct socket *sock2)
 {
 	return -EOPNOTSUPP;
@@ -1139,8 +1085,6 @@
 	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
-	skb->arp = 1;
-
 	skb_reserve(skb, size - len);
 
 	/*
@@ -1470,7 +1414,7 @@
 	proc_net_register(&proc_net_rose_neigh);
 	proc_net_register(&proc_net_rose_nodes);
 	proc_net_register(&proc_net_rose_routes);
-#endif	
+#endif
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c
--- v2.1.24/linux/net/rose/rose_dev.c	Thu Jan 23 21:06:59 1997
+++ linux/net/rose/rose_dev.c	Sun Feb  2 15:18:52 1997
@@ -200,9 +200,7 @@
 
 int rose_init(struct device *dev)
 {
-	int i;
-
-	dev->mtu		= ROSE_PACLEN - 2;
+	dev->mtu		= ROSE_MAX_PACKET_SIZE - 2;
 	dev->tbusy		= 0;
 	dev->hard_start_xmit	= rose_xmit;
 	dev->open		= rose_open;
@@ -231,9 +229,7 @@
 
 	dev->get_stats = rose_get_stats;
 
-	/* Fill in the generic fields of the device structure. */
-	for (i = 0; i < DEV_NUMBUFFS; i++)
-		skb_queue_head_init(&dev->buffs[i]);
+	dev_init_buffers(dev);
 
 	return 0;
 };
diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_in.c linux/net/rose/rose_in.c
--- v2.1.24/linux/net/rose/rose_in.c	Thu Jan 23 21:06:59 1997
+++ linux/net/rose/rose_in.c	Sun Feb  2 15:18:52 1997
@@ -1,8 +1,8 @@
 /*
  *	Rose release 001
  *
- *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *	releases, misbehave and/or generally screw up. It might even work. 
+ *	This is ALPHA test software. This code may break your machine, randomly fail to work with new
+ *	releases, misbehave and/or generally screw up. It might even work.
  *
  *	This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -64,8 +64,6 @@
 		if ((skbn = alloc_skb(sk->protinfo.rose->fraglen, GFP_ATOMIC)) == NULL)
 			return 1;
 
-		skbn->arp  = 1;
-		skb_set_owner_r(skbn, sk);
 		skbn->h.raw = skbn->data;
 
 		skbo = skb_dequeue(&sk->protinfo.rose->frag_queue);
@@ -189,11 +187,10 @@
 
 		case ROSE_RR:
 		case ROSE_RNR:
-			if (frametype == ROSE_RNR) {
+			if (frametype == ROSE_RNR)
 				sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY;
-			} else {
+			else
 				sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
-			}
 			if (!rose_validate_nr(sk, nr)) {
 				rose_clear_queues(sk);
 				rose_write_internal(sk, ROSE_RESET_REQUEST);
@@ -246,7 +243,7 @@
 			 * If the window is full, ack the frame, else start the
 			 * acknowledge hold back timer.
 			 */
-			if (((sk->protinfo.rose->vl + ROSE_DEFAULT_WINDOW) % ROSE_MODULUS) == sk->protinfo.rose->vr) {
+			if (((sk->protinfo.rose->vl + ROSE_MAX_WINDOW_SIZE) % ROSE_MODULUS) == sk->protinfo.rose->vr) {
 				sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
 				sk->protinfo.rose->timer      = 0;
 				rose_enquiry_response(sk);
diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_link.c linux/net/rose/rose_link.c
--- v2.1.24/linux/net/rose/rose_link.c	Thu Jan 23 21:06:59 1997
+++ linux/net/rose/rose_link.c	Sun Feb  2 15:18:52 1997
@@ -44,37 +44,20 @@
 static void rose_link_timer(unsigned long);
 
 /*
- *	Linux set/reset timer routines
+ *	Linux set timer
  */
-static void rose_link_set_timer(struct rose_neigh *neigh)
+void rose_link_set_timer(struct rose_neigh *neigh)
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	save_flags(flags); cli();
 	del_timer(&neigh->timer);
 	restore_flags(flags);
 
-	neigh->timer.next     = neigh->timer.prev = NULL;	
 	neigh->timer.data     = (unsigned long)neigh;
 	neigh->timer.function = &rose_link_timer;
-
 	neigh->timer.expires  = jiffies + 10;
-	add_timer(&neigh->timer);
-}
-
-static void rose_link_reset_timer(struct rose_neigh *neigh)
-{
-	unsigned long flags;
 
-	save_flags(flags);
-	cli();
-	del_timer(&neigh->timer);
-	restore_flags(flags);
-
-	neigh->timer.data     = (unsigned long)neigh;
-	neigh->timer.function = &rose_link_timer;
-	neigh->timer.expires  = jiffies + 10;
 	add_timer(&neigh->timer);
 }
 
@@ -88,19 +71,22 @@
 {
 	struct rose_neigh *neigh = (struct rose_neigh *)param;
 
-	if (neigh->t0timer == 0 || --neigh->t0timer > 0) {
-		rose_link_reset_timer(neigh);
-		return;
-	}
+	if (neigh->ftimer > 0)
+		neigh->ftimer--;
 
-	/*
-	 * T0 for a link has expired.
-	 */
-	rose_transmit_restart_request(neigh);
+	if (neigh->t0timer > 0) {
+		neigh->t0timer--;
 
-	neigh->t0timer = neigh->t0;
+		if (neigh->t0timer == 0) {
+			rose_transmit_restart_request(neigh);
+			neigh->t0timer = sysctl_rose_restart_request_timeout;
+		}
+	}
 
-	rose_link_set_timer(neigh);
+	if (neigh->ftimer > 0 || neigh->t0timer > 0)
+		rose_link_set_timer(neigh);
+	else
+		del_timer(&neigh->timer);
 }
 
 /*
@@ -117,7 +103,7 @@
 	else
 		rose_call = &rose_callsign;
 
-	return ax25_send_frame(skb, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+	return ax25_send_frame(skb, 0, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
 }
 
 /*
@@ -199,8 +185,6 @@
 	*dptr++ = 0x00;
 	*dptr++ = 0;
 
-	skb->sk = NULL;
-
 	if (!rose_send_frame(skb, neigh))
 		kfree_skb(skb, FREE_WRITE);
 }
@@ -228,8 +212,6 @@
 	*dptr++ = 0x00;
 	*dptr++ = ROSE_RESTART_CONFIRMATION;
 
-	skb->sk = NULL;
-
 	if (!rose_send_frame(skb, neigh))
 		kfree_skb(skb, FREE_WRITE);
 }
@@ -258,8 +240,6 @@
 	*dptr++ = ROSE_DIAGNOSTIC;
 	*dptr++ = diag;
 
-	skb->sk = NULL;
-
 	if (!rose_send_frame(skb, neigh))
 		kfree_skb(skb, FREE_WRITE);
 }
@@ -290,8 +270,6 @@
 	*dptr++ = cause;
 	*dptr++ = 0x00;
 
-	skb->sk = NULL;
-
 	if (!rose_send_frame(skb, neigh))
 		kfree_skb(skb, FREE_WRITE);
 }
@@ -311,8 +289,6 @@
 	dptr = skb_push(skb, 1);
 	*dptr++ = AX25_P_ROSE;
 
-	skb->arp = 1;
-
 	if (neigh->restarted) {
 		if (!rose_send_frame(skb, neigh))
 			kfree_skb(skb, FREE_WRITE);
@@ -321,7 +297,7 @@
 
 		if (neigh->t0timer == 0) {
 			rose_transmit_restart_request(neigh);
-			neigh->t0timer = neigh->t0;
+			neigh->t0timer = sysctl_rose_restart_request_timeout;
 			rose_link_set_timer(neigh);
 		}
 	}
diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_out.c linux/net/rose/rose_out.c
--- v2.1.24/linux/net/rose/rose_out.c	Thu Jan 23 21:06:59 1997
+++ linux/net/rose/rose_out.c	Sun Feb  2 15:18:52 1997
@@ -49,7 +49,7 @@
 	unsigned char header[ROSE_MIN_LEN];
 	int err, frontlen, len;
 
-	if (skb->len - ROSE_MIN_LEN > ROSE_PACLEN) {
+	if (skb->len - ROSE_MIN_LEN > ROSE_MAX_PACKET_SIZE) {
 		/* Save a copy of the Header */
 		memcpy(header, skb->data, ROSE_MIN_LEN);
 		skb_pull(skb, ROSE_MIN_LEN);
@@ -57,15 +57,12 @@
 		frontlen = skb_headroom(skb);
 
 		while (skb->len > 0) {
-			if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, 0, &err)) == NULL)
+			if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_MAX_PACKET_SIZE, 0, 0, &err)) == NULL)
 				return;
 
-			skbn->sk   = sk;
-			skbn->arp  = 1;
-
 			skb_reserve(skbn, frontlen);
 
-			len = (ROSE_PACLEN > skb->len) ? skb->len : ROSE_PACLEN;
+			len = (ROSE_MAX_PACKET_SIZE > skb->len) ? skb->len : ROSE_MAX_PACKET_SIZE;
 
 			/* Copy the user data */
 			memcpy(skb_put(skbn, len), skb->data, len);
@@ -112,7 +109,7 @@
 
 	del_timer(&sk->timer);
 
-	end = (sk->protinfo.rose->va + ROSE_DEFAULT_WINDOW) % ROSE_MODULUS;
+	end = (sk->protinfo.rose->va + ROSE_MAX_WINDOW_SIZE) % ROSE_MODULUS;
 
 	if (!(sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) &&
 	    sk->protinfo.rose->vs != end                             &&
@@ -149,11 +146,10 @@
 
 void rose_enquiry_response(struct sock *sk)
 {
-	if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY) {
+	if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)
 		rose_write_internal(sk, ROSE_RNR);
-	} else {
+	else
 		rose_write_internal(sk, ROSE_RR);
-	}
 
 	sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
 	sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_route.c linux/net/rose/rose_route.c
--- v2.1.24/linux/net/rose/rose_route.c	Thu Jan 23 21:06:59 1997
+++ linux/net/rose/rose_route.c	Sun Feb  2 15:18:52 1997
@@ -86,8 +86,8 @@
 		rose_neigh->number    = rose_neigh_no++;
 		rose_neigh->restarted = 0;
 		skb_queue_head_init(&rose_neigh->queue);
-		rose_neigh->t0        = sysctl_rose_restart_request_timeout;
 		rose_neigh->t0timer   = 0;
+		rose_neigh->ftimer    = 0;
 		init_timer(&rose_neigh->timer);
 
 		if (rose_route->ndigis != 0) {
@@ -114,10 +114,10 @@
 	 * best match.
 	 */
 	if (rose_node == NULL) {
-
 		rose_tmpn = rose_node_list;
 		rose_tmpp = NULL;
-		while(rose_tmpn != NULL) {
+
+		while (rose_tmpn != NULL) {
 			if (rose_tmpn->mask > rose_route->mask) {
 				rose_tmpp = rose_tmpn;
 				rose_tmpn = rose_tmpn->next;
@@ -132,7 +132,6 @@
 
 		rose_node->address = rose_route->address;
 		rose_node->mask    = rose_route->mask;
-		rose_node->which   = 0;
 		rose_node->count   = 1;
 		rose_node->neighbour[0] = rose_neigh;
 
@@ -163,13 +162,9 @@
 		return 0;
 	}
 
-	/* We have space at the bottom, slot it in */
+	/* We have space, slot it in */
 	if (rose_node->count < 3) {
-		rose_node->neighbour[2] = rose_node->neighbour[1];
-		rose_node->neighbour[1] = rose_node->neighbour[0];
-
-		rose_node->neighbour[0] = rose_neigh;
-
+		rose_node->neighbour[rose_node->count] = rose_neigh;
 		rose_node->count++;
 		rose_neigh->count++;
 	}
@@ -302,7 +297,7 @@
 
 			if (rose_neigh->count == 0)
 				rose_remove_neigh(rose_neigh);
-				
+
 			rose_node->count--;
 
 			if (rose_node->count == 0) {
@@ -436,6 +431,7 @@
 struct rose_neigh *rose_get_neigh(rose_address *addr)
 {
 	struct rose_node *node;
+	int i;
 
 	for (node = rose_node_list; node != NULL; node = node->next)
 		if (rosecmpm(addr, &node->address, node->mask) == 0)
@@ -443,9 +439,11 @@
 
 	if (node == NULL) return NULL;
 
-	if (node->which >= node->count) return NULL;
+	for (i = 0; i < node->count; i++)
+		if (node->neighbour[i]->ftimer == 0)
+			return node->neighbour[i];
 
-	return node->neighbour[node->which];
+	return NULL;
 }
 
 /*
@@ -494,25 +492,22 @@
 void rose_link_failed(ax25_address *callsign, struct device *dev)
 {
 	struct rose_neigh *rose_neigh;
-	struct rose_node  *rose_node;
 	struct sk_buff    *skb;
 
 	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
 		if (ax25cmp(&rose_neigh->callsign, callsign) == 0 && rose_neigh->dev == dev)
 			break;
-			
+
 	if (rose_neigh == NULL) return;
 
 	rose_neigh->restarted = 0;
 	rose_neigh->t0timer   = 0;
-	del_timer(&rose_neigh->timer);
+	rose_neigh->ftimer    = sysctl_rose_link_fail_timeout;
+
+	rose_link_set_timer(rose_neigh);
 
 	while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
-
-	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
-		if (rose_node->which < rose_node->count && rose_node->neighbour[rose_node->which] == rose_neigh)
-			rose_node->which++;
 }
 
 /*
@@ -521,35 +516,29 @@
 void rose_link_device_down(struct device *dev)
 {
 	struct rose_neigh *rose_neigh;
-	struct rose_node  *rose_node;
 	struct sk_buff    *skb;
 
 	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
 		if (rose_neigh->dev == dev) {
 			rose_neigh->restarted = 0;
 			rose_neigh->t0timer   = 0;
+			rose_neigh->ftimer    = 0;
 			del_timer(&rose_neigh->timer);
 
 			while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
 				kfree_skb(skb, FREE_WRITE);
-	
-			for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
-				if (rose_node->which < rose_node->count && rose_node->neighbour[rose_node->which] == rose_neigh)
-					rose_node->which++;
 		}
 	}
 }
 
 /*
- *	Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
- *	indicates an internally generated frame.
+ *	Route a frame to an appropriate AX.25 connection.
  */
 int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
 {
 	struct rose_neigh *rose_neigh, *new_neigh;
-	struct rose_node  *rose_node;
 	struct rose_route *rose_route;
-	rose_address *dest_addr;
+	rose_address *src_addr, *dest_addr;
 	struct sock *sk;
 	unsigned short frametype;
 	unsigned int lci;
@@ -563,6 +552,8 @@
 
 	frametype = skb->data[2];
 	lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
+	src_addr  = (rose_address *)(skb->data + 9);
+	dest_addr = (rose_address *)(skb->data + 4);
 
 	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
 		if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->device == rose_neigh->dev)
@@ -572,6 +563,11 @@
 		return 0;
 
 	/*
+	 *	Obviously the link is working, halt the ftimer.
+	 */
+	rose_neigh->ftimer = 0;
+
+	/*
 	 *	LCI of zero is always for us, and its always a restart
 	 * 	frame.
 	 */
@@ -591,12 +587,9 @@
 	/*
 	 *	Is is a Call Request and is it for us ?
 	 */
-	if (frametype == ROSE_CALL_REQUEST) {
-		dest_addr = (rose_address *)(skb->data + 4);
-
+	if (frametype == ROSE_CALL_REQUEST)
 		if ((dev = rose_dev_get(dest_addr)) != NULL)
 			return rose_rx_call_request(skb, dev, rose_neigh, lci);
-	}
 
 	if (!sysctl_rose_routing_control) {
 		rose_transmit_clear_request(rose_neigh, lci, 0x0D);
@@ -640,18 +633,7 @@
 	if (frametype != ROSE_CALL_REQUEST)	/* XXX */
 		return 0;
 
-	dest_addr = (rose_address *)(skb->data + 4);
-
-	/*
-	 *	Create a new route entry, if we can.
-	 */
-	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
-		if (rosecmpm(dest_addr, &rose_node->address, rose_node->mask) == 0)
-			break;
-	/*
-	 *	Its an unknown node, or is unreachable.
-	 */
-	if (rose_node == NULL || rose_node->which >= rose_node->count) {
+	if ((new_neigh = rose_get_neigh(dest_addr)) == NULL) {
 		rose_transmit_clear_request(rose_neigh, lci, 0x0D);
 		return 0;
 	}
@@ -661,8 +643,6 @@
 		return 0;
 	}
 
-	new_neigh = rose_node->neighbour[rose_node->which];
-
 	rose_route->lci1   = lci;
 	rose_route->neigh1 = rose_neigh;
 	rose_route->lci2   = rose_new_lci(new_neigh->dev);
@@ -693,13 +673,12 @@
 
 	cli();
 
-	len += sprintf(buffer, "address    mask w n neigh neigh neigh\n");
+	len += sprintf(buffer, "address    mask n neigh neigh neigh\n");
 
 	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) {
-		len += sprintf(buffer + len, "%-10s %04d %d %d",
+		len += sprintf(buffer + len, "%-10s %04d %d",
 			rose2asc(&rose_node->address),
 			rose_node->mask,
-			rose_node->which + 1,
 			rose_node->count);			
 
 		for (i = 0; i < rose_node->count; i++)
@@ -739,17 +718,17 @@
 
 	cli();
 
-	len += sprintf(buffer, "addr  callsign  dev  count  restart     t0\n");
+	len += sprintf(buffer, "addr  callsign  dev  count  restart   t0   tf\n");
 
 	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
-		len += sprintf(buffer + len, "%05d %-9s %-4s   %3d      %3s  %3d/%03d\n",
+		len += sprintf(buffer + len, "%05d %-9s %-4s   %3d      %3s  %3d  %3d\n",
 			rose_neigh->number,
 			ax2asc(&rose_neigh->callsign),
 			rose_neigh->dev ? rose_neigh->dev->name : "???",
 			rose_neigh->count,
 			(rose_neigh->restarted) ? "yes" : "no",
 			rose_neigh->t0timer / ROSE_SLOWHZ,
-			rose_neigh->t0      / ROSE_SLOWHZ);
+			rose_neigh->ftimer  / ROSE_SLOWHZ);
 
 		pos = begin + len;
 
diff -u --recursive --new-file v2.1.24/linux/net/rose/rose_timer.c linux/net/rose/rose_timer.c
--- v2.1.24/linux/net/rose/rose_timer.c	Thu Jan 23 21:06:59 1997
+++ linux/net/rose/rose_timer.c	Sun Feb  2 15:18:52 1997
@@ -43,37 +43,20 @@
 static void rose_timer(unsigned long);
 
 /*
- *	Linux set/reset timer routines
+ *	Linux set timer
  */
 void rose_set_timer(struct sock *sk)
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
-	del_timer(&sk->timer);
-	restore_flags(flags);
-
-	sk->timer.next     = sk->timer.prev = NULL;	
-	sk->timer.data     = (unsigned long)sk;
-	sk->timer.function = &rose_timer;
-
-	sk->timer.expires = jiffies + 10;
-	add_timer(&sk->timer);
-}
-
-static void rose_reset_timer(struct sock *sk)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
+	save_flags(flags); cli();
 	del_timer(&sk->timer);
 	restore_flags(flags);
 
 	sk->timer.data     = (unsigned long)sk;
 	sk->timer.function = &rose_timer;
 	sk->timer.expires  = jiffies + 10;
+
 	add_timer(&sk->timer);
 }
 
@@ -121,7 +104,7 @@
 	}
 
 	if (sk->protinfo.rose->timer == 0 || --sk->protinfo.rose->timer > 0) {
-		rose_reset_timer(sk);
+		rose_set_timer(sk);
 		return;
 	}
 
diff -u --recursive --new-file v2.1.24/linux/net/rose/sysctl_net_rose.c linux/net/rose/sysctl_net_rose.c
--- v2.1.24/linux/net/rose/sysctl_net_rose.c	Thu Jan 23 21:06:59 1997
+++ linux/net/rose/sysctl_net_rose.c	Sun Feb  2 15:18:52 1997
@@ -10,12 +10,13 @@
 #include <net/ax25.h>
 #include <net/rose.h>
 
-static int min_timer[] = {1 * ROSE_SLOWHZ};
-static int max_timer[] = {300 * ROSE_SLOWHZ};
-static int min_idle[]  = {0 * ROSE_SLOWHZ};
-static int max_idle[]  = {65535 * ROSE_SLOWHZ};
-static int min_route[] = {0};
-static int max_route[] = {1};
+static int min_timer[]  = {1 * ROSE_SLOWHZ};
+static int max_timer[]  = {300 * ROSE_SLOWHZ};
+static int min_idle[]   = {0 * ROSE_SLOWHZ};
+static int max_idle[]   = {65535 * ROSE_SLOWHZ};
+static int min_route[]  = {0}, max_route[] = {1};
+static int min_ftimer[] = {60 * ROSE_SLOWHZ};
+static int max_ftimer[] = {600 * ROSE_SLOWHZ};
 
 static struct ctl_table_header *rose_table_header;
 
@@ -41,6 +42,9 @@
         {NET_ROSE_ROUTING_CONTROL, "routing_control",
          &sysctl_rose_routing_control, sizeof(int), 0644, NULL,
          &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_route, &max_route},
+        {NET_ROSE_LINK_FAIL_TIMEOUT, "link_fail_timeout",
+         &sysctl_rose_link_fail_timeout, sizeof(int), 0644, NULL,
+         &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_ftimer, &max_ftimer},
 	{0}
 };
 
diff -u --recursive --new-file v2.1.24/linux/net/socket.c linux/net/socket.c
--- v2.1.24/linux/net/socket.c	Tue Jan 28 18:50:59 1997
+++ linux/net/socket.c	Sun Feb  2 15:18:52 1997
@@ -35,6 +35,9 @@
  *		Alan Cox	:	sendmsg/recvmsg basics.
  *		Tom Dyas	:	Export net symbols.
  *		Marcin Dalecki	:	Fixed problems with CONFIG_NET="n".
+ *		Alan Cox	:	Added thread locking to sys_* calls
+ *					for sockets. May have errors at the
+ *					moment.
  *
  *
  *		This program is free software; you can redistribute it and/or
@@ -46,14 +49,6 @@
  *	This module is effectively the top level interface to the BSD socket
  *	paradigm. 
  *
- * PROBLEMS:
- *	- CLONE_FILES. Big problem, cloned thread can close file,
- *	  while other thread sleeps in kernel. It can be solved
- *	  by increasing f_count and releasing it on exit from syscall.
- *	  _HAS_ to be fixed before 2.2 is released. I assume whoever is
- *	  working on the CLONE stuff will fix that pile of accidents. If
- *	  you find this comment in a 2.2-preXXX kernel scream loudly.
- *
  */
 
 #include <linux/config.h>
@@ -68,11 +63,13 @@
 #include <linux/stat.h>
 #include <linux/socket.h>
 #include <linux/fcntl.h>
+#include <linux/file.h>
 #include <linux/net.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/firewall.h>
+#include <linux/wanrouter.h>
 
 #if defined(CONFIG_KERNELD) && defined(CONFIG_NET)
 #include <linux/kerneld.h>
@@ -232,7 +229,7 @@
 	struct file *file;
 	struct inode *inode;
 
-	if (fd < 0 || fd >= NR_OPEN || !(file = current->files->fd[fd]))
+	if (!(file = fget(fd)))
 	{
 		*err = -EBADF;
 		return NULL;
@@ -242,12 +239,18 @@
 	if (!inode || !inode->i_sock || !socki_lookup(inode))
 	{
 		*err = -ENOTSOCK;
+		fput(file,inode);
 		return NULL;
 	}
 
 	return socki_lookup(inode);
 }
 
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file,sock->inode);
+}
+
 /*
  *	Allocate a socket.
  */
@@ -713,22 +716,16 @@
 asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen)
 {
 	struct socket *sock;
-	int i;
 	char address[MAX_SOCK_ADDR];
 	int err;
 
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd,&err))) 
-		goto out;
-  
-	if((err=move_addr_to_kernel(umyaddr,addrlen,address))<0)
-	  	goto out;
-  
-	if ((i = sock->ops->bind(sock, (struct sockaddr *)address, addrlen)) < 0) 
-		err = i;
-	else
-		err = 0;
-out:
+	if((sock = sockfd_lookup(fd,&err))!=NULL)
+	{
+		if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0)
+			err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen);
+		sockfd_put(sock);
+	}			
 	unlock_kernel();
 	return err;
 }
@@ -743,15 +740,14 @@
 asmlinkage int sys_listen(int fd, int backlog)
 {
 	struct socket *sock;
-	int err=-EOPNOTSUPP;
+	int err;
 	
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd, &err))) 
-		goto out;
-
-	if (sock->ops && sock->ops->listen)
+	if((sock = sockfd_lookup(fd, &err))!=NULL)
+	{
 		err=sock->ops->listen(sock, backlog);
-out:
+		sockfd_put(sock);
+	}
 	unlock_kernel();
 	return err;
 }
@@ -778,54 +774,50 @@
 	int len;
 
 	lock_kernel();
-  	if (!(sock = sockfd_lookup(fd, &err)))
-		goto out;
-	err = -EOPNOTSUPP;
-	if (!sock->ops->accept)
-		goto out;
-
-	err = -ENOSR;
-	if (!(newsock = sock_alloc())) 
-	{
-		printk(KERN_WARNING "accept: no more sockets\n");
-		goto out;	/* Was: EAGAIN, but we are out of system
-				   resources! */
-	}
+  	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+  	{
+		if (!(newsock = sock_alloc())) 
+		{
+			printk(KERN_WARNING "accept: no more sockets\n");
+			err=-EMFILE;
+			goto out;
+		}
 
-	inode = newsock->inode;
-	newsock->type = sock->type;
+		inode = newsock->inode;
+		newsock->type = sock->type;
 
-	if ((err = sock->ops->dup(newsock, sock)) < 0) 
-	{
-		sock_release(newsock);
-		goto out;
-	}
+		if ((err = sock->ops->dup(newsock, sock)) < 0) 
+		{
+			sock_release(newsock);
+			goto out;
+		}
 
-	err = newsock->ops->accept(sock, newsock, current->files->fd[fd]->f_flags);
+		err = newsock->ops->accept(sock, newsock, current->files->fd[fd]->f_flags);
 
-	if (err < 0)
-	{
-		sock_release(newsock);
-		goto out;
-	}
-	newsock = socki_lookup(inode);
+		if (err < 0)
+		{
+			sock_release(newsock);
+			goto out;
+		}
+		newsock = socki_lookup(inode);
 
-	if ((fd = get_fd(inode)) < 0) 
-	{
-		sock_release(newsock);
-		err = -EINVAL;
-		goto out;
-	}
+		if ((err = get_fd(inode)) < 0) 
+		{
+			sock_release(newsock);
+			err=-EINVAL;
+			goto out;
+		}
 
-	newsock->file = current->files->fd[fd];
+		newsock->file = current->files->fd[err];
 	
-	if (upeer_sockaddr)
-	{
-		newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1);
-		move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen);
-	}
-	err = fd;
+		if (upeer_sockaddr)
+		{
+			newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1);
+			move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen);
+		}
 out:
+		sockfd_put(sock);		
+	}
 	unlock_kernel();
 	return err;
 }
@@ -850,17 +842,13 @@
 	int err;
 
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd,&err)))
-		goto out;
-
-	if((err=move_addr_to_kernel(uservaddr,addrlen,address))<0)
-	  	goto out;
-  
-	err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen,
+	if ((sock = sockfd_lookup(fd,&err))!=NULL)
+	{
+		if((err=move_addr_to_kernel(uservaddr,addrlen,address))>=0)
+			err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen,
 			     current->files->fd[fd]->f_flags);
-	if (err >= 0)
-		err = 0;
-out:
+		sockfd_put(sock);
+	}
 	unlock_kernel();
 	return err;
 }
@@ -878,16 +866,12 @@
 	int err;
 	
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd, &err)))
-		goto out;
-
-	err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 0);
-	if(err)
-		goto out;
-	if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0)
-	  	goto out;
-	err = 0;
-out:
+	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+	{
+		if((err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 0))==0)
+			err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
+		sockfd_put(sock);
+	}
 	unlock_kernel();
 	return err;
 }
@@ -905,16 +889,12 @@
 	int err;
 
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd, &err)))
-		goto out;
-
-	err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
-	if(err)
-	  	goto out;
-	if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0)
-	  	goto out;
-	err = 0;
-out:
+	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+	{
+		if((err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1))==0)
+			err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
+		sockfd_put(sock);
+	}
 	unlock_kernel();
 	return err;
 }
@@ -932,30 +912,27 @@
 	struct iovec iov;
 
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd, &err))) 
-		goto out;
-
-	err = -EINVAL;
-	if(len<0)
-		goto out;
-	err=verify_area(VERIFY_READ, buff, len);
-	if(err)
-		goto out;
-		
-	iov.iov_base=buff;
-	iov.iov_len=len;
-	msg.msg_name=NULL;
-	msg.msg_namelen=0;
-	msg.msg_iov=&iov;
-	msg.msg_iovlen=1;
-	msg.msg_control=NULL;
-	msg.msg_controllen=0;
-	if (current->files->fd[fd]->f_flags & O_NONBLOCK)
-		flags |= MSG_DONTWAIT;
-	msg.msg_flags=flags;
-
-	err = sock_sendmsg(sock, &msg, len);
-out:
+	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+	{
+		if(len>=0)
+		{
+			iov.iov_base=buff;
+			iov.iov_len=len;
+			msg.msg_name=NULL;
+			msg.msg_namelen=0;
+			msg.msg_iov=&iov;
+			msg.msg_iovlen=1;
+			msg.msg_control=NULL;
+			msg.msg_controllen=0;
+			if (current->files->fd[fd]->f_flags & O_NONBLOCK)
+				flags |= MSG_DONTWAIT;
+			msg.msg_flags=flags;
+			err=sock_sendmsg(sock, &msg, len);
+		}
+		else
+			err=-EINVAL;
+		sockfd_put(sock);
+	}
 	unlock_kernel();
 	return err;
 }
@@ -976,35 +953,30 @@
 	struct iovec iov;
 	
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd,&err)))
-		goto out;
-
-	err=verify_area(VERIFY_READ,buff,len);
-	if(err)
-	  	goto out;
-
-	iov.iov_base=buff;
-	iov.iov_len=len;
-	msg.msg_name=NULL;
-	msg.msg_iov=&iov;
-	msg.msg_iovlen=1;
-	msg.msg_control=NULL;
-	msg.msg_controllen=0;
-	msg.msg_namelen=addr_len;
-	if(addr)
+	if ((sock = sockfd_lookup(fd,&err))!=NULL)
 	{
-		err=move_addr_to_kernel(addr,addr_len,address);
-		if (err < 0)
-			goto out;
-		msg.msg_name=address;
+		iov.iov_base=buff;
+		iov.iov_len=len;
+		msg.msg_name=NULL;
+		msg.msg_iov=&iov;
+		msg.msg_iovlen=1;
+		msg.msg_control=NULL;
+		msg.msg_controllen=0;
+		msg.msg_namelen=addr_len;
+		if(addr)
+		{
+			err=move_addr_to_kernel(addr,addr_len,address);
+			if (err < 0)
+				goto bad;
+			msg.msg_name=address;
+		}
+		if (current->files->fd[fd]->f_flags & O_NONBLOCK)
+			flags |= MSG_DONTWAIT;
+		msg.msg_flags=flags;
+		err=sock_sendmsg(sock, &msg, len);
+bad:		
+		sockfd_put(sock);
 	}
-
-	if (current->files->fd[fd]->f_flags & O_NONBLOCK)
-		flags |= MSG_DONTWAIT;
-	msg.msg_flags=flags;
-
-	err = sock_sendmsg(sock, &msg, len);
-out:
 	unlock_kernel();
 	return err;
 }
@@ -1022,28 +994,20 @@
 	int err;
 
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd, &err))) 
-		goto out;
-
-	err = 0;
-	if(size==0)
-		goto out;
-	err=verify_area(VERIFY_WRITE, ubuf, size);
-	if(err)
-		goto out;
-
-	msg.msg_name=NULL;
-	msg.msg_iov=&iov;
-	msg.msg_iovlen=1;
-	msg.msg_control=NULL;
-	msg.msg_controllen=0;
-	iov.iov_base=ubuf;
-	iov.iov_len=size;
-
-	err = sock_recvmsg(sock, &msg, size,
-			   (current->files->fd[fd]->f_flags & O_NONBLOCK)
-			   ? flags | MSG_DONTWAIT : flags);
-out:
+	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+	{		
+		msg.msg_name=NULL;
+		msg.msg_iov=&iov;
+		msg.msg_iovlen=1;
+		msg.msg_control=NULL;
+		msg.msg_controllen=0;
+		iov.iov_base=ubuf;
+		iov.iov_len=size;
+
+		err=sock_recvmsg(sock, &msg, size,
+			    (current->files->fd[fd]->f_flags & O_NONBLOCK) ? flags | MSG_DONTWAIT : flags);
+		sockfd_put(sock);
+	}
 	unlock_kernel();
 	return err;
 }
@@ -1061,39 +1025,29 @@
 	struct iovec iov;
 	struct msghdr msg;
 	char address[MAX_SOCK_ADDR];
-	int err;
+	int err,err2;
 
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd, &err)))
-	  	goto out;
-	err = 0;
-	if (size==0)
-		goto out;
-
-	err=verify_area(VERIFY_WRITE,ubuf,size);
-	if(err)
-	  	goto out;
-
-  	msg.msg_control=NULL;
-  	msg.msg_controllen=0;
-  	msg.msg_iovlen=1;
-  	msg.msg_iov=&iov;
-  	iov.iov_len=size;
-  	iov.iov_base=ubuf;
-  	msg.msg_name=address;
-  	msg.msg_namelen=MAX_SOCK_ADDR;
-	err = sock_recvmsg(sock, &msg, size,
-			   (current->files->fd[fd]->f_flags & O_NONBLOCK)
-			   ? (flags | MSG_DONTWAIT) : flags);
-
-	if(err<0)
-	 	goto out;
-	size=err;
-	if(addr!=NULL &&
-	   (err=move_addr_to_user(address, msg.msg_namelen, addr, addr_len))<0)
-	  	goto out;
-	err = size;
-out:
+	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+	{  
+  		msg.msg_control=NULL;
+  		msg.msg_controllen=0;
+  		msg.msg_iovlen=1;
+  		msg.msg_iov=&iov;
+  		iov.iov_len=size;
+  		iov.iov_base=ubuf;
+  		msg.msg_name=address;
+  		msg.msg_namelen=MAX_SOCK_ADDR;
+		err=sock_recvmsg(sock, &msg, size,
+			  (current->files->fd[fd]->f_flags & O_NONBLOCK) ? (flags | MSG_DONTWAIT) : flags);
+		if(err>=0 && addr!=NULL)
+		{
+			err2=move_addr_to_user(address, msg.msg_namelen, addr, addr_len);
+			if(err2<0)
+				err=err2;
+		}
+		sockfd_put(sock);			
+	}		
 	unlock_kernel();
 	return err;
 }
@@ -1109,16 +1063,14 @@
 	struct socket *sock;
 	
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd, &err))) 
-		goto out;
-
-	if (level == SOL_SOCKET)
-		err = sock_setsockopt(sock,level,optname,optval,optlen);
-	else if (sock->ops->setsockopt)
-		err = sock->ops->setsockopt(sock, level, optname, optval, optlen);
-	else
-		err = -EOPNOTSUPP;
-out:
+	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+	{
+		if (level == SOL_SOCKET)
+			err=sock_setsockopt(sock,level,optname,optval,optlen);
+		else
+			err=sock->ops->setsockopt(sock, level, optname, optval, optlen);
+		sockfd_put(sock);
+	}
 	unlock_kernel();
 	return err;
 }
@@ -1134,16 +1086,14 @@
 	struct socket *sock;
 
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd, &err)))
-		goto out;
-	    
-	if (level == SOL_SOCKET)
-		err = sock_getsockopt(sock,level,optname,optval,optlen);
-	else if (sock->ops->getsockopt)
-		err = sock->ops->getsockopt(sock, level, optname, optval, optlen);
-	else
-		err = -EOPNOTSUPP;
-out:
+	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+	{
+		if (level == SOL_SOCKET)
+			err=sock_getsockopt(sock,level,optname,optval,optlen);
+		else
+			err=sock->ops->getsockopt(sock, level, optname, optval, optlen);
+		sockfd_put(sock);
+	}
 	unlock_kernel();
 	return err;
 }
@@ -1159,12 +1109,11 @@
 	struct socket *sock;
 
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd, &err))) 
-		goto out;
-
-	err = sock->ops->shutdown(sock, how);
-out:
-	unlock_kernel();
+	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+	{
+		err=sock->ops->shutdown(sock, how);
+		sockfd_put(sock);
+	}
 	return err;
 }
 
@@ -1179,36 +1128,32 @@
 	struct iovec iov[UIO_FASTIOV];
 	unsigned char ctl[sizeof(struct cmsghdr) + 20];	/* 20 is size of ipv6_pktinfo */
 	struct msghdr msg_sys;
-	int err;
+	int err= -EINVAL;
 	int total_len;
 	
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd,&err)))
-		goto out;
-	
-	err = -EOPNOTSUPP;
-	if (sock->ops->sendmsg==NULL)
-		goto out;
 
-	err = -EFAULT;
 	if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
-		goto out;
-
+	{
+		err=-EFAULT;
+		goto out; 
+	}
 	/* do not move before msg_sys is valid */
-	err = -EINVAL;
 	if (msg_sys.msg_iovlen>UIO_MAXIOV)
 		goto out;
-
 	/* This will also move the address data into kernel space */
 	err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
 	if (err < 0)
 		goto out;
 	total_len=err;
 
-	if (msg_sys.msg_controllen) {
-		if (msg_sys.msg_controllen > sizeof(ctl)) {
+	if (msg_sys.msg_controllen) 
+	{
+		if (msg_sys.msg_controllen > sizeof(ctl)) 
+		{
 			char *tmp = kmalloc(msg_sys.msg_controllen, GFP_KERNEL);
-			if (tmp == NULL) {
+			if (tmp == NULL) 
+			{
 				err = -ENOBUFS;
 				goto failed2;
 			}
@@ -1221,12 +1166,15 @@
 		if (err)
 			goto failed;
 	}
-
 	msg_sys.msg_flags = flags;
 	if (current->files->fd[fd]->f_flags & O_NONBLOCK)
 		msg_sys.msg_flags |= MSG_DONTWAIT;
 
-	err = sock_sendmsg(sock, &msg_sys, total_len);
+	if ((sock = sockfd_lookup(fd,&err))!=NULL)
+	{
+		err = sock_sendmsg(sock, &msg_sys, total_len);
+		sockfd_put(sock);
+	}
 
 failed:
 	if (msg_sys.msg_controllen && msg_sys.msg_control != ctl)
@@ -1262,17 +1210,17 @@
 	int *uaddr_len;
 	
 	lock_kernel();
-	if (!(sock = sockfd_lookup(fd, &err)))
-		goto out;
-
-	err = -EFAULT;
 	if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
-		goto out; 
-
-	err = -EINVAL;
+	{
+		err=-EFAULT;
+		goto out;
+	}
 	if (msg_sys.msg_iovlen>UIO_MAXIOV)
+	{
+		err=-EFAULT;
 		goto out;
-
+	}
+	
 	/*
 	 *	Save the user-mode address (verify_iovec will change the
 	 *	kernel msghdr to use the kernel address space)
@@ -1291,34 +1239,35 @@
 	
 	if (current->files->fd[fd]->f_flags&O_NONBLOCK)
 		flags |= MSG_DONTWAIT;
-	len=sock_recvmsg(sock, &msg_sys, total_len, flags);
+
+
+	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+	{
+		err=sock_recvmsg(sock, &msg_sys, total_len, flags);
+		if(err>=0)
+			len=err;
+		sockfd_put(sock);
+	}
 	if (msg_sys.msg_iov != iov)
 		kfree(msg_sys.msg_iov);
-	if (len<0) {
-		err = len;
-		goto out;
-	}
 
-	if (uaddr != NULL)
-	{
+	if (uaddr != NULL && err>=0)
 		err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
-		if (err)
-			goto out;
-	}
-	err = -EFAULT;
-	if (put_user(msg_sys.msg_flags, &msg->msg_flags))
-		goto out;
-	if (put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen))
-		goto out;
-	err = len;
+	if (err>=0 && (put_user(msg_sys.msg_flags, &msg->msg_flags) || 
+		put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen)))
+		err = -EFAULT;
 out:
 	unlock_kernel();
-	return err;
+	if(err<0)
+		return err;
+	return len;
 }
 
 
 /*
  *	Perform a file control on a socket file descriptor.
+ *
+ *	FIXME: does this need an fd lock ?
  */
 
 int sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg)
@@ -1356,6 +1305,12 @@
 	if(call<1||call>SYS_RECVMSG)
 		goto out;
 	err = -EFAULT;
+
+	/*
+	 *	Ideally we want to precompute the maths, but unsigned long
+	 *	isnt a fixed size....
+	 */
+	 
 	if ((copy_from_user(a, args, nargs[call] * sizeof(unsigned long))))
 		goto out;
 		
@@ -1478,7 +1433,8 @@
 	 *	Initialize all address (protocol) families. 
 	 */
 	 
-	for (i = 0; i < NPROTO; i++) net_families[i] = NULL;
+	for (i = 0; i < NPROTO; i++) 
+		net_families[i] = NULL;
 
 	/*
 	 *	Initialize sock SLAB cache.
@@ -1492,6 +1448,14 @@
 
 #ifdef CONFIG_NETLINK
 	init_netlink();
+#endif
+
+	/*
+	 *	Wan router layer. 
+	 */
+
+#ifdef CONFIG_WAN_ROUTER	 
+	wanrouter_init();
 #endif
 
 	/*
diff -u --recursive --new-file v2.1.24/linux/net/wanrouter/Makefile linux/net/wanrouter/Makefile
--- v2.1.24/linux/net/wanrouter/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/net/wanrouter/Makefile	Sun Feb  2 15:18:52 1997
@@ -0,0 +1,17 @@
+#
+# Makefile for the Linux WAN router layer.
+#
+# 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).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := wanrouter.o
+O_OBJS   := wanmain.o wanproc.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
+
+tar:
+	tar -cvf /dev/f1 .
diff -u --recursive --new-file v2.1.24/linux/net/wanrouter/patchlevel linux/net/wanrouter/patchlevel
--- v2.1.24/linux/net/wanrouter/patchlevel	Thu Jan  1 02:00:00 1970
+++ linux/net/wanrouter/patchlevel	Sun Feb  2 15:18:52 1997
@@ -0,0 +1 @@
+1.0.0
diff -u --recursive --new-file v2.1.24/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c
--- v2.1.24/linux/net/wanrouter/wanmain.c	Thu Jan  1 02:00:00 1970
+++ linux/net/wanrouter/wanmain.c	Sun Feb  2 15:18:52 1997
@@ -0,0 +1,676 @@
+/*****************************************************************************
+* wanmain.c	WAN Multiprotocol Router Module. Main code.
+*
+*		This module is completely hardware-independent and provides
+*		the following common services for the WAN Link Drivers:
+*		 o WAN device managenment (registering, unregistering)
+*		 o Network interface management
+*		 o Physical connection management (dial-up, incomming calls)
+*		 o Logical connection management (switched virtual circuits)
+*		 o Protocol encapsulation/decapsulation
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*
+* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Dec 27, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
+* Jan 31, 1997  Alan Cox	Hacked it about a bit for 2.1
+*****************************************************************************/
+
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/config.h>	/* OS configuration options */
+#include <linux/kernel.h>
+#include <linux/module.h>	/* support for loadable modules */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/mm.h>		/* verify_area(), etc. */
+#include <linux/string.h>	/* inline mem*, str* functions */
+#include <asm/segment.h>	/* kernel <-> user copy */
+#include <asm/byteorder.h>	/* htons(), etc. */
+#include <asm/uaccess.h>	/* copy_to/from_user */
+#include <linux/wanrouter.h>	/* WAN router API definitions */
+
+/****** Defines and Macros **************************************************/
+
+#ifndef	min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef	max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+/****** Function Prototypes *************************************************/
+
+/*
+ *	Kernel loadable module interface.
+ */
+
+#ifdef MODULE
+int init_module (void);
+void cleanup_module (void);
+#endif
+
+/*
+ *	WAN device IOCTL handlers 
+ */
+
+static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf);
+static int device_stat (wan_device_t* wandev, wandev_stat_t* u_stat);
+static int device_shutdown (wan_device_t* wandev);
+static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf);
+static int device_del_if (wan_device_t* wandev, char* u_name);
+
+/*
+ *	Miscellaneous 
+ */
+
+static wan_device_t* find_device (char* name);
+static int delete_interface (wan_device_t* wandev, char* name, int forse);
+
+/*
+ *	Global Data
+ */
+
+static char fullname[]		= "WAN Router";
+static char copyright[]		= "(c) 1995-1996 Sangoma Technologies Inc.";
+static char modname[]		= ROUTER_NAME;	/* short module name */
+static wan_device_t* devlist	= NULL;	/* list of registered devices */
+static int devcnt		= 0;
+
+/*
+ *	Organizationally Unique Identifiers for encapsulation/decapsulation
+ */
+ 
+static unsigned char oui_ether[] = { 0x00, 0x00, 0x00 };
+static unsigned char oui_802_2[] = { 0x00, 0x80, 0xC2 };
+
+#ifdef MODULE
+
+/*
+ *	Kernel Loadable Module Entry Points
+ */
+
+/*
+ *	Module 'insert' entry point.
+ *	o print announcement
+ *	o initialize static data
+ *	o create /proc/net/router directory and static entries
+ *
+ *	Return:	0	Ok
+ *		< 0	error.
+ *	Context:	process
+ */
+
+int init_module	(void)
+{
+	int err;
+
+	printk(KERN_INFO "%s v%u.%u %s\n",
+		fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright);
+	err = wanrouter_proc_init();
+	if (err) printk(KERN_ERR
+		"%s: can't create entry in proc filesystem!\n", modname);
+	return err;
+}
+
+/*
+ *	Module 'remove' entry point.
+ *	o delete /proc/net/router directory and static entries.
+ */
+ 
+void cleanup_module (void)
+{
+	wanrouter_proc_cleanup();
+}
+
+#else
+
+void wanrouter_init(void)
+{
+	int err = wanrouter_proc_init();
+	if (err) printk(KERN_ERR
+		"%s: can't create entry in proc filesystem!\n", modname);
+}
+#endif
+
+/*
+ *	Kernel APIs
+ */
+
+/*
+ *	Register WAN device.
+ *	o verify device credentials
+ *	o create an entry for the device in the /proc/net/router directory
+ *	o initialize internally maintained fields of the wan_device structure
+ *	o link device data space to a singly-linked list
+ *	o if it's the first device, then start kernel 'thread'
+ *	o increment module use count
+ *
+ *	 Return:
+ *		0	Ok
+ *		< 0	error.
+ *
+ *	Context:	process
+ */
+
+int register_wan_device(wan_device_t* wandev)
+{
+	int err, namelen;
+
+	if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC) ||
+	    (wandev->name == NULL))
+		return -EINVAL;
+		
+	namelen = strlen(wandev->name);
+	if (!namelen || (namelen > WAN_DRVNAME_SZ))
+		return -EINVAL;
+		
+	if (find_device(wandev->name) != NULL)
+		return -EEXIST;
+
+#ifdef WANDEBUG		
+	printk(KERN_INFO "%s: registering WAN device %s\n",
+		modname, wandev->name);
+#endif
+
+	/*
+	 *	Register /proc directory entry 
+	 */
+	err = wanrouter_proc_add(wandev);
+	if (err)
+	{
+		printk(KERN_ERR
+			"%s: can't create /proc/net/router/%s entry!\n",
+			modname, wandev->name)
+		;
+		return err;
+	}
+
+	/*
+	 *	Initialize fields of the wan_device structure maintained by the
+	 *	router and update local data.
+	 */
+	 
+	wandev->ndev = 0;
+	wandev->dev  = NULL;
+	wandev->next = devlist;
+	devlist = wandev;
+	++devcnt;
+        MOD_INC_USE_COUNT;	/* prevent module from unloading */
+	return 0;
+}
+
+/*
+ *	Unregister WAN device.
+ *	o shut down device
+ *	o unlink device data space from the linked list
+ *	o delete device entry in the /proc/net/router directory
+ *	o decrement module use count
+ *
+ *	Return:		0	Ok
+ *			<0	error.
+ *	Context:	process
+ */
+ 
+int unregister_wan_device(char* name)
+{
+	wan_device_t *wandev, *prev;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	for (wandev = devlist, prev = NULL;
+		wandev && strcmp(wandev->name, name);
+		prev = wandev, wandev = wandev->next)
+		;
+	if (wandev == NULL)
+		return -ENODEV;
+
+#ifdef WANDEBUG		
+	printk(KERN_INFO "%s: unregistering WAN device %s\n", modname, name);
+#endif
+	
+	if (wandev->state != WAN_UNCONFIGURED)
+	{
+		while(wandev->dev)
+			delete_interface(wandev, wandev->dev->name, 1);
+		if (wandev->shutdown)	
+			wandev->shutdown(wandev);
+	}
+	if (prev)
+		prev->next = wandev->next;
+	else
+		devlist = wandev->next;
+	--devcnt;
+	wanrouter_proc_delete(wandev);
+        MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ *	Encapsulate packet.
+ *
+ *	Return:	encapsulation header size
+ *		< 0	- unsupported Ethertype
+ *
+ *	Notes:
+ *	1. This function may be called on interrupt context.
+ */
+
+int wanrouter_encapsulate (struct sk_buff* skb, struct device* dev)
+{
+	int hdr_len = 0;
+
+	switch (skb->protocol)
+	{
+	case ETH_P_IP:		/* IP datagram encapsulation */
+		hdr_len += 1;
+		skb_push(skb, 1);
+		skb->data[0] = NLPID_IP;
+		break;
+
+	case ETH_P_IPX:		/* SNAP encapsulation */
+	case ETH_P_ARP:
+		hdr_len += 6;
+		skb_push(skb, 6);
+		skb->data[0] = NLPID_SNAP;
+		memcpy(&skb->data[1], oui_ether, sizeof(oui_ether));
+		*((unsigned short*)&skb->data[4]) = htons(skb->protocol);
+		break;
+
+	default:		/* Unknown packet type */
+		printk(KERN_INFO
+			"%s: unsupported Ethertype 0x%04X on interface %s!\n",
+			modname, skb->protocol, dev->name);
+		hdr_len = -EINVAL;
+	}
+	return hdr_len;
+}
+
+/*
+ *	Decapsulate packet.
+ *
+ *	Return:	Ethertype (in network order)
+ *			0	unknown encapsulation
+ *
+ *	Notes:
+ *	1. This function may be called on interrupt context.
+ */
+
+unsigned short wanrouter_type_trans (struct sk_buff* skb, struct device* dev)
+{
+	int cnt = skb->data[0] ? 0 : 1;	/* there may be a pad present */
+	unsigned short ethertype;
+
+	switch (skb->data[cnt])
+	{
+	case NLPID_IP:		/* IP datagramm */
+		ethertype = htons(ETH_P_IP);
+		cnt += 1;
+		break;
+
+        case NLPID_SNAP:	/* SNAP encapsulation */
+		if (memcmp(&skb->data[cnt + 1], oui_ether, sizeof(oui_ether)))
+		{
+          		printk(KERN_INFO
+				"%s: unsupported SNAP OUI %02X-%02X-%02X "
+				"on interface %s!\n", modname,
+				skb->data[cnt+1], skb->data[cnt+2],
+				skb->data[cnt+3], dev->name);
+			;
+			return 0;
+		}	
+		ethertype = *((unsigned short*)&skb->data[cnt+4]);
+		cnt += 6;
+		break;
+
+	/* add other protocols, e.g. CLNP, ESIS, ISIS, if needed */
+
+	default:
+		printk(KERN_INFO
+			"%s: unsupported NLPID 0x%02X on interface %s!\n",
+			modname, skb->data[cnt], dev->name)
+		;
+		return 0;
+	}
+	skb->protocol = ethertype;
+	skb->pkt_type = PACKET_HOST;	/*	Physically point to point */
+	skb->mac.raw  = skb->data;
+	skb_pull(skb, cnt);
+	return ethertype;
+}
+
+/*
+ *	WAN device IOCTL.
+ *	o find WAN device associated with this node
+ *	o execute requested action or pass command to the device driver
+ */
+
+int wanrouter_ioctl(struct inode* inode, struct file* file,
+		unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	struct proc_dir_entry* dent;
+	wan_device_t* wandev;
+
+	if (!suser())
+		return -EPERM;
+		
+	if ((cmd >> 8) != ROUTER_IOCTL)
+		return -EINVAL;
+		
+	dent = inode->u.generic_ip;
+	if ((dent == NULL) || (dent->data == NULL))
+		return -EINVAL;
+		
+	wandev = dent->data;
+	if (wandev->magic != ROUTER_MAGIC)
+		return -EINVAL;
+		
+	switch (cmd)
+	{
+	case ROUTER_SETUP:
+		err = device_setup(wandev, (void*)arg);
+		break;
+
+	case ROUTER_DOWN:
+		err = device_shutdown(wandev);
+		break;
+
+	case ROUTER_STAT:
+		err = device_stat(wandev, (void*)arg);
+		break;
+
+	case ROUTER_IFNEW:
+		err = device_new_if(wandev, (void*)arg);
+		break;
+
+	case ROUTER_IFDEL:
+		err = device_del_if(wandev, (void*)arg);
+		break;
+
+	case ROUTER_IFSTAT:
+		break;
+
+	default:
+		if ((cmd >= ROUTER_USER) &&
+		    (cmd <= ROUTER_USER_MAX) &&
+		    wandev->ioctl)
+			err = wandev->ioctl(wandev, cmd, arg)
+		;
+		else err = -EINVAL;
+	}
+	return err;
+}
+
+/*
+ *	WAN Driver IOCTL Handlers
+ */
+
+/*
+ *	Setup WAN link device.
+ *	o verify user address space
+ *	o allocate kernel memory and copy configuration data to kernel space
+ *	o if configuration data includes extension, copy it to kernel space too
+ *	o call driver's setup() entry point
+ */
+
+static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf)
+{
+	void* data;
+	wandev_conf_t* conf;
+	int err= -EINVAL;
+
+	if (wandev->setup == NULL)	/* Nothing to do ? */
+		return 0;
+		
+	conf = kmalloc(sizeof(wandev_conf_t), GFP_KERNEL);
+	if (conf == NULL)
+		return -ENOBUFS;
+		
+	if(copy_from_user(conf, u_conf, sizeof(wandev_conf_t)))
+	{
+		kfree(conf);
+		return -EFAULT;
+	}
+	
+	if (conf->magic != ROUTER_MAGIC)
+		goto bail;
+
+	if (conf->data_size && conf->data)
+	{
+		if(conf->data_size > 1024 || conf->data_size < 0)
+			goto bail;
+		data = kmalloc(conf->data_size, GFP_KERNEL);
+		if (data)
+		{
+			if(!copy_from_user(data, conf->data, conf->data_size))
+			{
+				conf->data=data;
+				wandev->setup(wandev,conf);
+			}
+			else 
+				err = -ENOBUFS;
+		}
+		if (data)
+			kfree(data);
+	}
+bail:
+	kfree(conf);
+	return err;
+}
+
+/*
+ *	Shutdown WAN device.
+ *	o delete all not opened logical channels for this device
+ *	o call driver's shutdown() entry point
+ */
+ 
+static int device_shutdown (wan_device_t* wandev)
+{
+	struct device* dev;
+
+	if (wandev->state == WAN_UNCONFIGURED)
+		return 0;
+		
+	for (dev = wandev->dev; dev;)
+	{
+		if (delete_interface(wandev, dev->name, 0))
+			dev = dev->slave;
+	}
+	if (wandev->ndev)
+		return -EBUSY;	/* there are opened interfaces  */
+		
+	if (wandev->shutdown)
+		return wandev->shutdown(wandev);
+	return 0;
+}
+
+/*
+ *	Get WAN device status & statistics.
+ */
+
+static int device_stat (wan_device_t* wandev, wandev_stat_t* u_stat)
+{
+	wandev_stat_t stat;
+
+	memset(&stat, 0, sizeof(stat));
+
+	/* Ask device driver to update device statistics */
+	if ((wandev->state != WAN_UNCONFIGURED) && wandev->update)
+		wandev->update(wandev);
+
+	/* Fill out structure */
+	stat.ndev  = wandev->ndev;
+	stat.state = wandev->state;
+
+	if(copy_to_user(u_stat, &stat, sizeof(stat)))
+		return -EFAULT;
+	return 0;
+}
+
+/*
+ *	Create new WAN interface.
+ *	o verify user address space
+ *	o copy configuration data to kernel address space
+ *	o allocate network interface data space
+ *	o call driver's new_if() entry point
+ *	o make sure there is no interface name conflict
+ *	o register network interface
+ */
+
+static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf)
+{
+	wanif_conf_t conf;
+	struct device* dev;
+	int err;
+
+	if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL))
+		return -ENODEV;
+		
+	if(copy_from_user(&conf, u_conf, sizeof(wanif_conf_t)))
+		return -EFAULT;
+		
+	if (conf.magic != ROUTER_MAGIC)
+		return -EINVAL;
+		
+	dev = kmalloc(sizeof(struct device), GFP_KERNEL);
+	if (dev == NULL)
+		return -ENOBUFS;
+		
+	memset(dev, 0, sizeof(struct device));
+	err = wandev->new_if(wandev, dev, &conf);
+	if (!err)
+	{
+		/* Register network interface. This will invoke init()
+		 * function supplied by the driver.  If device registered
+		 * successfully, add it to the interface list.
+		 */
+		if (dev->name == NULL)
+			err = -EINVAL;
+			
+		else if (dev_get(dev->name))
+			err = -EEXIST;	/* name already exists */
+		else
+		{
+#ifdef WANDEBUG		
+			printk(KERN_INFO "%s: registering interface %s...\n",
+				modname, dev->name);
+#endif				
+			err = register_netdev(dev);
+			if (!err)
+			{
+				cli();	/***** critical section start *****/
+				dev->slave = wandev->dev;
+				wandev->dev = dev;
+				++wandev->ndev;
+				sti();	/****** critical section end ******/
+				return 0;	/* done !!! */
+			}
+		}
+		if (wandev->del_if)
+			wandev->del_if(wandev, dev);
+	}
+	kfree(dev);
+	return err;
+}
+
+/*
+ *	Delete WAN logical channel.
+ *	 o verify user address space
+ *	 o copy configuration data to kernel address space
+ */
+
+static int device_del_if (wan_device_t* wandev, char* u_name)
+{
+	char name[WAN_IFNAME_SZ + 1];
+
+	if (wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV;
+		
+	memset(name, 0, sizeof(name));
+	if(copy_from_user(name, u_name, WAN_IFNAME_SZ))
+		return -EFAULT;
+	return delete_interface(wandev, name, 0);
+}
+
+/*
+ *	Miscellaneous Functions
+ */
+
+/*
+ *	Find WAN device by name.
+ *	Return pointer to the WAN device data space or NULL if device not found.
+ */
+
+static wan_device_t* find_device (char* name)
+{
+	wan_device_t* wandev;
+
+	for (wandev = devlist;wandev && strcmp(wandev->name, name);
+		wandev = wandev->next);
+	return wandev;
+}
+
+/*
+ *	Delete WAN logical channel identified by its name.
+ *	o find logical channel by its name
+ *	o call driver's del_if() entry point
+ *	o unregister network interface
+ *	o unlink channel data space from linked list of channels
+ *	o release channel data space
+ *
+ *	Return:	0		success
+ *		-ENODEV		channel not found.
+ *		-EBUSY		interface is open
+ *
+ *	Note: If (force != 0), then device will be destroyed even if interface
+ *	associated with it is open. It's caller's responsibility to make
+ *	sure that opened interfaces are not removed!
+ */
+
+static int delete_interface (wan_device_t* wandev, char* name, int force)
+{
+	struct device *dev, *prev;
+
+	for (dev = wandev->dev, prev = NULL;
+		dev && strcmp(name, dev->name);
+		prev = dev, dev = dev->slave);
+
+	if (dev == NULL)
+		return -ENODEV;	/* interface not found */
+
+	if (dev->start)
+	{
+		if (force)
+		{
+			printk(KERN_WARNING
+				"%s: deleting opened interface %s!\n",modname, name);
+		}
+		else
+			return -EBUSY;	/* interface in use */
+	}
+	if (wandev->del_if)
+		wandev->del_if(wandev, dev);
+
+	cli();			/***** critical section start *****/
+	if (prev)
+		prev->slave = dev->slave;
+	else
+		wandev->dev = dev->slave;
+	--wandev->ndev;
+	sti();			/****** critical section end ******/
+
+	unregister_netdev(dev);
+	kfree(dev);
+	return 0;
+}
+
+/*
+ *	End
+ */
diff -u --recursive --new-file v2.1.24/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c
--- v2.1.24/linux/net/wanrouter/wanproc.c	Thu Jan  1 02:00:00 1970
+++ linux/net/wanrouter/wanproc.c	Sun Feb  2 16:44:21 1997
@@ -0,0 +1,460 @@
+/*****************************************************************************
+* wanproc.c	WAN Multiprotocol Router Module. proc filesystem interface.
+*
+*		This module is completely hardware-independent and provides
+*		access to the router using Linux /proc filesystem.
+*
+* Author:	Gene Kozin	<genek@compuserve.com>
+*
+* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+*
+*		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.
+* ============================================================================
+* Dec 13, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
+* Jan 30, 1997	Alan Cox	Hacked around for 2.1
+*****************************************************************************/
+
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/kernel.h>
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/mm.h>		/* verify_area(), etc. */
+#include <linux/string.h>	/* inline mem*, str* functions */
+#include <asm/segment.h>	/* kernel <-> user copy */
+#include <asm/byteorder.h>	/* htons(), etc. */
+#include <asm/uaccess.h>	/* copy_to_user */
+#include <linux/wanrouter.h>	/* WAN router API definitions */
+
+
+/****** Defines and Macros **************************************************/
+
+#ifndef	min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef	max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#define	ROUTER_PAGE_SZ	4000	/* buffer size for printing proc info */
+
+/****** Data Types **********************************************************/
+
+typedef struct wan_stat_entry
+{
+	struct wan_stat_entry *	next;
+	char *description;		/* description string */
+	void *data;			/* -> data */
+	unsigned data_type;		/* data type */
+} wan_stat_entry_t;
+
+/****** Function Prototypes *************************************************/
+
+/* Proc filesystem interface */
+static int router_proc_perms (struct inode*, int);
+static long router_proc_read(struct inode* inode, struct file* file, char* buf,
+				unsigned long count);
+
+/* Methods for preparing data for reading proc entries */
+
+static int about_get_info(char* buf, char** start, off_t offs, int len, int dummy);
+static int config_get_info(char* buf, char** start, off_t offs, int len, int dummy);
+static int status_get_info(char* buf, char** start, off_t offs, int len, int dummy);
+static int wandev_get_info(char* buf, char** start, off_t offs, int len, int dummy);
+
+/* Miscellaneous */
+
+/*
+ *	Global Data
+ */
+
+/*
+ *	Names of the proc directory entries 
+ */
+
+static char name_root[]	= ROUTER_NAME;
+static char name_info[]	= "about";
+static char name_conf[]	= "config";
+static char name_stat[]	= "status";
+
+/*
+ *	Structures for interfacing with the /proc filesystem.
+ *	Router creates its own directory /proc/net/router with the folowing
+ *	entries:
+ *	About		general information (version, copyright, etc.)
+ *	Conf		device configuration
+ *	Stat		global device statistics
+ *	<device>	entry for each WAN device
+ */
+
+/*
+ *	Generic /proc/net/router/<file> file and inode operations 
+ */
+
+static struct file_operations router_fops =
+{
+	NULL,			/* lseek   */
+	router_proc_read,	/* read	   */
+	NULL,			/* write   */
+	NULL,			/* readdir */
+	NULL,			/* select  */
+	NULL,			/* ioctl   */
+	NULL,			/* mmap	   */
+	NULL,			/* no special open code	   */
+	NULL,			/* no special release code */
+	NULL			/* can't fsync */
+};
+
+static struct inode_operations router_inode =
+{
+	&router_fops,
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	router_proc_perms
+};
+
+/*
+ *	/proc/net/router/<device> file and inode operations
+ */
+
+static struct file_operations wandev_fops =
+{
+	NULL,			/* lseek   */
+	router_proc_read,	/* read	   */
+	NULL,			/* write   */
+	NULL,			/* readdir */
+	NULL,			/* select  */
+	wanrouter_ioctl,	/* ioctl   */
+	NULL,			/* mmap	   */
+	NULL,			/* no special open code	   */
+	NULL,			/* no special release code */
+	NULL			/* can't fsync */
+};
+
+static struct inode_operations wandev_inode =
+{
+	&wandev_fops,
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	router_proc_perms
+};
+
+/*
+ * Proc filesystem derectory entries.
+ */
+
+/*
+ *	/proc/net/router 
+ */
+ 
+static struct proc_dir_entry proc_router =
+{
+	0,			/* .low_ino */
+	sizeof(name_root) - 1,	/* .namelen */
+	name_root,		/* .name */
+	0555 | S_IFDIR,		/* .mode */
+	2,			/* .nlink */
+	0,			/* .uid */
+	0,			/* .gid */
+	0,			/* .size */
+	&proc_dir_inode_operations, /* .ops */
+	NULL,			/* .get_info */
+	NULL,			/* .fill_node */
+	NULL,			/* .next */
+	NULL,			/* .parent */
+	NULL,			/* .subdir */
+	NULL,			/* .data */
+};
+
+/*
+ *	/proc/net/router/about 
+ */
+ 
+static struct proc_dir_entry proc_router_info =
+{
+	0,			/* .low_ino */
+	sizeof(name_info) - 1,	/* .namelen */
+	name_info,		/* .name */
+	0444 | S_IFREG,		/* .mode */
+	1,			/* .nlink */
+	0,			/* .uid */
+	0,			/* .gid */
+	0,			/* .size */
+	&router_inode,		/* .ops */
+	&about_get_info,	/* .get_info */
+	NULL,			/* .fill_node */
+	NULL,			/* .next */
+	NULL,			/* .parent */
+	NULL,			/* .subdir */
+	NULL,			/* .data */
+};
+
+/*
+ *	/proc/net/router/config 
+ */
+ 
+static struct proc_dir_entry proc_router_conf =
+{
+	0,			/* .low_ino */
+	sizeof(name_conf) - 1,	/* .namelen */
+	name_conf,		/* .name */
+	0444 | S_IFREG,		/* .mode */
+	1,			/* .nlink */
+	0,			/* .uid */
+	0,			/* .gid */
+	0,			/* .size */
+	&router_inode,		/* .ops */
+	&config_get_info,	/* .get_info */
+	NULL,			/* .fill_node */
+	NULL,			/* .next */
+	NULL,			/* .parent */
+	NULL,			/* .subdir */
+	NULL,			/* .data */
+};
+
+/*
+ *	/proc/net/router/status 
+ */
+ 
+static struct proc_dir_entry proc_router_stat =
+{
+	0,			/* .low_ino */
+	sizeof(name_stat) - 1,	/* .namelen */
+	name_stat,		/* .name */
+	0444 | S_IFREG,		/* .mode */
+	1,			/* .nlink */
+	0,			/* .uid */
+	0,			/* .gid */
+	0,			/* .size */
+	&router_inode,		/* .ops */
+	status_get_info,	/* .get_info */
+	NULL,			/* .fill_node */
+	NULL,			/* .next */
+	NULL,			/* .parent */
+	NULL,			/* .subdir */
+	NULL,			/* .data */
+};
+
+/*
+ *	Interface functions
+ */
+
+/*
+ *	Initialize router proc interface.
+ */
+
+int wanrouter_proc_init (void)
+{
+	int err = proc_register_dynamic(&proc_net, &proc_router);
+
+	if (!err)
+	{
+		proc_register_dynamic(&proc_router, &proc_router_info);
+		proc_register_dynamic(&proc_router, &proc_router_conf);
+		proc_register_dynamic(&proc_router, &proc_router_stat);
+	}
+	return err;
+}
+
+/*
+ *	Clean up router proc interface.
+ */
+
+void wanrouter_proc_cleanup (void)
+{
+	proc_unregister(&proc_router, proc_router_info.low_ino);
+	proc_unregister(&proc_router, proc_router_conf.low_ino);
+	proc_unregister(&proc_router, proc_router_stat.low_ino);
+	proc_unregister(&proc_net, proc_router.low_ino);
+}
+
+/*
+ *	Add directory entry for WAN device.
+ */
+
+int wanrouter_proc_add (wan_device_t* wandev)
+{
+	if (wandev->magic != ROUTER_MAGIC)
+		return -EINVAL;
+		
+	memset(&wandev->dent, 0, sizeof(wandev->dent));
+	wandev->dent.namelen	= strlen(wandev->name);
+	wandev->dent.name	= wandev->name;
+	wandev->dent.mode	= 0444 | S_IFREG;
+	wandev->dent.nlink	= 1;
+	wandev->dent.ops	= &wandev_inode;
+	wandev->dent.get_info	= &wandev_get_info;
+	wandev->dent.data	= wandev;
+	return proc_register_dynamic(&proc_router, &wandev->dent);
+}
+
+/*
+ *	Delete directory entry for WAN device.
+ */
+ 
+int wanrouter_proc_delete(wan_device_t* wandev)
+{
+	if (wandev->magic != ROUTER_MAGIC)
+		return -EINVAL;
+	proc_unregister(&proc_router, wandev->dent.low_ino);
+	return 0;
+}
+
+/****** Proc filesystem entry points ****************************************/
+
+/*
+ *	Verify access rights.
+ */
+
+static int router_proc_perms (struct inode* inode, int op)
+{
+	return 0;
+}
+
+/*
+ *	Read router proc directory entry.
+ *	This is universal routine for reading all entries in /proc/net/router
+ *	directory.  Each directory entry contains a pointer to the 'method' for
+ *	preparing data for that entry.
+ *	o verify arguments
+ *	o allocate kernel buffer
+ *	o call get_info() to prepare data
+ *	o copy data to user space
+ *	o release kernel buffer
+ *
+ *	Return:	number of bytes copied to user space (0, if no data)
+ *		<0	error
+ */
+
+static long router_proc_read(struct inode* inode, struct file* file, 
+				char* buf, unsigned long count)
+{
+	struct proc_dir_entry* dent;
+	char* page;
+	int pos, offs, len;
+
+	if (count <= 0)
+		return 0;
+		
+	dent = inode->u.generic_ip;
+	if ((dent == NULL) || (dent->get_info == NULL))
+		return 0;
+		
+	page = kmalloc(ROUTER_PAGE_SZ, GFP_KERNEL);
+	if (page == NULL)
+		return -ENOBUFS;
+		
+	pos = dent->get_info(page, dent->data, 0, 0, 0);
+	offs = file->f_pos;
+	if (offs < pos)
+	{
+		len = min(pos - offs, count);
+		if(copy_to_user(buf, (page + offs), len))
+			return -EFAULT;
+		file->f_pos += len;
+	}
+	else
+		len = 0;
+	kfree(page);
+	return len;
+}
+
+/*
+ *	Prepare data for reading 'About' entry.
+ *	Return length of data.
+ */
+
+static int about_get_info(char* buf, char** start, off_t offs, int len, 
+				int dummy)
+{
+	int cnt = 0;
+
+	cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
+		"version", ROUTER_VERSION, ROUTER_RELEASE);
+	return cnt;
+}
+
+/*
+ *	Prepare data for reading 'Config' entry.
+ *	Return length of data.
+ *	NOT YET IMPLEMENTED
+ */
+
+static int config_get_info(char* buf, char** start, off_t offs, int len, 
+	int dummy)
+{
+	int cnt = 0;
+
+	cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
+		"version", ROUTER_VERSION, ROUTER_RELEASE);
+	return cnt;
+}
+
+/*
+ *	Prepare data for reading 'Status' entry.
+ *	Return length of data.
+ *	NOT YET IMPLEMENTED
+ */
+
+static int status_get_info(char* buf, char** start, off_t offs, int len, 
+			int dummy)
+{
+	int cnt = 0;
+
+	cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
+		"version", ROUTER_VERSION, ROUTER_RELEASE);
+	return cnt;
+}
+
+/*
+ *	Prepare data for reading <device> entry.
+ *	Return length of data.
+ *
+ *	On entry, the 'start' argument will contain a pointer to WAN device
+ *	data space.
+ */
+
+static int wandev_get_info(char* buf, char** start, off_t offs, int len, 
+			int dummy)
+{
+	wan_device_t* wandev = (void*)start;
+	int cnt = 0;
+
+	if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
+		return 0;
+	cnt += sprintf(&buf[cnt], "%12s : %s\n", "name", wandev->name);
+	return cnt;
+}
+
+/*
+ *	End
+ */
+ 
diff -u --recursive --new-file v2.1.24/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.1.24/linux/net/x25/af_x25.c	Sun Feb  2 15:46:23 1997
+++ linux/net/x25/af_x25.c	Sun Feb  2 15:18:53 1997
@@ -421,28 +421,6 @@
 	return -EOPNOTSUPP;
 }
 
-static void def_callback1(struct sock *sk)
-{
-	if (!sk->dead)
-		wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
-	if (!sk->dead) {
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 1);
-	}
-}
-
-static void def_callback3(struct sock *sk)
-{
-	if (!sk->dead) {
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 2);
-	}
-}
-
 static struct sock *x25_alloc_socket(void)
 {
 	struct sock *sk;
@@ -463,16 +441,7 @@
 
 	MOD_INC_USE_COUNT;
 
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->back_log);
-
-	init_timer(&sk->timer);
-
-	sk->state_change = def_callback1;
-	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback3;
-	sk->error_report = def_callback1;
+	sock_init_data(NULL, sk);
 
 	skb_queue_head_init(&x25->fragment_queue);
 	skb_queue_head_init(&x25->interrupt_in_queue);
@@ -494,30 +463,17 @@
 
 	x25 = sk->protinfo.x25;
 
-	sock->ops         = &x25_proto_ops;
-
-	sk->socket        = sock;
-	sk->type          = sock->type;
-	sk->protocol      = protocol;
-	sk->allocation	  = GFP_KERNEL;
-	sk->rcvbuf        = SK_RMEM_MAX;
-	sk->sndbuf        = SK_WMEM_MAX;
-	sk->state         = TCP_CLOSE;
-	sk->priority      = SOPRI_NORMAL;
-	sk->mtu           = X25_DEFAULT_PACKET_SIZE;	/* X25_PS128 */
-	sk->zapped        = 1;
-
-	if (sock != NULL) {
-		sock->sk  = sk;
-		sk->sleep = &sock->wait;
-	}
-
-	x25->t21      = sysctl_x25_call_request_timeout;
-	x25->t22      = sysctl_x25_reset_request_timeout;
-	x25->t23      = sysctl_x25_clear_request_timeout;
-	x25->t2       = sysctl_x25_ack_holdback_timeout;
+	sock_init_data(sock, sk);
 
-	x25->state       = X25_STATE_0;
+	sock->ops    = &x25_proto_ops;
+	sk->protocol = protocol;
+	sk->mtu      = X25_DEFAULT_PACKET_SIZE;	/* X25_PS128 */
+
+	x25->t21   = sysctl_x25_call_request_timeout;
+	x25->t22   = sysctl_x25_reset_request_timeout;
+	x25->t23   = sysctl_x25_clear_request_timeout;
+	x25->t2    = sysctl_x25_ack_holdback_timeout;
+	x25->state = X25_STATE_0;
 
 	x25->facilities.winsize_in  = X25_DEFAULT_WINDOW_SIZE;
 	x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE;
diff -u --recursive --new-file v2.1.24/linux/net/x25/x25_link.c linux/net/x25/x25_link.c
--- v2.1.24/linux/net/x25/x25_link.c	Thu Jan 23 21:06:59 1997
+++ linux/net/x25/x25_link.c	Sun Feb  2 15:18:53 1997
@@ -52,31 +52,14 @@
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	save_flags(flags); cli();
 	del_timer(&neigh->timer);
 	restore_flags(flags);
 
-	neigh->timer.next     = neigh->timer.prev = NULL;	
 	neigh->timer.data     = (unsigned long)neigh;
 	neigh->timer.function = &x25_link_timer;
-
 	neigh->timer.expires  = jiffies + 100;
-	add_timer(&neigh->timer);
-}
 
-static void x25_link_reset_timer(struct x25_neigh *neigh)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	del_timer(&neigh->timer);
-	restore_flags(flags);
-
-	neigh->timer.data     = (unsigned long)neigh;
-	neigh->timer.function = &x25_link_timer;
-	neigh->timer.expires  = jiffies + 100;
 	add_timer(&neigh->timer);
 }
 
@@ -91,7 +74,7 @@
 	struct x25_neigh *neigh = (struct x25_neigh *)param;
 
 	if (neigh->t20timer == 0 || --neigh->t20timer > 0) {
-		x25_link_reset_timer(neigh);
+		x25_link_set_timer(neigh);
 		return;
 	}
 
diff -u --recursive --new-file v2.1.24/linux/net/x25/x25_timer.c linux/net/x25/x25_timer.c
--- v2.1.24/linux/net/x25/x25_timer.c	Thu Jan 23 21:06:59 1997
+++ linux/net/x25/x25_timer.c	Sun Feb  2 15:18:53 1997
@@ -42,36 +42,14 @@
 static void x25_timer(unsigned long);
 
 /*
- *	Linux set/reset timer routines
+ *	Linux set timer
  */
 void x25_set_timer(struct sock *sk)
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
-
+	save_flags(flags); cli();
 	del_timer(&sk->timer);
-
-	restore_flags(flags);
-
-	sk->timer.next     = sk->timer.prev = NULL;	
-	sk->timer.data     = (unsigned long)sk;
-	sk->timer.function = &x25_timer;
-	sk->timer.expires  = jiffies + 100;
-
-	add_timer(&sk->timer);
-}
-
-static void x25_reset_timer(struct sock *sk)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-
-	del_timer(&sk->timer);
-
 	restore_flags(flags);
 
 	sk->timer.data     = (unsigned long)sk;
@@ -125,7 +103,7 @@
 	}
 
 	if (sk->protinfo.x25->timer == 0 || --sk->protinfo.x25->timer > 0) {
-		x25_reset_timer(sk);
+		x25_set_timer(sk);
 		return;
 	}
 
